backend-infra-engineer: Pre-0.2.2 2024 Q2 snapshot
This commit is contained in:
42
src/app/editor/context/entrance_context.h
Normal file
42
src/app/editor/context/entrance_context.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef YAZE_APP_EDITOR_CONTEXT_ENTRANCE_CONTEXT_H_
|
||||
#define YAZE_APP_EDITOR_CONTEXT_ENTRANCE_CONTEXT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
namespace context {
|
||||
|
||||
class EntranceContext {
|
||||
public:
|
||||
absl::Status LoadEntranceTileTypes(Rom& rom) {
|
||||
int offset_low = 0xDB8BF;
|
||||
int offset_high = 0xDB917;
|
||||
|
||||
for (int i = 0; i < 0x2C; i++) {
|
||||
// Load entrance tile types
|
||||
ASSIGN_OR_RETURN(auto value_low, rom.ReadWord(offset_low + i));
|
||||
entrance_tile_types_low_.push_back(value_low);
|
||||
ASSIGN_OR_RETURN(auto value_high, rom.ReadWord(offset_high + i));
|
||||
entrance_tile_types_low_.push_back(value_high);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint16_t> entrance_tile_types_low_;
|
||||
std::vector<uint16_t> entrance_tile_types_high_;
|
||||
};
|
||||
|
||||
} // namespace context
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_CONTEXT_ENTRANCE_CONTEXT_H_
|
||||
@@ -4,23 +4,24 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "app/core/editor.h"
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
namespace context {
|
||||
|
||||
std::unordered_map<uint8_t, gfx::Paletteset> GfxContext::palettesets_;
|
||||
|
||||
}
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#include "app/core/editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
@@ -19,7 +19,11 @@
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
namespace context {
|
||||
|
||||
/**
|
||||
* @brief Shared graphical context across editors.
|
||||
*/
|
||||
class GfxContext {
|
||||
public:
|
||||
absl::Status Update();
|
||||
@@ -29,6 +33,7 @@ class GfxContext {
|
||||
static std::unordered_map<uint8_t, gfx::Paletteset> palettesets_;
|
||||
};
|
||||
|
||||
} // namespace context
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
@@ -30,60 +30,12 @@ using ImGui::TableSetupColumn;
|
||||
|
||||
absl::Status DungeonEditor::Update() {
|
||||
if (!is_loaded_ && rom()->is_loaded()) {
|
||||
for (int i = 0; i < 0x100 + 40; i++) {
|
||||
rooms_.emplace_back(zelda3::dungeon::Room(i));
|
||||
rooms_[i].LoadHeader();
|
||||
rooms_[i].LoadRoomFromROM();
|
||||
if (flags()->kDrawDungeonRoomGraphics) {
|
||||
rooms_[i].LoadRoomGraphics();
|
||||
}
|
||||
|
||||
room_size_pointers_.push_back(rooms_[i].room_size_ptr());
|
||||
if (rooms_[i].room_size_ptr() != 0x0A8000) {
|
||||
room_size_addresses_[i] = rooms_[i].room_size_ptr();
|
||||
}
|
||||
|
||||
auto dungeon_palette_ptr = rom()->paletteset_ids[rooms_[i].palette][0];
|
||||
ASSIGN_OR_RETURN(auto palette_id,
|
||||
rom()->ReadWord(0xDEC4B + dungeon_palette_ptr));
|
||||
int p_id = palette_id / 180;
|
||||
auto color = rom()->palette_group("dungeon_main")[p_id][3];
|
||||
|
||||
room_palette_[rooms_[i].palette] = color.rgb();
|
||||
}
|
||||
|
||||
LoadDungeonRoomSize();
|
||||
LoadRoomEntrances();
|
||||
|
||||
// Load the palette group and palette for the dungeon
|
||||
full_palette_ =
|
||||
rom()->palette_group("dungeon_main")[current_palette_group_id_];
|
||||
ASSIGN_OR_RETURN(current_palette_group_,
|
||||
gfx::CreatePaletteGroupFromLargePalette(full_palette_));
|
||||
|
||||
graphics_bin_ = *rom()->mutable_bitmap_manager();
|
||||
// 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].get());
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(Initialize());
|
||||
is_loaded_ = true;
|
||||
}
|
||||
|
||||
if (refresh_graphics_) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int block = rooms_[current_room_id_].blocks()[i];
|
||||
graphics_bin_[block].get()->ApplyPaletteWithTransparent(
|
||||
current_palette_group_[current_palette_id_], 0);
|
||||
rom()->UpdateBitmap(graphics_bin_[block].get(), true);
|
||||
}
|
||||
for (int i = 9; i < 16; i++) {
|
||||
int block = rooms_[current_room_id_].blocks()[i];
|
||||
graphics_bin_[block].get()->ApplyPaletteWithTransparent(
|
||||
rom()->palette_group("sprites_aux1")[current_palette_id_], 0);
|
||||
rom()->UpdateBitmap(graphics_bin_[block].get(), true);
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(RefreshGraphics());
|
||||
refresh_graphics_ = false;
|
||||
}
|
||||
|
||||
@@ -106,6 +58,62 @@ absl::Status DungeonEditor::Update() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status DungeonEditor::Initialize() {
|
||||
auto dungeon_man_pal_group = rom()->palette_group().dungeon_main;
|
||||
for (int i = 0; i < 0x100 + 40; i++) {
|
||||
rooms_.emplace_back(zelda3::dungeon::Room(i));
|
||||
rooms_[i].LoadHeader();
|
||||
rooms_[i].LoadRoomFromROM();
|
||||
if (flags()->kDrawDungeonRoomGraphics) {
|
||||
rooms_[i].LoadRoomGraphics();
|
||||
}
|
||||
|
||||
room_size_pointers_.push_back(rooms_[i].room_size_ptr());
|
||||
if (rooms_[i].room_size_ptr() != 0x0A8000) {
|
||||
room_size_addresses_[i] = rooms_[i].room_size_ptr();
|
||||
}
|
||||
|
||||
auto dungeon_palette_ptr = rom()->paletteset_ids[rooms_[i].palette][0];
|
||||
ASSIGN_OR_RETURN(auto palette_id,
|
||||
rom()->ReadWord(0xDEC4B + dungeon_palette_ptr));
|
||||
int p_id = palette_id / 180;
|
||||
auto color = dungeon_man_pal_group[p_id][3];
|
||||
room_palette_[rooms_[i].palette] = color.rgb();
|
||||
}
|
||||
|
||||
LoadDungeonRoomSize();
|
||||
LoadRoomEntrances();
|
||||
|
||||
// Load the palette group and palette for the dungeon
|
||||
full_palette_ = dungeon_man_pal_group[current_palette_group_id_];
|
||||
ASSIGN_OR_RETURN(current_palette_group_,
|
||||
gfx::CreatePaletteGroupFromLargePalette(full_palette_));
|
||||
|
||||
graphics_bin_ = *rom()->mutable_bitmap_manager();
|
||||
// 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].get());
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status DungeonEditor::RefreshGraphics() {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int block = rooms_[current_room_id_].blocks()[i];
|
||||
RETURN_IF_ERROR(graphics_bin_[block].get()->ApplyPaletteWithTransparent(
|
||||
current_palette_group_[current_palette_id_], 0));
|
||||
rom()->UpdateBitmap(graphics_bin_[block].get(), true);
|
||||
}
|
||||
auto sprites_aux1_pal_group = rom()->palette_group().sprites_aux1;
|
||||
for (int i = 9; i < 16; i++) {
|
||||
int block = rooms_[current_room_id_].blocks()[i];
|
||||
graphics_bin_[block].get()->ApplyPaletteWithTransparent(
|
||||
sprites_aux1_pal_group[current_palette_id_], 0);
|
||||
rom()->UpdateBitmap(graphics_bin_[block].get(), true);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void DungeonEditor::LoadDungeonRoomSize() {
|
||||
std::map<int, std::vector<int>> rooms_by_bank;
|
||||
for (const auto& room : room_size_addresses_) {
|
||||
@@ -148,13 +156,13 @@ void DungeonEditor::LoadDungeonRoomSize() {
|
||||
}
|
||||
}
|
||||
|
||||
void DungeonEditor::UpdateDungeonRoomView() {
|
||||
absl::Status DungeonEditor::UpdateDungeonRoomView() {
|
||||
DrawToolset();
|
||||
|
||||
if (palette_showing_) {
|
||||
ImGui::Begin("Palette Editor", &palette_showing_, 0);
|
||||
current_palette_ =
|
||||
rom()->palette_group("dungeon_main")[current_palette_group_id_];
|
||||
auto dungeon_main_pal_group = rom()->palette_group().dungeon_main;
|
||||
current_palette_ = dungeon_main_pal_group[current_palette_group_id_];
|
||||
gui::SelectablePalettePipeline(current_palette_id_, refresh_graphics_,
|
||||
current_palette_);
|
||||
ImGui::End();
|
||||
@@ -186,6 +194,7 @@ void DungeonEditor::UpdateDungeonRoomView() {
|
||||
DrawTileSelector();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawToolset() {
|
||||
@@ -483,7 +492,7 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
||||
|
||||
void DungeonEditor::DrawRoomGraphics() {
|
||||
const auto height = 0x40;
|
||||
room_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 0x10 * 0x40 + 1));
|
||||
room_gfx_canvas_.DrawBackground(ImVec2(0x100 + 1, 0x10 * 0x40 + 1));
|
||||
room_gfx_canvas_.DrawContextMenu();
|
||||
room_gfx_canvas_.DrawTileSelector(32);
|
||||
if (is_loaded_) {
|
||||
@@ -593,26 +602,19 @@ void DungeonEditor::LoadRoomEntrances() {
|
||||
// ============================================================================
|
||||
|
||||
void DungeonEditor::CalculateUsageStats() {
|
||||
// Create a hash map of the usage for elements of each Dungeon Room such as
|
||||
// the blockset, spriteset, palette, etc. This is so we can keep track of
|
||||
// which graphics sets and palette sets are in use and which are not.
|
||||
|
||||
for (const auto& room : rooms_) {
|
||||
// Blockset
|
||||
if (blockset_usage_.find(room.blockset) == blockset_usage_.end()) {
|
||||
blockset_usage_[room.blockset] = 1;
|
||||
} else {
|
||||
blockset_usage_[room.blockset] += 1;
|
||||
}
|
||||
|
||||
// Spriteset
|
||||
if (spriteset_usage_.find(room.spriteset) == spriteset_usage_.end()) {
|
||||
spriteset_usage_[room.spriteset] = 1;
|
||||
} else {
|
||||
spriteset_usage_[room.spriteset] += 1;
|
||||
}
|
||||
|
||||
// Palette
|
||||
if (palette_usage_.find(room.palette) == palette_usage_.end()) {
|
||||
palette_usage_[room.palette] = 1;
|
||||
} else {
|
||||
@@ -756,22 +758,14 @@ void DungeonEditor::DrawUsageStats() {
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawUsageGrid() {
|
||||
// Create a grid of 295 small squares which is 16 squares wide
|
||||
// Each square represents a room in the game
|
||||
// When you hover a square it should show a hover tooltip with the properties
|
||||
// of the room such as the blockset, spriteset, palette, etc. Calculate the
|
||||
// number of rows
|
||||
int totalSquares = 296;
|
||||
int squaresWide = 16;
|
||||
int squaresTall = (totalSquares + squaresWide - 1) /
|
||||
squaresWide; // Ceiling of totalSquares/squaresWide
|
||||
|
||||
// Loop through each row
|
||||
for (int row = 0; row < squaresTall; ++row) {
|
||||
// Start a new line for each row
|
||||
ImGui::NewLine();
|
||||
|
||||
// Loop through each column in the row
|
||||
for (int col = 0; col < squaresWide; ++col) {
|
||||
// Check if we have reached 295 squares
|
||||
if (row * squaresWide + col >= totalSquares) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/core/labeling.h"
|
||||
#include "app/editor/modules/gfx_group_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
@@ -32,8 +32,18 @@ constexpr ImGuiTableFlags kDungeonTableFlags =
|
||||
ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter |
|
||||
ImGuiTableFlags_BordersV;
|
||||
|
||||
/**
|
||||
* @brief DungeonEditor class for editing dungeons.
|
||||
*
|
||||
* This class is currently a work in progress and is used for editing dungeons.
|
||||
* It provides various functions for updating, cutting, copying, pasting,
|
||||
* undoing, and redoing. It also includes methods for drawing the toolset, room
|
||||
* selector, entrance selector, dungeon tab view, dungeon canvas, room graphics,
|
||||
* tile selector, and object renderer. Additionally, it handles loading room
|
||||
* entrances, calculating usage statistics, and rendering set usage.
|
||||
*/
|
||||
class DungeonEditor : public Editor,
|
||||
public SharedROM,
|
||||
public SharedRom,
|
||||
public core::ExperimentFlags {
|
||||
public:
|
||||
absl::Status Update() override;
|
||||
@@ -46,9 +56,12 @@ class DungeonEditor : public Editor,
|
||||
void add_room(int i) { active_rooms_.push_back(i); }
|
||||
|
||||
private:
|
||||
absl::Status Initialize();
|
||||
absl::Status RefreshGraphics();
|
||||
|
||||
void LoadDungeonRoomSize();
|
||||
|
||||
void UpdateDungeonRoomView();
|
||||
absl::Status UpdateDungeonRoomView();
|
||||
|
||||
void DrawToolset();
|
||||
void DrawRoomSelector();
|
||||
|
||||
@@ -51,12 +51,13 @@ absl::Status GraphicsEditor::Update() {
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::UpdateGfxEdit() {
|
||||
TAB_ITEM("Graphics Editor")
|
||||
TAB_ITEM("Sheet Editor")
|
||||
|
||||
if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags,
|
||||
ImVec2(0, 0))) {
|
||||
for (const auto& name : kGfxEditColumnNames)
|
||||
ImGui::TableSetupColumn(name.data());
|
||||
for (const auto& name :
|
||||
{"Tilesheets", "Current Graphics", "Palette Controls"})
|
||||
ImGui::TableSetupColumn(name);
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
@@ -321,10 +322,10 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::UpdatePaletteColumn() {
|
||||
auto palette_group = rom()->palette_group(
|
||||
auto palette_group = *rom()->palette_group().get_group(
|
||||
kPaletteGroupAddressesKeys[edit_palette_group_name_index_]);
|
||||
|
||||
auto palette = palette_group[edit_palette_index_];
|
||||
auto palette = palette_group.palette(edit_palette_index_);
|
||||
|
||||
if (rom()->is_loaded()) {
|
||||
gui::TextWithSeparators("ROM Palette");
|
||||
@@ -339,11 +340,13 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
|
||||
gui::SelectablePalettePipeline(edit_palette_sub_index_, refresh_graphics_,
|
||||
palette);
|
||||
|
||||
if (refresh_graphics_) {
|
||||
rom()->bitmap_manager()[current_sheet_]->ApplyPaletteWithTransparent(
|
||||
palette, edit_palette_sub_index_);
|
||||
if (refresh_graphics_ && !open_sheets_.empty()) {
|
||||
RETURN_IF_ERROR(
|
||||
rom()->bitmap_manager()[current_sheet_]->ApplyPaletteWithTransparent(
|
||||
palette, edit_palette_sub_index_));
|
||||
rom()->UpdateBitmap(
|
||||
rom()->mutable_bitmap_manager()->mutable_bitmap(current_sheet_).get());
|
||||
rom()->mutable_bitmap_manager()->mutable_bitmap(current_sheet_).get(),
|
||||
true);
|
||||
refresh_graphics_ = false;
|
||||
}
|
||||
|
||||
@@ -353,22 +356,44 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
|
||||
absl::Status GraphicsEditor::UpdateLinkGfxView() {
|
||||
TAB_ITEM("Player Animations")
|
||||
|
||||
const auto link_gfx_offset = 0x80000;
|
||||
const auto link_gfx_length = 0x7000;
|
||||
if (ImGui::BeginTable("##PlayerAnimationTable", 3, kGfxEditTableFlags,
|
||||
ImVec2(0, 0))) {
|
||||
for (const auto& name : {"Canvas", "Animation Steps", "Properties"})
|
||||
ImGui::TableSetupColumn(name);
|
||||
|
||||
// TODO: Finish Rom::LoadLinkGraphics and implement this
|
||||
if (ImGui::Button("Load Link Graphics (Experimental)")) {
|
||||
if (rom()->is_loaded()) {
|
||||
// Load Links graphics from the ROM
|
||||
rom()->LoadLinkGraphics();
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
// Split it into the pose data frames
|
||||
// Create an animation step display for the poses
|
||||
// Allow the user to modify the frames used in an anim step
|
||||
// LinkOAM_AnimationSteps:
|
||||
// #_0D85FB
|
||||
NEXT_COLUMN();
|
||||
link_canvas_.DrawBackground();
|
||||
link_canvas_.DrawGrid(16.0f);
|
||||
int i = 0;
|
||||
for (auto [key, link_sheet] : rom()->link_graphics()) {
|
||||
int x_offset = 0;
|
||||
int y_offset = core::kTilesheetHeight * i * 4;
|
||||
link_canvas_.DrawBitmap(link_sheet, x_offset, y_offset, 4);
|
||||
i++;
|
||||
}
|
||||
link_canvas_.DrawOverlay();
|
||||
link_canvas_.DrawGrid();
|
||||
|
||||
NEXT_COLUMN();
|
||||
ImGui::Text("Placeholder");
|
||||
|
||||
NEXT_COLUMN();
|
||||
if (ImGui::Button("Load Link Graphics (Experimental)")) {
|
||||
if (rom()->is_loaded()) {
|
||||
// Load Links graphics from the ROM
|
||||
RETURN_IF_ERROR(rom()->LoadLinkGraphics());
|
||||
|
||||
// Split it into the pose data frames
|
||||
// Create an animation step display for the poses
|
||||
// Allow the user to modify the frames used in an anim step
|
||||
// LinkOAM_AnimationSteps:
|
||||
// #_0D85FB
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
||||
END_TAB_ITEM()
|
||||
return absl::OkStatus();
|
||||
@@ -477,8 +502,8 @@ absl::Status GraphicsEditor::DrawCgxImport() {
|
||||
[this]() { ImGui::SetClipboardText(cgx_file_path_); });
|
||||
|
||||
gui::ButtonPipe("Load CGX Data", [this]() {
|
||||
status_ = gfx::LoadCgx(current_bpp_, cgx_file_path_, cgx_data_,
|
||||
decoded_cgx_, extra_cgx_data_);
|
||||
status_ = gfx::scad_format::LoadCgx(current_bpp_, cgx_file_path_, cgx_data_,
|
||||
decoded_cgx_, extra_cgx_data_);
|
||||
|
||||
cgx_bitmap_.InitializeFromData(0x80, 0x200, 8, decoded_cgx_);
|
||||
if (col_file_) {
|
||||
@@ -508,11 +533,12 @@ absl::Status GraphicsEditor::DrawScrImport() {
|
||||
InputInt("SCR Mod", &scr_mod_value_);
|
||||
|
||||
gui::ButtonPipe("Load Scr Data", [this]() {
|
||||
status_ = gfx::LoadScr(scr_file_path_, scr_mod_value_, scr_data_);
|
||||
status_ =
|
||||
gfx::scad_format::LoadScr(scr_file_path_, scr_mod_value_, scr_data_);
|
||||
|
||||
decoded_scr_data_.resize(0x100 * 0x100);
|
||||
status_ = gfx::DrawScrWithCgx(current_bpp_, scr_data_, decoded_scr_data_,
|
||||
decoded_cgx_);
|
||||
status_ = gfx::scad_format::DrawScrWithCgx(current_bpp_, scr_data_,
|
||||
decoded_scr_data_, decoded_cgx_);
|
||||
|
||||
scr_bitmap_.InitializeFromData(0x100, 0x100, 8, decoded_scr_data_);
|
||||
if (scr_loaded_) {
|
||||
@@ -551,7 +577,7 @@ absl::Status GraphicsEditor::DrawPaletteControls() {
|
||||
col_file_palette_ = gfx::SnesPalette(col_data_);
|
||||
|
||||
// gigaleak dev format based code
|
||||
decoded_col_ = gfx::DecodeColFile(col_file_path_);
|
||||
decoded_col_ = gfx::scad_format::DecodeColFile(col_file_path_);
|
||||
col_file_ = true;
|
||||
is_open_ = true;
|
||||
});
|
||||
@@ -711,7 +737,7 @@ absl::Status GraphicsEditor::DecompressImportData(int size) {
|
||||
converted_sheet);
|
||||
|
||||
if (rom()->is_loaded()) {
|
||||
auto palette_group = rom()->palette_group("ow_main");
|
||||
auto palette_group = rom()->palette_group().overworld_animated;
|
||||
z3_rom_palette_ = palette_group[current_palette_];
|
||||
if (col_file_) {
|
||||
bin_bitmap_.ApplyPalette(col_file_palette_);
|
||||
@@ -743,9 +769,10 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
|
||||
col_file_palette_group_[current_palette_index_]);
|
||||
} else {
|
||||
// ROM palette
|
||||
auto palette_group =
|
||||
rom()->palette_group(kPaletteGroupAddressesKeys[current_palette_]);
|
||||
z3_rom_palette_ = palette_group[current_palette_index_];
|
||||
|
||||
auto palette_group = rom()->palette_group().get_group(
|
||||
kPaletteGroupAddressesKeys[current_palette_]);
|
||||
z3_rom_palette_ = *palette_group->mutable_palette(current_palette_index_);
|
||||
graphics_bin_[i].ApplyPalette(z3_rom_palette_);
|
||||
}
|
||||
|
||||
@@ -768,9 +795,9 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
|
||||
col_file_palette_group_[current_palette_index_]);
|
||||
} else {
|
||||
// ROM palette
|
||||
auto palette_group =
|
||||
rom()->palette_group(kPaletteGroupAddressesKeys[current_palette_]);
|
||||
z3_rom_palette_ = palette_group[current_palette_index_];
|
||||
auto palette_group = rom()->palette_group().get_group(
|
||||
kPaletteGroupAddressesKeys[current_palette_]);
|
||||
z3_rom_palette_ = *palette_group->mutable_palette(current_palette_index_);
|
||||
graphics_bin_[i].ApplyPalette(z3_rom_palette_);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -50,9 +50,6 @@ constexpr const char* kPaletteGroupAddressesKeys[] = {
|
||||
"grass", "3d_object", "ow_mini_map",
|
||||
};
|
||||
|
||||
static constexpr std::string_view kGfxEditColumnNames[] = {
|
||||
"Tilesheets", "Current Graphics", "Palette Controls"};
|
||||
|
||||
static constexpr absl::string_view kGfxToolsetColumnNames[] = {
|
||||
"#memoryEditor",
|
||||
"##separator_gfx1",
|
||||
@@ -62,7 +59,21 @@ constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable |
|
||||
ImGuiTableFlags_Resizable |
|
||||
ImGuiTableFlags_SizingStretchSame;
|
||||
|
||||
class GraphicsEditor : public SharedROM {
|
||||
/**
|
||||
* @class GraphicsEditor
|
||||
* @brief Allows the user to edit graphics sheets from the game or view
|
||||
* prototype graphics.
|
||||
*
|
||||
* The GraphicsEditor class is responsible for providing functionality to edit
|
||||
* graphics sheets from the game or view prototype graphics of Link to the Past
|
||||
* from the CGX, SCR, and OBJ formats. It provides various methods to update
|
||||
* different components of the graphics editor, such as the graphics edit tab,
|
||||
* link graphics view, and prototype graphics viewer. It also includes import
|
||||
* functions for different file formats, as well as other utility functions for
|
||||
* drawing toolsets, palette controls, clipboard imports, experimental features,
|
||||
* and memory editor.
|
||||
*/
|
||||
class GraphicsEditor : public SharedRom {
|
||||
public:
|
||||
absl::Status Update();
|
||||
|
||||
@@ -154,9 +165,9 @@ class GraphicsEditor : public SharedROM {
|
||||
|
||||
GfxEditMode gfx_edit_mode_ = GfxEditMode::kSelect;
|
||||
|
||||
ROM temp_rom_;
|
||||
ROM tilemap_rom_;
|
||||
zelda3::Overworld overworld_;
|
||||
Rom temp_rom_;
|
||||
Rom tilemap_rom_;
|
||||
zelda3::overworld::Overworld overworld_;
|
||||
MemoryEditor cgx_memory_editor_;
|
||||
MemoryEditor col_memory_editor_;
|
||||
PaletteEditor palette_editor_;
|
||||
@@ -184,6 +195,9 @@ class GraphicsEditor : public SharedROM {
|
||||
gui::Canvas super_donkey_canvas_;
|
||||
gui::Canvas current_sheet_canvas_{ImVec2(0x80, 0x20),
|
||||
gui::CanvasGridSize::k8x8};
|
||||
gui::Canvas link_canvas_{
|
||||
ImVec2(core::kTilesheetWidth * 4, core::kTilesheetHeight * 0x10 * 4),
|
||||
gui::CanvasGridSize::k16x16};
|
||||
absl::Status status_;
|
||||
};
|
||||
|
||||
|
||||
@@ -151,6 +151,8 @@ absl::Status MasterEditor::Update() {
|
||||
DrawInfoPopup();
|
||||
|
||||
if (rom()->is_loaded() && !rom_assets_loaded_) {
|
||||
// Load all of the graphics data from the game.
|
||||
RETURN_IF_ERROR(rom()->LoadAllGraphicsData())
|
||||
// Initialize overworld graphics, maps, and palettes
|
||||
RETURN_IF_ERROR(overworld_editor_.LoadGraphics());
|
||||
rom_assets_loaded_ = true;
|
||||
@@ -464,7 +466,43 @@ void MasterEditor::DrawViewMenu() {
|
||||
|
||||
if (show_memory_editor) {
|
||||
static MemoryEditor mem_edit;
|
||||
mem_edit.DrawWindow("Memory Editor", (void*)&(*rom()), rom()->size());
|
||||
static MemoryEditor comp_edit;
|
||||
static bool show_compare_rom = false;
|
||||
static Rom comparison_rom;
|
||||
ImGui::Begin("Hex Editor", &show_memory_editor);
|
||||
if (ImGui::Button("Compare Rom")) {
|
||||
auto file_name = FileDialogWrapper::ShowOpenFileDialog();
|
||||
PRINT_IF_ERROR(comparison_rom.LoadFromFile(file_name));
|
||||
show_compare_rom = true;
|
||||
}
|
||||
|
||||
static uint64_t convert_address = 0;
|
||||
gui::InputHex("SNES to PC", (int*)&convert_address, 6, 200.f);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%x", core::SnesToPc(convert_address));
|
||||
|
||||
// mem_edit.DrawWindow("Memory Editor", (void*)&(*rom()), rom()->size());
|
||||
BEGIN_TABLE("Memory Comparison", 2, ImGuiTableFlags_Resizable);
|
||||
SETUP_COLUMN("Source")
|
||||
SETUP_COLUMN("Dest")
|
||||
|
||||
NEXT_COLUMN()
|
||||
ImGui::Text("%s", rom()->filename().data());
|
||||
mem_edit.DrawContents((void*)&(*rom()), rom()->size());
|
||||
|
||||
NEXT_COLUMN()
|
||||
if (show_compare_rom) {
|
||||
comp_edit.SetComparisonData((void*)&(*rom()));
|
||||
ImGui::BeginGroup();
|
||||
ImGui::BeginChild("Comparison ROM");
|
||||
ImGui::Text("%s", comparison_rom.filename().data());
|
||||
comp_edit.DrawContents((void*)&(comparison_rom), comparison_rom.size());
|
||||
ImGui::EndChild();
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
END_TABLE()
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (show_imgui_demo) {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/editor/context/gfx_context.h"
|
||||
#include "app/editor/dungeon_editor.h"
|
||||
#include "app/editor/graphics_editor.h"
|
||||
@@ -28,14 +27,33 @@
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class MasterEditor : public SharedROM,
|
||||
public GfxContext,
|
||||
/**
|
||||
* @class MasterEditor
|
||||
* @brief The MasterEditor class represents the main editor for a Rom in the
|
||||
* Yaze application.
|
||||
*
|
||||
* This class inherits from SharedRom, GfxContext, and ExperimentFlags, and
|
||||
* provides functionality for setting up the screen, updating the editor, and
|
||||
* shutting down the editor. It also includes methods for drawing various menus
|
||||
* and popups, saving the Rom, and managing editor-specific flags.
|
||||
*
|
||||
* The MasterEditor class contains instances of various editor classes such as
|
||||
* AssemblyEditor, DungeonEditor, GraphicsEditor, MusicEditor, OverworldEditor,
|
||||
* PaletteEditor, ScreenEditor, and SpriteEditor. The current_editor_ member
|
||||
* variable points to the currently active editor in the tab view.
|
||||
*
|
||||
* @note This class assumes the presence of an SDL_Renderer object for rendering
|
||||
* graphics.
|
||||
*/
|
||||
class MasterEditor : public SharedRom,
|
||||
public context::GfxContext,
|
||||
public core::ExperimentFlags {
|
||||
public:
|
||||
MasterEditor() { current_editor_ = &overworld_editor_; }
|
||||
|
||||
@@ -12,6 +12,10 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
/**
|
||||
* @class AssemblyEditor
|
||||
* @brief Text editor for modifying assembly code.
|
||||
*/
|
||||
class AssemblyEditor {
|
||||
public:
|
||||
AssemblyEditor();
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/gui/widgets.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -220,29 +220,20 @@ void GfxGroupEditor::DrawPaletteViewer() {
|
||||
gui::InputHexByte("Dungeon Spr Pal 2", &dungeon_spr_pal_2_val);
|
||||
gui::InputHexByte("Dungeon Spr Pal 3", &dungeon_spr_pal_3_val);
|
||||
|
||||
auto &palette =
|
||||
*rom()
|
||||
->mutable_palette_group(
|
||||
"dungeon_main")[rom()->paletteset_ids[selected_paletteset][0]]
|
||||
.mutable_palette(0);
|
||||
auto &palette = *rom()->mutable_palette_group()->dungeon_main.mutable_palette(
|
||||
rom()->paletteset_ids[selected_paletteset][0]);
|
||||
DrawPaletteFromPaletteGroup(palette);
|
||||
auto &spr_aux_pal1 =
|
||||
*rom()
|
||||
->mutable_palette_group(
|
||||
"sprites_aux1")[rom()->paletteset_ids[selected_paletteset][1]]
|
||||
.mutable_palette(0);
|
||||
*rom()->mutable_palette_group()->sprites_aux1.mutable_palette(
|
||||
rom()->paletteset_ids[selected_paletteset][1]);
|
||||
DrawPaletteFromPaletteGroup(spr_aux_pal1);
|
||||
auto &spr_aux_pal2 =
|
||||
*rom()
|
||||
->mutable_palette_group(
|
||||
"sprites_aux2")[rom()->paletteset_ids[selected_paletteset][2]]
|
||||
.mutable_palette(0);
|
||||
*rom()->mutable_palette_group()->sprites_aux2.mutable_palette(
|
||||
rom()->paletteset_ids[selected_paletteset][2]);
|
||||
DrawPaletteFromPaletteGroup(spr_aux_pal2);
|
||||
auto &spr_aux_pal3 =
|
||||
*rom()
|
||||
->mutable_palette_group(
|
||||
"sprites_aux3")[rom()->paletteset_ids[selected_paletteset][3]]
|
||||
.mutable_palette(0);
|
||||
*rom()->mutable_palette_group()->sprites_aux3.mutable_palette(
|
||||
rom()->paletteset_ids[selected_paletteset][3]);
|
||||
DrawPaletteFromPaletteGroup(spr_aux_pal3);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
@@ -17,13 +17,17 @@
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/gui/widgets.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class GfxGroupEditor : public SharedROM {
|
||||
/**
|
||||
* @class GfxGroupEditor
|
||||
* @brief Manage graphics group configurations in a Rom.
|
||||
*/
|
||||
class GfxGroupEditor : public SharedRom {
|
||||
public:
|
||||
absl::Status Update();
|
||||
|
||||
@@ -61,7 +65,7 @@ class GfxGroupEditor : public SharedROM {
|
||||
std::vector<gfx::Bitmap> tile16_individual_;
|
||||
|
||||
gui::BitmapViewer gfx_group_viewer_;
|
||||
zelda3::Overworld overworld_;
|
||||
zelda3::overworld::Overworld overworld_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
|
||||
@@ -54,7 +54,12 @@ static const char* kGameSongs[] = {"Title",
|
||||
static constexpr absl::string_view kSongNotes[] = {
|
||||
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C",
|
||||
"C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C"};
|
||||
class MusicEditor : public SharedROM {
|
||||
|
||||
/**
|
||||
* @class MusicEditor
|
||||
* @brief A class for editing music data in a Rom.
|
||||
*/
|
||||
class MusicEditor : public SharedRom {
|
||||
public:
|
||||
void Update();
|
||||
|
||||
@@ -65,7 +70,7 @@ class MusicEditor : public SharedROM {
|
||||
void DrawSongToolset();
|
||||
void DrawToolset();
|
||||
|
||||
zelda3::Tracker music_tracker_;
|
||||
zelda3::music::Tracker music_tracker_;
|
||||
|
||||
// Mix_Music* current_song_ = NULL;
|
||||
|
||||
|
||||
@@ -75,30 +75,32 @@ absl::Status PaletteEditor::Update() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void PaletteEditor::EditColorInPalette(gfx::SnesPalette& palette, int index) {
|
||||
absl::Status PaletteEditor::EditColorInPalette(gfx::SnesPalette& palette,
|
||||
int index) {
|
||||
if (index >= palette.size()) {
|
||||
// Handle error: the index is out of bounds
|
||||
return;
|
||||
return absl::InvalidArgumentError("Index out of bounds");
|
||||
}
|
||||
|
||||
// Get the current color
|
||||
auto currentColor = palette.GetColor(index).rgb();
|
||||
ASSIGN_OR_RETURN(auto color, palette.GetColor(index));
|
||||
auto currentColor = color.rgb();
|
||||
if (ImGui::ColorPicker4("Color Picker", (float*)&palette[index])) {
|
||||
// The color was modified, update it in the palette
|
||||
palette(index, currentColor);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void PaletteEditor::ResetColorToOriginal(
|
||||
absl::Status PaletteEditor::ResetColorToOriginal(
|
||||
gfx::SnesPalette& palette, int index,
|
||||
const gfx::SnesPalette& originalPalette) {
|
||||
if (index >= palette.size() || index >= originalPalette.size()) {
|
||||
// Handle error: the index is out of bounds
|
||||
return;
|
||||
return absl::InvalidArgumentError("Index out of bounds");
|
||||
}
|
||||
|
||||
auto originalColor = originalPalette.GetColor(index).rgb();
|
||||
ASSIGN_OR_RETURN(auto color, originalPalette.GetColor(index));
|
||||
auto originalColor = color.rgb();
|
||||
palette(index, originalColor);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status PaletteEditor::DrawPaletteGroup(int category) {
|
||||
@@ -106,17 +108,17 @@ absl::Status PaletteEditor::DrawPaletteGroup(int category) {
|
||||
return absl::NotFoundError("ROM not open, no palettes to display");
|
||||
}
|
||||
|
||||
const auto size =
|
||||
rom()->palette_group(kPaletteGroupNames[category].data()).size();
|
||||
auto palettes =
|
||||
rom()->mutable_palette_group(kPaletteGroupNames[category].data());
|
||||
std::string group_name = kPaletteGroupNames[category].data();
|
||||
auto palette_group = *rom()->palette_group().get_group(group_name);
|
||||
const auto size = palette_group.size();
|
||||
|
||||
static bool edit_color = false;
|
||||
for (int j = 0; j < size; j++) {
|
||||
// ImGui::Text("%d", j);
|
||||
rom()->resource_label()->SelectableLabelWithNameEdit(
|
||||
false, "Palette Group Name", std::to_string(j),
|
||||
std::string(kPaletteGroupNames[category]));
|
||||
auto palette = palettes->mutable_palette(j);
|
||||
auto palette = palette_group.mutable_palette(j);
|
||||
auto pal_size = palette->size();
|
||||
|
||||
for (int n = 0; n < pal_size; n++) {
|
||||
@@ -129,7 +131,7 @@ absl::Status PaletteEditor::DrawPaletteGroup(int category) {
|
||||
// Small icon of the color in the palette
|
||||
if (gui::SnesColorButton(popup_id, *palette->mutable_color(n),
|
||||
palette_button_flags)) {
|
||||
current_color_ = palette->GetColor(n);
|
||||
ASSIGN_OR_RETURN(current_color_, palette->GetColor(n));
|
||||
// EditColorInPalette(*palette, n);
|
||||
}
|
||||
|
||||
@@ -152,8 +154,7 @@ absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i,
|
||||
int j, int n) {
|
||||
auto col = gfx::ToFloatArray(palette[n]);
|
||||
if (gui::SnesColorEdit4("Edit Color", palette[n], color_popup_flags)) {
|
||||
RETURN_IF_ERROR(rom()->UpdatePaletteColor(kPaletteGroupNames[i].data(), j,
|
||||
n, palette[n]))
|
||||
// TODO: Implement new update color function
|
||||
}
|
||||
|
||||
if (ImGui::Button("Copy as..", ImVec2(-1, 0))) ImGui::OpenPopup("Copy");
|
||||
|
||||
@@ -25,6 +25,7 @@ static constexpr absl::string_view kPaletteGroupNames[] = {
|
||||
"ow_aux", "global_sprites", "dungeon_main", "ow_mini_map",
|
||||
"ow_mini_map", "3d_object", "3d_object"};
|
||||
|
||||
namespace palette_internal {
|
||||
struct PaletteChange {
|
||||
std::string group_name;
|
||||
size_t palette_index;
|
||||
@@ -74,15 +75,20 @@ class PaletteEditorHistory {
|
||||
std::deque<PaletteChange> recentChanges;
|
||||
static const size_t maxHistorySize = 50; // or any other number you deem fit
|
||||
};
|
||||
} // namespace palette_internal
|
||||
|
||||
class PaletteEditor : public SharedROM {
|
||||
/**
|
||||
* @class PaletteEditor
|
||||
* @brief Allows the user to view and edit in game palettes.
|
||||
*/
|
||||
class PaletteEditor : public SharedRom {
|
||||
public:
|
||||
absl::Status Update();
|
||||
absl::Status DrawPaletteGroups();
|
||||
|
||||
void EditColorInPalette(gfx::SnesPalette& palette, int index);
|
||||
void ResetColorToOriginal(gfx::SnesPalette& palette, int index,
|
||||
const gfx::SnesPalette& originalPalette);
|
||||
absl::Status EditColorInPalette(gfx::SnesPalette& palette, int index);
|
||||
absl::Status ResetColorToOriginal(gfx::SnesPalette& palette, int index,
|
||||
const gfx::SnesPalette& originalPalette);
|
||||
void DisplayPalette(gfx::SnesPalette& palette, bool loaded);
|
||||
void DrawPortablePalette(gfx::SnesPalette& palette);
|
||||
absl::Status DrawPaletteGroup(int category);
|
||||
@@ -90,18 +96,20 @@ class PaletteEditor : public SharedROM {
|
||||
private:
|
||||
absl::Status HandleColorPopup(gfx::SnesPalette& palette, int i, int j, int n);
|
||||
|
||||
void InitializeSavedPalette(const gfx::SnesPalette& palette) {
|
||||
absl::Status InitializeSavedPalette(const gfx::SnesPalette& palette) {
|
||||
for (int n = 0; n < palette.size(); n++) {
|
||||
saved_palette_[n].x = palette.GetColor(n).rgb().x / 255;
|
||||
saved_palette_[n].y = palette.GetColor(n).rgb().y / 255;
|
||||
saved_palette_[n].z = palette.GetColor(n).rgb().z / 255;
|
||||
ASSIGN_OR_RETURN(auto color, palette.GetColor(n));
|
||||
saved_palette_[n].x = color.rgb().x / 255;
|
||||
saved_palette_[n].y = color.rgb().y / 255;
|
||||
saved_palette_[n].z = color.rgb().z / 255;
|
||||
saved_palette_[n].w = 255; // Alpha
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status status_;
|
||||
|
||||
PaletteEditorHistory history_;
|
||||
palette_internal::PaletteEditorHistory history_;
|
||||
|
||||
ImVec4 saved_palette_[256] = {};
|
||||
gfx::SnesColor current_color_;
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gfx/tilesheet.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
@@ -18,7 +19,7 @@
|
||||
#include "app/gui/style.h"
|
||||
#include "app/gui/widgets.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -50,6 +51,7 @@ absl::Status Tile16Editor::Update() {
|
||||
*tile8_source_canvas_.custom_labels_enabled() = true;
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(DrawMenu());
|
||||
if (BeginTabBar("Tile16 Editor Tabs")) {
|
||||
RETURN_IF_ERROR(DrawTile16Editor());
|
||||
RETURN_IF_ERROR(UpdateTile16Transfer());
|
||||
@@ -59,11 +61,25 @@ absl::Status Tile16Editor::Update() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::DrawMenu() {
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
if (ImGui::BeginMenu("View")) {
|
||||
ImGui::Checkbox("Show Collision Types",
|
||||
tile8_source_canvas_.custom_labels_enabled());
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::DrawTile16Editor() {
|
||||
if (BeginTabItem("Tile16 Editing")) {
|
||||
if (BeginTable("#Tile16EditorTable", 2, TABLE_BORDERS_RESIZABLE,
|
||||
ImVec2(0, 0))) {
|
||||
TableSetupColumn("Tiles", ImGuiTableColumnFlags_WidthFixed,
|
||||
TableSetupColumn("Blockset", ImGuiTableColumnFlags_WidthFixed,
|
||||
ImGui::GetContentRegionAvail().x);
|
||||
TableSetupColumn("Properties", ImGuiTableColumnFlags_WidthStretch,
|
||||
ImGui::GetContentRegionAvail().x);
|
||||
@@ -74,31 +90,7 @@ absl::Status Tile16Editor::DrawTile16Editor() {
|
||||
|
||||
TableNextColumn();
|
||||
RETURN_IF_ERROR(UpdateTile16Edit());
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::UpdateTile16Transfer() {
|
||||
if (BeginTabItem("Tile16 Transfer")) {
|
||||
if (BeginTable("#Tile16TransferTable", 2, TABLE_BORDERS_RESIZABLE,
|
||||
ImVec2(0, 0))) {
|
||||
TableSetupColumn("Current ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
|
||||
ImGui::GetContentRegionAvail().x / 2);
|
||||
TableSetupColumn("Transfer ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
|
||||
ImGui::GetContentRegionAvail().x / 2);
|
||||
TableHeadersRow();
|
||||
TableNextRow();
|
||||
|
||||
TableNextColumn();
|
||||
RETURN_IF_ERROR(UpdateBlockset());
|
||||
|
||||
TableNextColumn();
|
||||
RETURN_IF_ERROR(UpdateTransferTileCanvas());
|
||||
RETURN_IF_ERROR(DrawTileEditControls());
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
@@ -113,12 +105,14 @@ absl::Status Tile16Editor::UpdateBlockset() {
|
||||
gui::BeginChildWithScrollbar("##Tile16EditorBlocksetScrollRegion");
|
||||
blockset_canvas_.DrawBackground();
|
||||
gui::EndPadding();
|
||||
blockset_canvas_.DrawContextMenu();
|
||||
blockset_canvas_.DrawTileSelector(32);
|
||||
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 0, map_blockset_loaded_);
|
||||
blockset_canvas_.DrawGrid();
|
||||
blockset_canvas_.DrawOverlay();
|
||||
ImGui::EndChild();
|
||||
{
|
||||
blockset_canvas_.DrawContextMenu();
|
||||
blockset_canvas_.DrawTileSelector(32);
|
||||
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 0, map_blockset_loaded_);
|
||||
blockset_canvas_.DrawGrid();
|
||||
blockset_canvas_.DrawOverlay();
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
if (!blockset_canvas_.points().empty()) {
|
||||
uint16_t x = blockset_canvas_.points().front().x / 32;
|
||||
@@ -130,8 +124,9 @@ absl::Status Tile16Editor::UpdateBlockset() {
|
||||
if (notify_tile16.modified()) {
|
||||
current_tile16_ = notify_tile16.get();
|
||||
current_tile16_bmp_ = tile16_individual_[notify_tile16];
|
||||
current_tile16_bmp_.ApplyPalette(
|
||||
rom()->palette_group("ow_main")[current_palette_]);
|
||||
auto ow_main_pal_group = rom()->palette_group().overworld_main;
|
||||
RETURN_IF_ERROR(current_tile16_bmp_.ApplyPalette(
|
||||
ow_main_pal_group[current_palette_]));
|
||||
rom()->RenderBitmap(¤t_tile16_bmp_);
|
||||
}
|
||||
}
|
||||
@@ -173,40 +168,41 @@ absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) {
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::UpdateTile16Edit() {
|
||||
auto ow_main_pal_group = rom()->palette_group().overworld_main;
|
||||
|
||||
if (ImGui::BeginChild("Tile8 Selector",
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0x175),
|
||||
true)) {
|
||||
tile8_source_canvas_.DrawBackground(
|
||||
ImVec2(core::kTilesheetWidth * 4, core::kTilesheetHeight * 0x10 * 4));
|
||||
tile8_source_canvas_.DrawContextMenu();
|
||||
tile8_source_canvas_.DrawBackground();
|
||||
tile8_source_canvas_.DrawContextMenu(¤t_gfx_bmp_);
|
||||
if (tile8_source_canvas_.DrawTileSelector(32)) {
|
||||
current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
|
||||
rom()->palette_group("ow_main")[0], current_palette_);
|
||||
RETURN_IF_ERROR(
|
||||
current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
|
||||
ow_main_pal_group[0], current_palette_));
|
||||
rom()->UpdateBitmap(¤t_gfx_individual_[current_tile8_]);
|
||||
}
|
||||
tile8_source_canvas_.DrawBitmap(current_gfx_bmp_, 0, 0, 4.0f);
|
||||
tile8_source_canvas_.DrawGrid(32.0f);
|
||||
tile8_source_canvas_.DrawGrid();
|
||||
tile8_source_canvas_.DrawOverlay();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
// The user selected a tile8
|
||||
if (!tile8_source_canvas_.points().empty()) {
|
||||
uint16_t x = tile8_source_canvas_.points().front().x / 16;
|
||||
uint16_t y = tile8_source_canvas_.points().front().y / 16;
|
||||
|
||||
current_tile8_ = x + (y * 8);
|
||||
current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
|
||||
rom()->palette_group("ow_main")[0], current_palette_);
|
||||
RETURN_IF_ERROR(
|
||||
current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
|
||||
ow_main_pal_group[0], current_palette_));
|
||||
rom()->UpdateBitmap(¤t_gfx_individual_[current_tile8_]);
|
||||
}
|
||||
|
||||
ImGui::Text("Tile16 ID: %d", current_tile16_);
|
||||
ImGui::Text("Tile8 ID: %d", current_tile8_);
|
||||
|
||||
if (ImGui::BeginChild("Tile16 Editor Options",
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0x50), true)) {
|
||||
tile16_edit_canvas_.DrawBackground(ImVec2(0x40, 0x40));
|
||||
tile16_edit_canvas_.DrawContextMenu();
|
||||
tile16_edit_canvas_.DrawBackground();
|
||||
tile16_edit_canvas_.DrawContextMenu(¤t_tile16_bmp_);
|
||||
tile16_edit_canvas_.DrawBitmap(current_tile16_bmp_, 0, 0, 4.0f);
|
||||
if (!tile8_source_canvas_.points().empty()) {
|
||||
if (tile16_edit_canvas_.DrawTilePainter(
|
||||
@@ -216,17 +212,17 @@ absl::Status Tile16Editor::UpdateTile16Edit() {
|
||||
rom()->UpdateBitmap(¤t_tile16_bmp_);
|
||||
}
|
||||
}
|
||||
tile16_edit_canvas_.DrawGrid(64.0f);
|
||||
tile16_edit_canvas_.DrawGrid();
|
||||
tile16_edit_canvas_.DrawOverlay();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
DrawTileEditControls();
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void Tile16Editor::DrawTileEditControls() {
|
||||
absl::Status Tile16Editor::DrawTileEditControls() {
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Tile16 ID: %d", current_tile16_);
|
||||
ImGui::Text("Tile8 ID: %d", current_tile8_);
|
||||
ImGui::Text("Options:");
|
||||
gui::InputHexByte("Palette", ¬ify_palette.mutable_get());
|
||||
notify_palette.apply_changes();
|
||||
@@ -242,8 +238,10 @@ void Tile16Editor::DrawTileEditControls() {
|
||||
}
|
||||
|
||||
if (value > 0x00) {
|
||||
current_gfx_bmp_.ApplyPaletteWithTransparent(palette, value);
|
||||
current_tile16_bmp_.ApplyPaletteWithTransparent(palette, value);
|
||||
RETURN_IF_ERROR(
|
||||
current_gfx_bmp_.ApplyPaletteWithTransparent(palette, value));
|
||||
RETURN_IF_ERROR(
|
||||
current_tile16_bmp_.ApplyPaletteWithTransparent(palette, value));
|
||||
rom()->UpdateBitmap(¤t_gfx_bmp_);
|
||||
rom()->UpdateBitmap(¤t_tile16_bmp_);
|
||||
}
|
||||
@@ -252,6 +250,82 @@ void Tile16Editor::DrawTileEditControls() {
|
||||
ImGui::Checkbox("X Flip", &x_flip);
|
||||
ImGui::Checkbox("Y Flip", &y_flip);
|
||||
ImGui::Checkbox("Priority Tile", &priority_tile);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::LoadTile8() {
|
||||
auto ow_main_pal_group = rom()->palette_group().overworld_main;
|
||||
|
||||
current_gfx_individual_.reserve(1024);
|
||||
|
||||
for (int index = 0; index < 1024; index++) {
|
||||
std::vector<uint8_t> tile_data(0x40, 0x00);
|
||||
|
||||
// Copy the pixel data for the current tile into the vector
|
||||
for (int ty = 0; ty < 8; ty++) {
|
||||
for (int tx = 0; tx < 8; tx++) {
|
||||
// Current Gfx Data is 16 sheets of 8x8 tiles ordered 16 wide by 4 tall
|
||||
|
||||
// Calculate the position in the tile data vector
|
||||
int position = tx + (ty * 0x08);
|
||||
|
||||
// Calculate the position in the current gfx data
|
||||
int num_columns = current_gfx_bmp_.width() / 8;
|
||||
int num_rows = current_gfx_bmp_.height() / 8;
|
||||
int x = (index % num_columns) * 8 + tx;
|
||||
int y = (index / num_columns) * 8 + ty;
|
||||
int gfx_position = x + (y * 0x100);
|
||||
|
||||
// Get the pixel value from the current gfx data
|
||||
uint8_t value = current_gfx_bmp_.data()[gfx_position];
|
||||
|
||||
if (value & 0x80) {
|
||||
value -= 0x88;
|
||||
}
|
||||
|
||||
tile_data[position] = value;
|
||||
}
|
||||
}
|
||||
|
||||
current_gfx_individual_.emplace_back();
|
||||
current_gfx_individual_[index].Create(0x08, 0x08, 0x08, tile_data);
|
||||
RETURN_IF_ERROR(current_gfx_individual_[index].ApplyPaletteWithTransparent(
|
||||
ow_main_pal_group[0], current_palette_));
|
||||
rom()->RenderBitmap(¤t_gfx_individual_[index]);
|
||||
}
|
||||
|
||||
map_blockset_loaded_ = true;
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Tile16 Transfer
|
||||
|
||||
absl::Status Tile16Editor::UpdateTile16Transfer() {
|
||||
if (BeginTabItem("Tile16 Transfer")) {
|
||||
if (BeginTable("#Tile16TransferTable", 2, TABLE_BORDERS_RESIZABLE,
|
||||
ImVec2(0, 0))) {
|
||||
TableSetupColumn("Current ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
|
||||
ImGui::GetContentRegionAvail().x / 2);
|
||||
TableSetupColumn("Transfer ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
|
||||
ImGui::GetContentRegionAvail().x / 2);
|
||||
TableHeadersRow();
|
||||
TableNextRow();
|
||||
|
||||
TableNextColumn();
|
||||
RETURN_IF_ERROR(UpdateBlockset());
|
||||
|
||||
TableNextColumn();
|
||||
RETURN_IF_ERROR(UpdateTransferTileCanvas());
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::UpdateTransferTileCanvas() {
|
||||
@@ -279,9 +353,9 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() {
|
||||
palette_ = transfer_overworld_.AreaPalette();
|
||||
|
||||
// Create the tile16 blockset image
|
||||
gui::BuildAndRenderBitmapPipeline(0x80, 0x2000, 0x80,
|
||||
transfer_overworld_.Tile16Blockset(),
|
||||
*rom(), transfer_blockset_bmp_, palette_);
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(0x80, 0x2000, 0x80,
|
||||
transfer_overworld_.Tile16Blockset(),
|
||||
transfer_blockset_bmp_, palette_));
|
||||
transfer_blockset_loaded_ = true;
|
||||
}
|
||||
|
||||
@@ -293,62 +367,6 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::InitBlockset(
|
||||
const gfx::Bitmap& tile16_blockset_bmp, gfx::Bitmap current_gfx_bmp,
|
||||
const std::vector<gfx::Bitmap>& tile16_individual,
|
||||
uint8_t all_tiles_types[0x200]) {
|
||||
all_tiles_types_ = all_tiles_types;
|
||||
tile16_blockset_bmp_ = tile16_blockset_bmp;
|
||||
tile16_individual_ = tile16_individual;
|
||||
current_gfx_bmp_ = current_gfx_bmp;
|
||||
tile8_gfx_data_ = current_gfx_bmp_.vector();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::LoadTile8() {
|
||||
current_gfx_individual_.reserve(1024);
|
||||
|
||||
for (int index = 0; index < 1024; index++) {
|
||||
std::vector<uint8_t> tile_data(0x40, 0x00);
|
||||
|
||||
// Copy the pixel data for the current tile into the vector
|
||||
for (int ty = 0; ty < 8; ty++) {
|
||||
for (int tx = 0; tx < 8; tx++) {
|
||||
// Current Gfx Data is 16 sheets of 8x8 tiles ordered 16 wide by 4 tall
|
||||
|
||||
// Calculate the position in the tile data vector
|
||||
int position = tx + (ty * 0x08);
|
||||
|
||||
// Calculate the position in the current gfx data
|
||||
int num_columns = current_gfx_bmp_.width() / 8;
|
||||
int num_rows = current_gfx_bmp_.height() / 8;
|
||||
int x = (index % num_columns) * 8 + tx;
|
||||
int y = (index / num_columns) * 8 + ty;
|
||||
int gfx_position = x + (y * 0x100);
|
||||
|
||||
// Get the pixel value from the current gfx data
|
||||
uint8_t value = tile8_gfx_data_[gfx_position];
|
||||
|
||||
if (value & 0x80) {
|
||||
value -= 0x88;
|
||||
}
|
||||
|
||||
tile_data[position] = value;
|
||||
}
|
||||
}
|
||||
|
||||
current_gfx_individual_.emplace_back();
|
||||
current_gfx_individual_[index].Create(0x08, 0x08, 0x08, tile_data);
|
||||
current_gfx_individual_[index].ApplyPaletteWithTransparent(
|
||||
rom()->palette_group("ow_main")[0], current_palette_);
|
||||
rom()->RenderBitmap(¤t_gfx_individual_[index]);
|
||||
}
|
||||
|
||||
map_blockset_loaded_ = true;
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -7,25 +7,31 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/editor/context/gfx_context.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gfx/tilesheet.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class Tile16Editor : public GfxContext, public SharedROM {
|
||||
/**
|
||||
* @brief Popup window to edit Tile16 data
|
||||
*/
|
||||
class Tile16Editor : public context::GfxContext, public SharedRom {
|
||||
public:
|
||||
absl::Status Update();
|
||||
absl::Status DrawMenu();
|
||||
|
||||
absl::Status DrawTile16Editor();
|
||||
absl::Status UpdateTile16Transfer();
|
||||
absl::Status UpdateBlockset();
|
||||
@@ -34,23 +40,31 @@ class Tile16Editor : public GfxContext, public SharedROM {
|
||||
|
||||
absl::Status UpdateTile16Edit();
|
||||
|
||||
void DrawTileEditControls();
|
||||
absl::Status DrawTileEditControls();
|
||||
|
||||
absl::Status UpdateTransferTileCanvas();
|
||||
|
||||
absl::Status InitBlockset(const gfx::Bitmap& tile16_blockset_bmp,
|
||||
gfx::Bitmap current_gfx_bmp,
|
||||
const std::vector<gfx::Bitmap>& tile16_individual,
|
||||
uint8_t all_tiles_types[0x200]);
|
||||
void InitBlockset(const gfx::Bitmap& tile16_blockset_bmp,
|
||||
gfx::Bitmap current_gfx_bmp,
|
||||
const std::vector<gfx::Bitmap>& tile16_individual,
|
||||
uint8_t all_tiles_types[0x200]) {
|
||||
all_tiles_types_ = all_tiles_types;
|
||||
tile16_blockset_bmp_ = tile16_blockset_bmp;
|
||||
tile16_individual_ = tile16_individual;
|
||||
current_gfx_bmp_ = current_gfx_bmp;
|
||||
tile8_gfx_data_ = current_gfx_bmp_.vector();
|
||||
}
|
||||
|
||||
absl::Status LoadTile8();
|
||||
|
||||
auto set_tile16(int id) {
|
||||
absl::Status set_tile16(int id) {
|
||||
current_tile16_ = id;
|
||||
current_tile16_bmp_ = tile16_individual_[id];
|
||||
current_tile16_bmp_.ApplyPalette(
|
||||
rom()->palette_group("ow_main")[current_palette_]);
|
||||
auto ow_main_pal_group = rom()->palette_group().overworld_main;
|
||||
RETURN_IF_ERROR(
|
||||
current_tile16_bmp_.ApplyPalette(ow_main_pal_group[current_palette_]));
|
||||
rom()->RenderBitmap(¤t_tile16_bmp_);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -78,7 +92,7 @@ class Tile16Editor : public GfxContext, public SharedROM {
|
||||
bool priority_tile;
|
||||
int tile_size;
|
||||
|
||||
uint8_t *all_tiles_types_;
|
||||
uint8_t* all_tiles_types_;
|
||||
|
||||
// Tile16 blockset for selecting the tile to edit
|
||||
gui::Canvas blockset_canvas_{ImVec2(0x100, 0x4000),
|
||||
@@ -86,13 +100,17 @@ class Tile16Editor : public GfxContext, public SharedROM {
|
||||
gfx::Bitmap tile16_blockset_bmp_;
|
||||
|
||||
// Canvas for editing the selected tile
|
||||
gui::Canvas tile16_edit_canvas_;
|
||||
gui::Canvas tile16_edit_canvas_{ImVec2(0x40, 0x40),
|
||||
gui::CanvasGridSize::k64x64};
|
||||
gfx::Bitmap current_tile16_bmp_;
|
||||
gfx::Bitmap current_tile8_bmp_;
|
||||
|
||||
// Tile8 canvas to get the tile to drawing in the tile16_edit_canvas_
|
||||
gui::Canvas tile8_source_canvas_;
|
||||
gui::Canvas tile8_source_canvas_{
|
||||
ImVec2(core::kTilesheetWidth * 4, core::kTilesheetHeight * 0x10 * 4),
|
||||
gui::CanvasGridSize::k32x32};
|
||||
gfx::Bitmap current_gfx_bmp_;
|
||||
std::vector<gfx::Tilesheet> current_tilesheets_;
|
||||
|
||||
gui::Canvas transfer_canvas_;
|
||||
gfx::Bitmap transfer_blockset_bmp_;
|
||||
@@ -110,14 +128,12 @@ class Tile16Editor : public GfxContext, public SharedROM {
|
||||
PaletteEditor palette_editor_;
|
||||
|
||||
gfx::SnesPalette palette_;
|
||||
zelda3::Overworld transfer_overworld_;
|
||||
zelda3::overworld::Overworld transfer_overworld_;
|
||||
|
||||
gfx::BitmapTable graphics_bin_;
|
||||
|
||||
ROM transfer_rom_;
|
||||
Rom transfer_rom_;
|
||||
absl::Status transfer_status_;
|
||||
|
||||
core::TaskManager<std::function<void(int)>> task_manager_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "app/gui/style.h"
|
||||
#include "app/gui/widgets.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -44,52 +44,17 @@ using ImGui::Text;
|
||||
|
||||
absl::Status OverworldEditor::Update() {
|
||||
if (rom()->is_loaded() && !all_gfx_loaded_) {
|
||||
RETURN_IF_ERROR(tile16_editor_.InitBlockset(
|
||||
tile16_blockset_bmp_, current_gfx_bmp_, tile16_individual_,
|
||||
*overworld_.mutable_all_tiles_types()));
|
||||
tile16_editor_.InitBlockset(tile16_blockset_bmp_, current_gfx_bmp_,
|
||||
tile16_individual_,
|
||||
*overworld_.mutable_all_tiles_types());
|
||||
gfx_group_editor_.InitBlockset(tile16_blockset_bmp_);
|
||||
RETURN_IF_ERROR(LoadEntranceTileTypes(*rom()));
|
||||
all_gfx_loaded_ = true;
|
||||
} else if (!rom()->is_loaded() && all_gfx_loaded_) {
|
||||
// TODO: Destroy the overworld graphics canvas.
|
||||
Shutdown();
|
||||
overworld_.Destroy();
|
||||
all_gfx_loaded_ = false;
|
||||
map_blockset_loaded_ = false;
|
||||
}
|
||||
|
||||
// TODO: Setup pan tool with middle mouse button
|
||||
// if (ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) {
|
||||
// previous_mode = current_mode;
|
||||
// current_mode = EditingMode::PAN;
|
||||
// ow_map_canvas_.set_draggable(true);
|
||||
// middle_mouse_dragging_ = true;
|
||||
// }
|
||||
// if (ImGui::IsMouseReleased(ImGuiMouseButton_Middle) &&
|
||||
// current_mode == EditingMode::PAN && middle_mouse_dragging_) {
|
||||
// current_mode = previous_mode;
|
||||
// ow_map_canvas_.set_draggable(false);
|
||||
// middle_mouse_dragging_ = false;
|
||||
// }
|
||||
|
||||
if (overworld_canvas_fullscreen_) {
|
||||
static bool use_work_area = true;
|
||||
static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoSavedSettings;
|
||||
const ImGuiViewport *viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
|
||||
ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize
|
||||
: viewport->Size);
|
||||
|
||||
if (ImGui::Begin("Example: Fullscreen window",
|
||||
&overworld_canvas_fullscreen_, flags)) {
|
||||
// Draws the toolset for editing the Overworld.
|
||||
RETURN_IF_ERROR(DrawToolset())
|
||||
DrawOverworldCanvas();
|
||||
}
|
||||
ImGui::End();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
RETURN_IF_ERROR(UpdateFullscreenCanvas());
|
||||
|
||||
TAB_BAR("##OWEditorTabBar")
|
||||
TAB_ITEM("Map Editor")
|
||||
@@ -117,12 +82,35 @@ absl::Status OverworldEditor::UpdateOverworldEdit() {
|
||||
TableNextColumn();
|
||||
DrawOverworldCanvas();
|
||||
TableNextColumn();
|
||||
DrawTileSelector();
|
||||
RETURN_IF_ERROR(DrawTileSelector());
|
||||
ImGui::EndTable();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::UpdateFullscreenCanvas() {
|
||||
if (overworld_canvas_fullscreen_) {
|
||||
static bool use_work_area = true;
|
||||
static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoSavedSettings;
|
||||
const ImGuiViewport *viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
|
||||
ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize
|
||||
: viewport->Size);
|
||||
|
||||
if (ImGui::Begin("Example: Fullscreen window",
|
||||
&overworld_canvas_fullscreen_, flags)) {
|
||||
// Draws the toolset for editing the Overworld.
|
||||
RETURN_IF_ERROR(DrawToolset())
|
||||
DrawOverworldCanvas();
|
||||
}
|
||||
ImGui::End();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::DrawToolset() {
|
||||
static bool show_gfx_group = false;
|
||||
static bool show_properties = false;
|
||||
@@ -258,7 +246,8 @@ absl::Status OverworldEditor::DrawToolset() {
|
||||
|
||||
if (show_tile16_editor_) {
|
||||
// Create a table in ImGui for the Tile16 Editor
|
||||
ImGui::Begin("Tile16 Editor", &show_tile16_editor_);
|
||||
ImGui::Begin("Tile16 Editor", &show_tile16_editor_,
|
||||
ImGuiWindowFlags_MenuBar);
|
||||
RETURN_IF_ERROR(tile16_editor_.Update())
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -358,21 +347,24 @@ void OverworldEditor::RefreshOverworldMap() {
|
||||
}
|
||||
|
||||
// TODO: Palette throws out of bounds error unexpectedly.
|
||||
void OverworldEditor::RefreshMapPalette() {
|
||||
absl::Status OverworldEditor::RefreshMapPalette() {
|
||||
const auto current_map_palette =
|
||||
overworld_.overworld_map(current_map_)->current_palette();
|
||||
|
||||
if (overworld_.overworld_map(current_map_)->is_large_map()) {
|
||||
// We need to update the map and its siblings if it's a large map
|
||||
for (int i = 1; i < 4; i++) {
|
||||
int sibling_index = overworld_.overworld_map(current_map_)->parent() + i;
|
||||
if (i >= 2) sibling_index += 6;
|
||||
overworld_.mutable_overworld_map(sibling_index)->LoadPalette();
|
||||
maps_bmp_[sibling_index].ApplyPalette(
|
||||
*overworld_.mutable_overworld_map(sibling_index)
|
||||
->mutable_current_palette());
|
||||
RETURN_IF_ERROR(
|
||||
overworld_.mutable_overworld_map(sibling_index)->LoadPalette());
|
||||
RETURN_IF_ERROR(
|
||||
maps_bmp_[sibling_index].ApplyPalette(current_map_palette));
|
||||
}
|
||||
}
|
||||
maps_bmp_[current_map_].ApplyPalette(
|
||||
*overworld_.mutable_overworld_map(current_map_)
|
||||
->mutable_current_palette());
|
||||
|
||||
RETURN_IF_ERROR(maps_bmp_[current_map_].ApplyPalette(current_map_palette));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void OverworldEditor::RefreshMapProperties() {
|
||||
@@ -396,17 +388,13 @@ void OverworldEditor::RefreshMapProperties() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add @JaredBrian per map mosaic feature
|
||||
void OverworldEditor::DrawOverworldMapSettings() {
|
||||
if (BeginTable(kOWMapTable.data(), 8, kOWMapFlags, ImVec2(0, 0), -1)) {
|
||||
for (const auto &name :
|
||||
{"##mapIdCol", "##1stCol", "##gfxCol", "##palCol", "##sprgfxCol",
|
||||
"##sprpalCol", "##msgidCol", "##2ndCol"})
|
||||
if (BeginTable(kOWMapTable.data(), 7, kOWMapFlags, ImVec2(0, 0), -1)) {
|
||||
for (const auto &name : {"##1stCol", "##gfxCol", "##palCol", "##sprgfxCol",
|
||||
"##sprpalCol", "##msgidCol", "##2ndCol"})
|
||||
ImGui::TableSetupColumn(name);
|
||||
|
||||
TableNextColumn();
|
||||
ImGui::Text("Parent/Map ID:%#x, %#x",
|
||||
overworld_.overworld_map(current_map_)->parent(), current_map_);
|
||||
|
||||
TableNextColumn();
|
||||
ImGui::SetNextItemWidth(120.f);
|
||||
ImGui::Combo("##world", ¤t_world_, kWorldList.data(), 3);
|
||||
@@ -429,7 +417,8 @@ void OverworldEditor::DrawOverworldMapSettings() {
|
||||
->mutable_area_palette(),
|
||||
kInputFieldSize)) {
|
||||
RefreshMapProperties();
|
||||
RefreshMapPalette();
|
||||
status_ = RefreshMapPalette();
|
||||
RefreshOverworldMap();
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
@@ -643,7 +632,7 @@ void OverworldEditor::CheckForSelectRectangle() {
|
||||
ow_map_canvas_.DrawBitmapGroup(tile16_ids, tile16_individual_, 0x10);
|
||||
}
|
||||
|
||||
void OverworldEditor::CheckForCurrentMap() {
|
||||
absl::Status OverworldEditor::CheckForCurrentMap() {
|
||||
// 4096x4096, 512x512 maps and some are larges maps 1024x1024
|
||||
auto mouse_position = ImGui::GetIO().MousePos;
|
||||
constexpr int small_map_size = 512;
|
||||
@@ -686,28 +675,48 @@ void OverworldEditor::CheckForCurrentMap() {
|
||||
if (maps_bmp_[current_map_].modified() ||
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
|
||||
RefreshOverworldMap();
|
||||
RefreshTile16Blockset();
|
||||
RETURN_IF_ERROR(RefreshTile16Blockset());
|
||||
rom()->UpdateBitmap(&maps_bmp_[current_map_]);
|
||||
maps_bmp_[current_map_].set_modified(false);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Overworld Editor canvas
|
||||
// Allows the user to make changes to the overworld map.
|
||||
void OverworldEditor::CheckForMousePan() {
|
||||
if (ImGui::IsMouseDragging(ImGuiMouseButton_Middle)) {
|
||||
previous_mode = current_mode;
|
||||
current_mode = EditingMode::PAN;
|
||||
ow_map_canvas_.set_draggable(true);
|
||||
middle_mouse_dragging_ = true;
|
||||
}
|
||||
if (ImGui::IsMouseReleased(ImGuiMouseButton_Middle) &&
|
||||
current_mode == EditingMode::PAN && middle_mouse_dragging_) {
|
||||
current_mode = previous_mode;
|
||||
ow_map_canvas_.set_draggable(false);
|
||||
middle_mouse_dragging_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add @JaredBrian ZSCustomOverworld features to OverworldEditor
|
||||
void OverworldEditor::DrawOverworldCanvas() {
|
||||
if (all_gfx_loaded_) {
|
||||
DrawOverworldMapSettings();
|
||||
Separator();
|
||||
}
|
||||
|
||||
gui::BeginNoPadding();
|
||||
gui::BeginChildBothScrollbars(7);
|
||||
ow_map_canvas_.DrawBackground();
|
||||
gui::EndNoPadding();
|
||||
|
||||
CheckForMousePan();
|
||||
if (current_mode == EditingMode::PAN) {
|
||||
ow_map_canvas_.DrawContextMenu();
|
||||
} else {
|
||||
ow_map_canvas_.set_draggable(false);
|
||||
}
|
||||
|
||||
if (overworld_.is_loaded()) {
|
||||
DrawOverworldMaps();
|
||||
DrawOverworldExits(ow_map_canvas_.zero_point(), ow_map_canvas_.scrolling());
|
||||
@@ -716,40 +725,47 @@ void OverworldEditor::DrawOverworldCanvas() {
|
||||
DrawOverworldItems();
|
||||
DrawOverworldSprites();
|
||||
CheckForOverworldEdits();
|
||||
if (ImGui::IsItemHovered()) CheckForCurrentMap();
|
||||
if (ImGui::IsItemHovered()) status_ = CheckForCurrentMap();
|
||||
}
|
||||
|
||||
ow_map_canvas_.DrawGrid();
|
||||
ow_map_canvas_.DrawOverlay();
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void OverworldEditor::DrawTile16Selector() {
|
||||
absl::Status OverworldEditor::DrawTile16Selector() {
|
||||
gui::BeginPadding(3);
|
||||
ImGui::BeginGroup();
|
||||
gui::BeginChildWithScrollbar("##Tile16SelectorScrollRegion");
|
||||
blockset_canvas_.DrawBackground();
|
||||
gui::EndNoPadding();
|
||||
blockset_canvas_.DrawContextMenu();
|
||||
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, /*border_offset=*/2,
|
||||
map_blockset_loaded_);
|
||||
if (blockset_canvas_.DrawTileSelector(32.0f)) {
|
||||
// Open the tile16 editor to the tile
|
||||
auto tile_pos = blockset_canvas_.points().front();
|
||||
int grid_x = static_cast<int>(tile_pos.x / 32);
|
||||
int grid_y = static_cast<int>(tile_pos.y / 32);
|
||||
int id = grid_x + grid_y * 8;
|
||||
tile16_editor_.set_tile16(id);
|
||||
show_tile16_editor_ = true;
|
||||
{
|
||||
blockset_canvas_.DrawContextMenu();
|
||||
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, /*border_offset=*/2,
|
||||
map_blockset_loaded_);
|
||||
|
||||
if (blockset_canvas_.DrawTileSelector(32.0f)) {
|
||||
// Open the tile16 editor to the tile
|
||||
auto tile_pos = blockset_canvas_.points().front();
|
||||
int grid_x = static_cast<int>(tile_pos.x / 32);
|
||||
int grid_y = static_cast<int>(tile_pos.y / 32);
|
||||
int id = grid_x + grid_y * 8;
|
||||
RETURN_IF_ERROR(tile16_editor_.set_tile16(id));
|
||||
show_tile16_editor_ = true;
|
||||
}
|
||||
|
||||
if (ImGui::IsItemClicked() && !blockset_canvas_.points().empty()) {
|
||||
int x = blockset_canvas_.points().front().x / 32;
|
||||
int y = blockset_canvas_.points().front().y / 32;
|
||||
current_tile16_ = x + (y * 8);
|
||||
}
|
||||
|
||||
blockset_canvas_.DrawGrid();
|
||||
blockset_canvas_.DrawOverlay();
|
||||
}
|
||||
if (ImGui::IsItemClicked() && !blockset_canvas_.points().empty()) {
|
||||
int x = blockset_canvas_.points().front().x / 32;
|
||||
int y = blockset_canvas_.points().front().y / 32;
|
||||
current_tile16_ = x + (y * 8);
|
||||
}
|
||||
blockset_canvas_.DrawGrid();
|
||||
blockset_canvas_.DrawOverlay();
|
||||
ImGui::EndChild();
|
||||
ImGui::EndGroup();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void OverworldEditor::DrawTile8Selector() {
|
||||
@@ -774,15 +790,14 @@ void OverworldEditor::DrawTile8Selector() {
|
||||
graphics_bin_canvas_.DrawOverlay();
|
||||
}
|
||||
|
||||
void OverworldEditor::DrawAreaGraphics() {
|
||||
absl::Status OverworldEditor::DrawAreaGraphics() {
|
||||
if (overworld_.is_loaded()) {
|
||||
if (current_graphics_set_.count(current_map_) == 0) {
|
||||
overworld_.set_current_map(current_map_);
|
||||
palette_ = overworld_.AreaPalette();
|
||||
gfx::Bitmap bmp;
|
||||
gui::BuildAndRenderBitmapPipeline(0x80, 0x200, 0x08,
|
||||
overworld_.current_graphics(), *rom(),
|
||||
bmp, palette_);
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
|
||||
0x80, 0x200, 0x08, overworld_.current_graphics(), bmp, palette_));
|
||||
current_graphics_set_[current_map_] = bmp;
|
||||
}
|
||||
}
|
||||
@@ -792,21 +807,24 @@ void OverworldEditor::DrawAreaGraphics() {
|
||||
gui::BeginChildWithScrollbar("##AreaGraphicsScrollRegion");
|
||||
current_gfx_canvas_.DrawBackground();
|
||||
gui::EndPadding();
|
||||
current_gfx_canvas_.DrawContextMenu();
|
||||
current_gfx_canvas_.DrawBitmap(current_graphics_set_[current_map_],
|
||||
/*border_offset=*/2, overworld_.is_loaded());
|
||||
current_gfx_canvas_.DrawTileSelector(32.0f);
|
||||
current_gfx_canvas_.DrawGrid();
|
||||
current_gfx_canvas_.DrawOverlay();
|
||||
{
|
||||
current_gfx_canvas_.DrawContextMenu();
|
||||
current_gfx_canvas_.DrawBitmap(current_graphics_set_[current_map_],
|
||||
/*border_offset=*/2, overworld_.is_loaded());
|
||||
current_gfx_canvas_.DrawTileSelector(32.0f);
|
||||
current_gfx_canvas_.DrawGrid();
|
||||
current_gfx_canvas_.DrawOverlay();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::EndGroup();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void OverworldEditor::DrawTileSelector() {
|
||||
absl::Status OverworldEditor::DrawTileSelector() {
|
||||
if (BeginTabBar(kTileSelectorTab.data(),
|
||||
ImGuiTabBarFlags_FittingPolicyScroll)) {
|
||||
if (BeginTabItem("Tile16")) {
|
||||
DrawTile16Selector();
|
||||
RETURN_IF_ERROR(DrawTile16Selector());
|
||||
EndTabItem();
|
||||
}
|
||||
if (BeginTabItem("Tile8")) {
|
||||
@@ -823,6 +841,7 @@ void OverworldEditor::DrawTileSelector() {
|
||||
}
|
||||
EndTabBar();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -940,7 +959,9 @@ bool DrawEntranceInserterPopup() {
|
||||
return set_done;
|
||||
}
|
||||
|
||||
bool DrawOverworldEntrancePopup(zelda3::OverworldEntrance &entrance) {
|
||||
// TODO: Implement deleting OverworldEntrance objects, currently only hides them
|
||||
bool DrawOverworldEntrancePopup(
|
||||
zelda3::overworld::OverworldEntrance &entrance) {
|
||||
static bool set_done = false;
|
||||
if (set_done) {
|
||||
set_done = false;
|
||||
@@ -1045,6 +1066,7 @@ void OverworldEditor::DrawOverworldEntrances(ImVec2 canvas_p0, ImVec2 scrolling,
|
||||
|
||||
namespace exit_internal {
|
||||
|
||||
// TODO: Implement deleting OverworldExit objects
|
||||
void DrawExitInserterPopup() {
|
||||
if (ImGui::BeginPopup("Exit Inserter")) {
|
||||
static int exit_id = 0;
|
||||
@@ -1063,7 +1085,7 @@ void DrawExitInserterPopup() {
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawExitEditorPopup(zelda3::OverworldExit &exit) {
|
||||
bool DrawExitEditorPopup(zelda3::overworld::OverworldExit &exit) {
|
||||
static bool set_done = false;
|
||||
if (set_done) {
|
||||
set_done = false;
|
||||
@@ -1259,8 +1281,8 @@ void DrawItemInsertPopup() {
|
||||
ImGui::Text("Add Item");
|
||||
ImGui::BeginChild("ScrollRegion", ImVec2(150, 150), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
for (int i = 0; i < zelda3::kSecretItemNames.size(); i++) {
|
||||
if (ImGui::Selectable(zelda3::kSecretItemNames[i].c_str(),
|
||||
for (int i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) {
|
||||
if (ImGui::Selectable(zelda3::overworld::kSecretItemNames[i].c_str(),
|
||||
i == new_item_id)) {
|
||||
new_item_id = i;
|
||||
}
|
||||
@@ -1282,7 +1304,8 @@ void DrawItemInsertPopup() {
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawItemEditorPopup(zelda3::OverworldItem &item) {
|
||||
// TODO: Implement deleting OverworldItem objects, currently only hides them
|
||||
bool DrawItemEditorPopup(zelda3::overworld::OverworldItem &item) {
|
||||
static bool set_done = false;
|
||||
if (set_done) {
|
||||
set_done = false;
|
||||
@@ -1292,8 +1315,8 @@ bool DrawItemEditorPopup(zelda3::OverworldItem &item) {
|
||||
ImGui::BeginChild("ScrollRegion", ImVec2(150, 150), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
ImGui::BeginGroup();
|
||||
for (int i = 0; i < zelda3::kSecretItemNames.size(); i++) {
|
||||
if (ImGui::Selectable(zelda3::kSecretItemNames[i].c_str(),
|
||||
for (int i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) {
|
||||
if (ImGui::Selectable(zelda3::overworld::kSecretItemNames[i].c_str(),
|
||||
item.id == i)) {
|
||||
item.id = i;
|
||||
}
|
||||
@@ -1326,7 +1349,7 @@ void OverworldEditor::DrawOverworldItems() {
|
||||
// Get the item's bitmap and real X and Y positions
|
||||
if (item.room_map_id < 0x40 + (current_world_ * 0x40) &&
|
||||
item.room_map_id >= (current_world_ * 0x40) && !item.deleted) {
|
||||
std::string item_name = zelda3::kSecretItemNames[item.id];
|
||||
std::string item_name = zelda3::overworld::kSecretItemNames[item.id];
|
||||
|
||||
ow_map_canvas_.DrawRect(item.x_, item.y_, 16, 16, ImVec4(255, 0, 0, 150));
|
||||
|
||||
@@ -1461,6 +1484,7 @@ void DrawSpriteTable(std::function<void(int)> onSpriteSelect) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement deleting OverworldSprite objects
|
||||
void DrawSpriteInserterPopup() {
|
||||
if (ImGui::BeginPopup("Sprite Inserter")) {
|
||||
static int new_sprite_id = 0;
|
||||
@@ -1576,8 +1600,6 @@ void OverworldEditor::DrawOverworldSprites() {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
absl::Status OverworldEditor::LoadGraphics() {
|
||||
// Load all of the graphics data from the game.
|
||||
PRINT_IF_ERROR(rom()->LoadAllGraphicsData())
|
||||
graphics_bin_ = rom()->graphics_bin();
|
||||
|
||||
// Load the Link to the Past overworld.
|
||||
@@ -1585,14 +1607,12 @@ absl::Status OverworldEditor::LoadGraphics() {
|
||||
palette_ = overworld_.AreaPalette();
|
||||
|
||||
// Create the area graphics image
|
||||
gui::BuildAndRenderBitmapPipeline(0x80, 0x200, 0x40,
|
||||
overworld_.current_graphics(), *rom(),
|
||||
current_gfx_bmp_, palette_);
|
||||
rom()->CreateAndRenderBitmap(0x80, 0x200, 0x40, overworld_.current_graphics(),
|
||||
current_gfx_bmp_, palette_);
|
||||
|
||||
// Create the tile16 blockset image
|
||||
gui::BuildAndRenderBitmapPipeline(0x80, 0x2000, 0x08,
|
||||
overworld_.Tile16Blockset(), *rom(),
|
||||
tile16_blockset_bmp_, palette_);
|
||||
rom()->CreateAndRenderBitmap(0x80, 0x2000, 0x08, overworld_.Tile16Blockset(),
|
||||
tile16_blockset_bmp_, palette_);
|
||||
map_blockset_loaded_ = true;
|
||||
|
||||
// Copy the tile16 data into individual tiles.
|
||||
@@ -1620,18 +1640,17 @@ absl::Status OverworldEditor::LoadGraphics() {
|
||||
// Render the bitmaps of each tile.
|
||||
for (int id = 0; id < 4096; id++) {
|
||||
tile16_individual_.emplace_back();
|
||||
gui::BuildAndRenderBitmapPipeline(0x10, 0x10, 0x80,
|
||||
tile16_individual_data_[id], *rom(),
|
||||
tile16_individual_[id], palette_);
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
|
||||
0x10, 0x10, 0x80, tile16_individual_data_[id], tile16_individual_[id],
|
||||
palette_));
|
||||
}
|
||||
|
||||
// Render the overworld maps loaded from the ROM.
|
||||
for (int i = 0; i < zelda3::kNumOverworldMaps; ++i) {
|
||||
for (int i = 0; i < zelda3::overworld::kNumOverworldMaps; ++i) {
|
||||
overworld_.set_current_map(i);
|
||||
auto palette = overworld_.AreaPalette();
|
||||
gui::BuildAndRenderBitmapPipeline(0x200, 0x200, 0x200,
|
||||
overworld_.BitmapData(), *rom(),
|
||||
maps_bmp_[i], palette);
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
|
||||
0x200, 0x200, 0x200, overworld_.BitmapData(), maps_bmp_[i], palette));
|
||||
}
|
||||
|
||||
if (flags()->overworld.kDrawOverworldSprites) {
|
||||
@@ -1641,19 +1660,19 @@ absl::Status OverworldEditor::LoadGraphics() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void OverworldEditor::RefreshTile16Blockset() {
|
||||
absl::Status OverworldEditor::RefreshTile16Blockset() {
|
||||
if (current_blockset_ ==
|
||||
overworld_.overworld_map(current_map_)->area_graphics()) {
|
||||
return;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
current_blockset_ = overworld_.overworld_map(current_map_)->area_graphics();
|
||||
|
||||
overworld_.set_current_map(current_map_);
|
||||
palette_ = overworld_.AreaPalette();
|
||||
// Create the tile16 blockset image
|
||||
gui::BuildAndRenderBitmapPipeline(0x80, 0x2000, 0x08,
|
||||
overworld_.Tile16Blockset(), *rom(),
|
||||
tile16_blockset_bmp_, palette_);
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(0x80, 0x2000, 0x08,
|
||||
overworld_.Tile16Blockset(),
|
||||
tile16_blockset_bmp_, palette_));
|
||||
|
||||
// Copy the tile16 data into individual tiles.
|
||||
auto tile16_data = overworld_.Tile16Blockset();
|
||||
@@ -1691,9 +1710,11 @@ void OverworldEditor::RefreshTile16Blockset() {
|
||||
|
||||
// Render the bitmaps of each tile.
|
||||
for (int id = 0; id < 4096; id++) {
|
||||
tile16_individual_[id].ApplyPalette(palette_);
|
||||
RETURN_IF_ERROR(tile16_individual_[id].ApplyPalette(palette_));
|
||||
rom()->UpdateBitmap(&tile16_individual_[id]);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::LoadSpriteGraphics() {
|
||||
@@ -1705,7 +1726,7 @@ absl::Status OverworldEditor::LoadSpriteGraphics() {
|
||||
int depth = 0x40;
|
||||
auto spr_gfx = sprite.PreviewGraphics();
|
||||
sprite_previews_[sprite.id()].Create(width, height, depth, spr_gfx);
|
||||
sprite_previews_[sprite.id()].ApplyPalette(palette_);
|
||||
RETURN_IF_ERROR(sprite_previews_[sprite.id()].ApplyPalette(palette_));
|
||||
rom()->RenderBitmap(&(sprite_previews_[sprite.id()]));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
@@ -1880,15 +1901,15 @@ void OverworldEditor::DrawUsageGrid() {
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldEditor::LoadAnimatedMaps() {
|
||||
absl::Status OverworldEditor::LoadAnimatedMaps() {
|
||||
int world_index = 0;
|
||||
static std::vector<bool> animated_built(0x40, false);
|
||||
if (!animated_built[world_index]) {
|
||||
animated_maps_[world_index] = maps_bmp_[world_index];
|
||||
auto &map = *overworld_.mutable_overworld_map(world_index);
|
||||
map.DrawAnimatedTiles();
|
||||
map.BuildTileset();
|
||||
map.BuildTiles16Gfx(overworld_.tiles16().size());
|
||||
RETURN_IF_ERROR(map.BuildTileset());
|
||||
RETURN_IF_ERROR(map.BuildTiles16Gfx(overworld_.tiles16().size()));
|
||||
OWBlockset blockset;
|
||||
if (current_world_ == 0) {
|
||||
blockset = overworld_.map_tiles().light_world;
|
||||
@@ -1897,14 +1918,16 @@ void OverworldEditor::LoadAnimatedMaps() {
|
||||
} else {
|
||||
blockset = overworld_.map_tiles().special_world;
|
||||
}
|
||||
map.BuildBitmap(blockset);
|
||||
RETURN_IF_ERROR(map.BuildBitmap(blockset));
|
||||
|
||||
gui::BuildAndRenderBitmapPipeline(0x200, 0x200, 0x200, map.bitmap_data(),
|
||||
*rom(), animated_maps_[world_index],
|
||||
*map.mutable_current_palette());
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
|
||||
0x200, 0x200, 0x200, map.bitmap_data(), animated_maps_[world_index],
|
||||
*map.mutable_current_palette()));
|
||||
|
||||
animated_built[world_index] = true;
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/editor/context/entrance_context.h"
|
||||
#include "app/editor/context/gfx_context.h"
|
||||
#include "app/editor/modules/gfx_group_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/editor/modules/tile16_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
@@ -24,7 +25,7 @@
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/pipeline.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -61,9 +62,26 @@ constexpr absl::string_view kTileSelectorTab = "##TileSelectorTabBar";
|
||||
constexpr absl::string_view kOWEditTable = "##OWEditTable";
|
||||
constexpr absl::string_view kOWMapTable = "#MapSettingsTable";
|
||||
|
||||
/**
|
||||
* @class OverworldEditor
|
||||
* @brief Manipulates the Overworld and OverworldMap data in a Rom.
|
||||
*
|
||||
* The `OverworldEditor` class is responsible for managing the editing and
|
||||
* manipulation of the overworld in a game. The user can drag and drop tiles,
|
||||
* modify OverworldEntrance, OverworldExit, Sprite, and OverworldItem
|
||||
* as well as change the gfx and palettes used in each overworld map.
|
||||
*
|
||||
* The Overworld itself is a series of bitmap images which exist inside each
|
||||
* OverworldMap object. The drawing of the overworld is done using the Canvas
|
||||
* class in conjunction with these underlying Bitmap objects.
|
||||
*
|
||||
* Provides access to the GfxGroupEditor and Tile16Editor through popup windows.
|
||||
*
|
||||
*/
|
||||
class OverworldEditor : public Editor,
|
||||
public SharedROM,
|
||||
public GfxContext,
|
||||
public SharedRom,
|
||||
public context::GfxContext,
|
||||
public context::EntranceContext,
|
||||
public core::ExperimentFlags {
|
||||
public:
|
||||
absl::Status Update() final;
|
||||
@@ -75,6 +93,9 @@ class OverworldEditor : public Editor,
|
||||
|
||||
auto overworld() { return &overworld_; }
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
int jump_to_tab() { return jump_to_tab_; }
|
||||
int jump_to_tab_ = -1;
|
||||
|
||||
@@ -91,21 +112,33 @@ class OverworldEditor : public Editor,
|
||||
for (auto& [i, bmp] : current_graphics_set_) {
|
||||
bmp.Cleanup();
|
||||
}
|
||||
maps_bmp_.clear();
|
||||
overworld_.Destroy();
|
||||
all_gfx_loaded_ = false;
|
||||
map_blockset_loaded_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load the Bitmap objects for each OverworldMap.
|
||||
*
|
||||
* Calls the Overworld class to load the image data and palettes from the Rom,
|
||||
* then renders the area graphics and tile16 blockset Bitmap objects before
|
||||
* assembling the OverworldMap Bitmap objects.
|
||||
*/
|
||||
absl::Status LoadGraphics();
|
||||
|
||||
private:
|
||||
absl::Status UpdateOverworldEdit();
|
||||
absl::Status UpdateFullscreenCanvas();
|
||||
|
||||
absl::Status DrawToolset();
|
||||
void DrawOverworldMapSettings();
|
||||
|
||||
void RefreshChildMap(int i);
|
||||
void RefreshOverworldMap();
|
||||
void RefreshMapPalette();
|
||||
absl::Status RefreshMapPalette();
|
||||
void RefreshMapProperties();
|
||||
void RefreshTile16Blockset();
|
||||
absl::Status RefreshTile16Blockset();
|
||||
|
||||
void DrawOverworldEntrances(ImVec2 canvas_p, ImVec2 scrolling,
|
||||
bool holes = false);
|
||||
@@ -118,14 +151,19 @@ class OverworldEditor : public Editor,
|
||||
void RenderUpdatedMapBitmap(const ImVec2& click_position,
|
||||
const Bytes& tile_data);
|
||||
void CheckForOverworldEdits();
|
||||
void CheckForCurrentMap();
|
||||
void CheckForSelectRectangle();
|
||||
absl::Status CheckForCurrentMap();
|
||||
void CheckForMousePan();
|
||||
|
||||
/**
|
||||
* @brief Allows the user to make changes to the overworld map.
|
||||
*/
|
||||
void DrawOverworldCanvas();
|
||||
|
||||
void DrawTile16Selector();
|
||||
absl::Status DrawTile16Selector();
|
||||
void DrawTile8Selector();
|
||||
void DrawAreaGraphics();
|
||||
void DrawTileSelector();
|
||||
absl::Status DrawAreaGraphics();
|
||||
absl::Status DrawTileSelector();
|
||||
|
||||
absl::Status LoadSpriteGraphics();
|
||||
|
||||
@@ -137,7 +175,7 @@ class OverworldEditor : public Editor,
|
||||
void DrawUsageGrid();
|
||||
void CalculateUsageStats();
|
||||
|
||||
void LoadAnimatedMaps();
|
||||
absl::Status LoadAnimatedMaps();
|
||||
void DrawDebugWindow();
|
||||
|
||||
auto gfx_group_editor() const { return gfx_group_editor_; }
|
||||
@@ -197,11 +235,11 @@ class OverworldEditor : public Editor,
|
||||
zelda3::OverworldEntity* current_entity_;
|
||||
|
||||
int current_entrance_id_ = 0;
|
||||
zelda3::OverworldEntrance current_entrance_;
|
||||
zelda3::overworld::OverworldEntrance current_entrance_;
|
||||
int current_exit_id_ = 0;
|
||||
zelda3::OverworldExit current_exit_;
|
||||
zelda3::overworld::OverworldExit current_exit_;
|
||||
int current_item_id_ = 0;
|
||||
zelda3::OverworldItem current_item_;
|
||||
zelda3::overworld::OverworldItem current_item_;
|
||||
int current_sprite_id_ = 0;
|
||||
zelda3::Sprite current_sprite_;
|
||||
|
||||
@@ -219,7 +257,7 @@ class OverworldEditor : public Editor,
|
||||
Tile16Editor tile16_editor_;
|
||||
GfxGroupEditor gfx_group_editor_;
|
||||
PaletteEditor palette_editor_;
|
||||
zelda3::Overworld overworld_;
|
||||
zelda3::overworld::Overworld overworld_;
|
||||
|
||||
gui::Canvas ow_map_canvas_{ImVec2(0x200 * 8, 0x200 * 8),
|
||||
gui::CanvasGridSize::k64x64};
|
||||
|
||||
@@ -117,25 +117,30 @@ absl::Status ScreenEditor::LoadDungeonMaps() {
|
||||
for (int d = 0; d < 14; d++) {
|
||||
current_floor_rooms_d.clear();
|
||||
current_floor_gfx_d.clear();
|
||||
ASSIGN_OR_RETURN(int ptr,
|
||||
rom()->ReadWord(zelda3::kDungeonMapRoomsPtr + (d * 2)));
|
||||
ASSIGN_OR_RETURN(int ptrGFX,
|
||||
rom()->ReadWord(zelda3::kDungeonMapRoomsPtr + (d * 2)));
|
||||
ASSIGN_OR_RETURN(
|
||||
int ptr,
|
||||
rom()->ReadWord(zelda3::screen::kDungeonMapRoomsPtr + (d * 2)));
|
||||
ASSIGN_OR_RETURN(
|
||||
int ptrGFX,
|
||||
rom()->ReadWord(zelda3::screen::kDungeonMapRoomsPtr + (d * 2)));
|
||||
ptr |= 0x0A0000; // Add bank to the short ptr
|
||||
ptrGFX |= 0x0A0000; // Add bank to the short ptr
|
||||
int pcPtr = core::SnesToPc(ptr); // Contains data for the next 25 rooms
|
||||
int pcPtrGFX =
|
||||
core::SnesToPc(ptrGFX); // Contains data for the next 25 rooms
|
||||
|
||||
ASSIGN_OR_RETURN(ushort bossRoomD,
|
||||
rom()->ReadWord(zelda3::kDungeonMapBossRooms + (d * 2)));
|
||||
ASSIGN_OR_RETURN(
|
||||
ushort bossRoomD,
|
||||
rom()->ReadWord(zelda3::screen::kDungeonMapBossRooms + (d * 2)));
|
||||
|
||||
ASSIGN_OR_RETURN(nbr_basement_d,
|
||||
rom()->ReadByte(zelda3::kDungeonMapFloors + (d * 2)));
|
||||
ASSIGN_OR_RETURN(
|
||||
nbr_basement_d,
|
||||
rom()->ReadByte(zelda3::screen::kDungeonMapFloors + (d * 2)));
|
||||
nbr_basement_d &= 0x0F;
|
||||
|
||||
ASSIGN_OR_RETURN(nbr_floor_d,
|
||||
rom()->ReadByte(zelda3::kDungeonMapFloors + (d * 2)));
|
||||
ASSIGN_OR_RETURN(
|
||||
nbr_floor_d,
|
||||
rom()->ReadByte(zelda3::screen::kDungeonMapFloors + (d * 2)));
|
||||
nbr_floor_d &= 0xF0;
|
||||
nbr_floor_d = nbr_floor_d >> 4;
|
||||
|
||||
@@ -179,8 +184,8 @@ absl::Status ScreenEditor::LoadDungeonMaps() {
|
||||
|
||||
absl::Status ScreenEditor::SaveDungeonMaps() {
|
||||
for (int d = 0; d < 14; d++) {
|
||||
int ptr = zelda3::kDungeonMapRoomsPtr + (d * 2);
|
||||
int ptrGFX = zelda3::kDungeonMapGfxPtr + (d * 2);
|
||||
int ptr = zelda3::screen::kDungeonMapRoomsPtr + (d * 2);
|
||||
int ptrGFX = zelda3::screen::kDungeonMapGfxPtr + (d * 2);
|
||||
int pcPtr = core::SnesToPc(ptr);
|
||||
int pcPtrGFX = core::SnesToPc(ptrGFX);
|
||||
|
||||
@@ -208,9 +213,9 @@ absl::Status ScreenEditor::LoadDungeonMapTile16() {
|
||||
tile16_sheet_.Init(256, 192, gfx::TileType::Tile16);
|
||||
|
||||
for (int i = 0; i < 186; i++) {
|
||||
int addr = zelda3::kDungeonMapTile16;
|
||||
if (rom()->data()[zelda3::kDungeonMapExpCheck] != 0xB9) {
|
||||
addr = zelda3::kDungeonMapTile16Expanded;
|
||||
int addr = zelda3::screen::kDungeonMapTile16;
|
||||
if (rom()->data()[zelda3::screen::kDungeonMapExpCheck] != 0xB9) {
|
||||
addr = zelda3::screen::kDungeonMapTile16Expanded;
|
||||
}
|
||||
|
||||
ASSIGN_OR_RETURN(auto tl, rom()->ReadWord(addr + (i * 8)));
|
||||
|
||||
@@ -22,7 +22,21 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class ScreenEditor : public SharedROM {
|
||||
/**
|
||||
* @brief The ScreenEditor class allows the user to edit a variety of screens in
|
||||
* the game or create a custom menu.
|
||||
*
|
||||
* This class is currently a work in progress (WIP) and provides functionality
|
||||
* for updating the screens, saving dungeon maps, drawing different types of
|
||||
* screens, loading dungeon maps, and managing various properties related to the
|
||||
* editor.
|
||||
*
|
||||
* The screens that can be edited include the title screen, naming screen,
|
||||
* overworld map, inventory menu, and more.
|
||||
*
|
||||
* The class inherits from the SharedRom class.
|
||||
*/
|
||||
class ScreenEditor : public SharedRom {
|
||||
public:
|
||||
ScreenEditor();
|
||||
void Update();
|
||||
@@ -43,7 +57,7 @@ class ScreenEditor : public SharedROM {
|
||||
void DrawDungeonMapsTabs();
|
||||
void DrawDungeonMapsEditor();
|
||||
|
||||
std::vector<zelda3::DungeonMap> dungeon_maps_;
|
||||
std::vector<zelda3::screen::DungeonMap> dungeon_maps_;
|
||||
std::vector<std::vector<std::array<std::string, 25>>> dungeon_map_labels_;
|
||||
|
||||
std::unordered_map<int, gfx::Bitmap> tile16_individual_;
|
||||
@@ -60,7 +74,7 @@ class ScreenEditor : public SharedROM {
|
||||
bool paste_button_pressed = false;
|
||||
|
||||
Bytes all_gfx_;
|
||||
zelda3::Inventory inventory_;
|
||||
zelda3::screen::Inventory inventory_;
|
||||
gfx::SnesPalette palette_;
|
||||
gui::Canvas screen_canvas_;
|
||||
gui::Canvas tilesheet_canvas_;
|
||||
|
||||
@@ -9,17 +9,41 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class SpriteEditor : public SharedROM {
|
||||
/**
|
||||
* @class SpriteEditor
|
||||
* @brief Allows the user to edit sprites.
|
||||
*
|
||||
* This class provides functionality for updating the sprite editor, drawing the
|
||||
* editor table, drawing the sprite canvas, and drawing the current sheets.
|
||||
*/
|
||||
class SpriteEditor : public SharedRom {
|
||||
public:
|
||||
/**
|
||||
* @brief Updates the sprite editor.
|
||||
*
|
||||
* @return An absl::Status indicating the success or failure of the update.
|
||||
*/
|
||||
absl::Status Update();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Draws the editor table.
|
||||
*/
|
||||
void DrawEditorTable();
|
||||
|
||||
/**
|
||||
* @brief Draws the sprite canvas.
|
||||
*/
|
||||
void DrawSpriteCanvas();
|
||||
|
||||
/**
|
||||
* @brief Draws the current sheets.
|
||||
*/
|
||||
void DrawCurrentSheets();
|
||||
|
||||
uint8_t current_sheets_[8];
|
||||
bool sheets_loaded_ = false;
|
||||
uint8_t current_sheets_[8]; /**< Array to store the current sheets. */
|
||||
bool sheets_loaded_ =
|
||||
false; /**< Flag indicating whether the sheets are loaded or not. */
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
|
||||
40
src/app/editor/utils/editor.h
Normal file
40
src/app/editor/utils/editor.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef YAZE_APP_CORE_EDITOR_H
|
||||
#define YAZE_APP_CORE_EDITOR_H
|
||||
|
||||
#include "absl/status/status.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
|
||||
/**
|
||||
* @namespace yaze::app::editor
|
||||
* @brief Editors are the view controllers for the application.
|
||||
*/
|
||||
namespace editor {
|
||||
|
||||
/**
|
||||
* @class Editor
|
||||
* @brief Interface for editor classes.
|
||||
*
|
||||
* Provides basic editing operations that each editor should implement.
|
||||
*/
|
||||
class Editor {
|
||||
public:
|
||||
Editor() = default;
|
||||
virtual ~Editor() = default;
|
||||
|
||||
virtual absl::Status Cut() = 0;
|
||||
virtual absl::Status Copy() = 0;
|
||||
virtual absl::Status Paste() = 0;
|
||||
|
||||
virtual absl::Status Undo() = 0;
|
||||
virtual absl::Status Redo() = 0;
|
||||
|
||||
virtual absl::Status Update() = 0;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_CORE_EDITOR_H
|
||||
Reference in New Issue
Block a user