backend-infra-engineer: Pre-0.2.2 2024 Q4 snapshot
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
#include "assembly_editor.h"
|
||||
|
||||
#include "ImGuiColorTextEdit/TextEditor.h"
|
||||
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "app/core/platform/file_dialog.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "core/constants.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
using core::FileDialogWrapper;
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::string> RemoveIgnoredFiles(
|
||||
@@ -57,11 +58,11 @@ core::FolderItem LoadFolder(const std::string& folder) {
|
||||
auto root_files = FileDialogWrapper::GetFilesInFolder(current_folder.name);
|
||||
current_folder.files = RemoveIgnoredFiles(root_files, ignored_files);
|
||||
|
||||
for (const auto& folder :
|
||||
for (const auto& subfolder :
|
||||
FileDialogWrapper::GetSubdirectoriesInFolder(current_folder.name)) {
|
||||
core::FolderItem folder_item;
|
||||
folder_item.name = folder;
|
||||
std::string full_folder = current_folder.name + "/" + folder;
|
||||
folder_item.name = subfolder;
|
||||
std::string full_folder = current_folder.name + "/" + subfolder;
|
||||
auto folder_files = FileDialogWrapper::GetFilesInFolder(full_folder);
|
||||
for (const auto& files : folder_files) {
|
||||
// Remove subdirectory files
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#ifndef YAZE_APP_EDITOR_ASSEMBLY_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_ASSEMBLY_EDITOR_H
|
||||
|
||||
#include "ImGuiColorTextEdit/TextEditor.h"
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
#include "ImGuiColorTextEdit/TextEditor.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gui/style.h"
|
||||
|
||||
namespace yaze {
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
#ifndef YAZE_APP_EDITOR_CODE_MEMORY_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_CODE_MEMORY_EDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/core/platform/file_dialog.h"
|
||||
#include "app/core/project.h"
|
||||
#include "app/editor/code/assembly_editor.h"
|
||||
#include "app/editor/code/memory_editor.h"
|
||||
#include "app/editor/dungeon/dungeon_editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/editor/graphics/graphics_editor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/graphics/screen_editor.h"
|
||||
#include "app/editor/music/music_editor.h"
|
||||
#include "app/editor/overworld_editor.h"
|
||||
#include "app/editor/overworld/overworld_editor.h"
|
||||
#include "app/editor/sprite/sprite_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/utils/gfx_context.h"
|
||||
#include "app/editor/utils/recent_files.h"
|
||||
#include "app/emu/emulator.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
@@ -30,6 +23,9 @@
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/rom.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -46,7 +42,7 @@ struct MemoryEditorWithDiffChecker : public SharedRom {
|
||||
static Rom comparison_rom;
|
||||
ImGui::Begin("Hex Editor", &show_memory_editor);
|
||||
if (ImGui::Button("Compare Rom")) {
|
||||
auto file_name = FileDialogWrapper::ShowOpenFileDialog();
|
||||
auto file_name = core::FileDialogWrapper::ShowOpenFileDialog();
|
||||
PRINT_IF_ERROR(comparison_rom.LoadFromFile(file_name));
|
||||
show_compare_rom = true;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "dungeon_editor.h"
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/labeling.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "app/core/platform/renderer.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/color.h"
|
||||
@@ -11,13 +9,15 @@
|
||||
#include "app/gui/input.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/dungeon/object_names.h"
|
||||
#include "app/zelda3/dungeon/room_names.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "zelda3/dungeon/room.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
using core::Renderer;
|
||||
|
||||
using ImGui::BeginChild;
|
||||
using ImGui::BeginTabBar;
|
||||
using ImGui::BeginTabItem;
|
||||
@@ -50,21 +50,22 @@ absl::Status DungeonEditor::Update() {
|
||||
refresh_graphics_ = false;
|
||||
}
|
||||
|
||||
TAB_BAR("##DungeonEditorTabBar")
|
||||
TAB_ITEM("Room Editor")
|
||||
status_ = UpdateDungeonRoomView();
|
||||
END_TAB_ITEM()
|
||||
TAB_ITEM("Usage Statistics")
|
||||
if (is_loaded_) {
|
||||
static bool calc_stats = false;
|
||||
if (!calc_stats) {
|
||||
CalculateUsageStats();
|
||||
calc_stats = true;
|
||||
if (ImGui::BeginTabBar("##DungeonEditorTabBar")) {
|
||||
TAB_ITEM("Room Editor")
|
||||
status_ = UpdateDungeonRoomView();
|
||||
END_TAB_ITEM()
|
||||
TAB_ITEM("Usage Statistics")
|
||||
if (is_loaded_) {
|
||||
static bool calc_stats = false;
|
||||
if (!calc_stats) {
|
||||
CalculateUsageStats();
|
||||
calc_stats = true;
|
||||
}
|
||||
DrawUsageStats();
|
||||
}
|
||||
DrawUsageStats();
|
||||
END_TAB_ITEM()
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
END_TAB_ITEM()
|
||||
END_TAB_BAR()
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -72,7 +73,7 @@ absl::Status DungeonEditor::Update() {
|
||||
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_.emplace_back(zelda3::dungeon::Room(/*room_id=*/i));
|
||||
rooms_[i].LoadHeader();
|
||||
rooms_[i].LoadRoomFromROM();
|
||||
if (flags()->kDrawDungeonRoomGraphics) {
|
||||
@@ -107,7 +108,7 @@ absl::Status DungeonEditor::Initialize() {
|
||||
ASSIGN_OR_RETURN(current_palette_group_,
|
||||
gfx::CreatePaletteGroupFromLargePalette(full_palette_));
|
||||
|
||||
graphics_bin_ = *rom()->mutable_bitmap_manager();
|
||||
graphics_bin_ = rom()->gfx_sheets();
|
||||
// Create a vector of pointers to the current block bitmaps
|
||||
for (int block : rooms_[current_room_id_].blocks()) {
|
||||
room_gfx_sheets_.emplace_back(&graphics_bin_[block]);
|
||||
@@ -120,14 +121,14 @@ absl::Status DungeonEditor::RefreshGraphics() {
|
||||
int block = rooms_[current_room_id_].blocks()[i];
|
||||
RETURN_IF_ERROR(graphics_bin_[block].ApplyPaletteWithTransparent(
|
||||
current_palette_group_[current_palette_id_], 0));
|
||||
rom()->UpdateBitmap(&graphics_bin_[block], true);
|
||||
Renderer::GetInstance().UpdateBitmap(&graphics_bin_[block]);
|
||||
}
|
||||
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];
|
||||
RETURN_IF_ERROR(graphics_bin_[block].ApplyPaletteWithTransparent(
|
||||
sprites_aux1_pal_group[current_palette_id_], 0));
|
||||
rom()->UpdateBitmap(&graphics_bin_[block], true);
|
||||
Renderer::GetInstance().UpdateBitmap(&graphics_bin_[block]);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -195,14 +196,15 @@ absl::Status DungeonEditor::UpdateDungeonRoomView() {
|
||||
TableNextRow();
|
||||
|
||||
TableNextColumn();
|
||||
TAB_BAR("##DungeonRoomTabBar");
|
||||
TAB_ITEM("Rooms");
|
||||
DrawRoomSelector();
|
||||
END_TAB_ITEM();
|
||||
TAB_ITEM("Entrances");
|
||||
DrawEntranceSelector();
|
||||
END_TAB_ITEM();
|
||||
END_TAB_BAR();
|
||||
if (ImGui::BeginTabBar("##DungeonRoomTabBar")) {
|
||||
TAB_ITEM("Rooms");
|
||||
DrawRoomSelector();
|
||||
END_TAB_ITEM();
|
||||
TAB_ITEM("Entrances");
|
||||
DrawEntranceSelector();
|
||||
END_TAB_ITEM();
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
TableNextColumn();
|
||||
DrawDungeonTabView();
|
||||
@@ -320,7 +322,7 @@ void DungeonEditor::DrawRoomSelector() {
|
||||
for (const auto each_room_name : zelda3::dungeon::kRoomNames) {
|
||||
rom()->resource_label()->SelectableLabelWithNameEdit(
|
||||
current_room_id_ == i, "Dungeon Room Names",
|
||||
core::UppercaseHexByte(i), zelda3::dungeon::kRoomNames[i].data());
|
||||
core::UppercaseHexByte(i), each_room_name.data());
|
||||
if (ImGui::IsItemClicked()) {
|
||||
// TODO: Jump to tab if room is already open
|
||||
current_room_id_ = i;
|
||||
@@ -498,7 +500,7 @@ void DungeonEditor::DrawRoomGraphics() {
|
||||
top_left_y = room_gfx_canvas_.zero_point().y + height * current_block;
|
||||
}
|
||||
room_gfx_canvas_.draw_list()->AddImage(
|
||||
(void*)graphics_bin_[block].texture(),
|
||||
(ImTextureID)(intptr_t)graphics_bin_[block].texture(),
|
||||
ImVec2(room_gfx_canvas_.zero_point().x + 2, top_left_y),
|
||||
ImVec2(room_gfx_canvas_.zero_point().x + 0x100,
|
||||
room_gfx_canvas_.zero_point().y + offset));
|
||||
@@ -547,7 +549,7 @@ void DungeonEditor::DrawObjectRenderer() {
|
||||
current_object_ = i;
|
||||
object_renderer_.LoadObject(i,
|
||||
rooms_[current_room_id_].mutable_blocks());
|
||||
rom()->RenderBitmap(object_renderer_.bitmap());
|
||||
Renderer::GetInstance().RenderBitmap(object_renderer_.bitmap());
|
||||
object_loaded_ = true;
|
||||
}
|
||||
i += 1;
|
||||
@@ -827,4 +829,4 @@ void DungeonEditor::DrawUsageGrid() {
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
} // namespace yaze
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#ifndef YAZE_APP_EDITOR_DUNGEONEDITOR_H
|
||||
#define YAZE_APP_EDITOR_DUNGEONEDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/labeling.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "app/editor/graphics/gfx_group_editor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/rom.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "zelda3/dungeon/room.h"
|
||||
#include "zelda3/dungeon/room_entrance.h"
|
||||
#include "zelda3/dungeon/room_object.h"
|
||||
@@ -100,7 +98,6 @@ class DungeonEditor : public Editor,
|
||||
bool object_loaded_ = false;
|
||||
bool palette_showing_ = false;
|
||||
bool refresh_graphics_ = false;
|
||||
bool show_object_render_ = false;
|
||||
|
||||
uint16_t current_entrance_id_ = 0;
|
||||
uint16_t current_room_id_ = 0;
|
||||
@@ -120,12 +117,11 @@ class DungeonEditor : public Editor,
|
||||
gui::Canvas object_canvas_;
|
||||
|
||||
gfx::Bitmap room_gfx_bmp_;
|
||||
gfx::BitmapManager graphics_bin_;
|
||||
std::array<gfx::Bitmap, kNumGfxSheets> graphics_bin_;
|
||||
|
||||
std::vector<gfx::Bitmap*> room_gfx_sheets_;
|
||||
std::vector<zelda3::dungeon::Room> rooms_;
|
||||
std::vector<zelda3::dungeon::RoomEntrance> entrances_;
|
||||
std::vector<gfx::BitmapManager> room_graphics_;
|
||||
zelda3::dungeon::DungeonObjectRenderer object_renderer_;
|
||||
|
||||
absl::flat_hash_map<uint16_t, int> spriteset_usage_;
|
||||
|
||||
52
src/app/editor/editor.cc
Normal file
52
src/app/editor/editor.cc
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "editor.h"
|
||||
|
||||
#include "app/core/constants.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
absl::Status DrawEditor(EditorLayoutParams *params) {
|
||||
if (params->editor == nullptr) {
|
||||
return absl::InternalError("Editor is not initialized");
|
||||
}
|
||||
|
||||
// Draw the editors based on h_split and v_split in a recursive manner
|
||||
if (params->v_split) {
|
||||
ImGui::BeginTable("##VerticalSplitTable", 2);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (params->left)
|
||||
RETURN_IF_ERROR(DrawEditor(params->left));
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (params->right)
|
||||
RETURN_IF_ERROR(DrawEditor(params->right));
|
||||
|
||||
ImGui::EndTable();
|
||||
} else if (params->h_split) {
|
||||
ImGui::BeginTable("##HorizontalSplitTable", 1);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (params->top)
|
||||
RETURN_IF_ERROR(DrawEditor(params->top));
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (params->bottom)
|
||||
RETURN_IF_ERROR(DrawEditor(params->bottom));
|
||||
|
||||
ImGui::EndTable();
|
||||
} else {
|
||||
// No split, just draw the single editor
|
||||
ImGui::Text("%s Editor",
|
||||
kEditorNames[static_cast<int>(params->editor->type())]);
|
||||
RETURN_IF_ERROR(params->editor->Update());
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -1,21 +1,21 @@
|
||||
set(
|
||||
YAZE_APP_EDITOR_SRC
|
||||
app/editor/editor.cc
|
||||
app/editor/editor_manager.cc
|
||||
app/editor/dungeon/dungeon_editor.cc
|
||||
app/editor/master_editor.cc
|
||||
app/editor/master_editor_test.cc
|
||||
app/editor/settings_editor.cc
|
||||
app/editor/overworld_editor.cc
|
||||
app/editor/overworld/overworld_editor.cc
|
||||
app/editor/sprite/sprite_editor.cc
|
||||
app/editor/music/music_editor.cc
|
||||
app/editor/message/message_editor.cc
|
||||
app/editor/message/message_editor_test.cc
|
||||
app/editor/message/message_data.cc
|
||||
app/editor/code/assembly_editor.cc
|
||||
app/editor/graphics/screen_editor.cc
|
||||
app/editor/graphics/graphics_editor.cc
|
||||
app/editor/graphics/palette_editor.cc
|
||||
app/editor/graphics/tile16_editor.cc
|
||||
app/editor/graphics/gfx_group_editor.cc
|
||||
app/editor/utils/gfx_context.cc
|
||||
app/editor/overworld/refresh.cc
|
||||
app/editor/overworld/entity.cc
|
||||
)
|
||||
app/editor/system/settings_editor.cc
|
||||
app/editor/system/command_manager.cc
|
||||
app/editor/system/extension_manager.cc
|
||||
)
|
||||
@@ -1,7 +1,14 @@
|
||||
#ifndef YAZE_APP_CORE_EDITOR_H
|
||||
#define YAZE_APP_CORE_EDITOR_H
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/editor/system/command_manager.h"
|
||||
#include "app/editor/system/constant_manager.h"
|
||||
#include "app/editor/system/extension_manager.h"
|
||||
#include "app/editor/system/history_manager.h"
|
||||
#include "app/editor/system/resource_manager.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -12,6 +19,14 @@ namespace app {
|
||||
*/
|
||||
namespace editor {
|
||||
|
||||
struct EditorContext {
|
||||
ConstantManager constant_manager;
|
||||
CommandManager command_manager;
|
||||
ExtensionManager extension_manager;
|
||||
HistoryManager history_manager;
|
||||
ResourceManager resource_manager;
|
||||
};
|
||||
|
||||
enum class EditorType {
|
||||
kAssembly,
|
||||
kDungeon,
|
||||
@@ -25,7 +40,7 @@ enum class EditorType {
|
||||
kSettings,
|
||||
};
|
||||
|
||||
constexpr std::array<const char*, 10> kEditorNames = {
|
||||
constexpr std::array<const char *, 10> kEditorNames = {
|
||||
"Assembly", "Dungeon", "Graphics", "Music", "Overworld",
|
||||
"Palette", "Screen", "Sprite", "Message", "Settings",
|
||||
};
|
||||
@@ -56,10 +71,35 @@ class Editor {
|
||||
|
||||
protected:
|
||||
EditorType type_;
|
||||
EditorContext context_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Dynamic Editor Layout Parameters
|
||||
*/
|
||||
typedef struct EditorLayoutParams {
|
||||
bool v_split;
|
||||
bool h_split;
|
||||
int v_split_pos;
|
||||
int h_split_pos;
|
||||
Editor *editor = nullptr;
|
||||
EditorLayoutParams *left = nullptr;
|
||||
EditorLayoutParams *right = nullptr;
|
||||
EditorLayoutParams *top = nullptr;
|
||||
EditorLayoutParams *bottom = nullptr;
|
||||
|
||||
EditorLayoutParams() {
|
||||
v_split = false;
|
||||
h_split = false;
|
||||
v_split_pos = 0;
|
||||
h_split_pos = 0;
|
||||
}
|
||||
} EditorLayoutParams;
|
||||
|
||||
absl::Status DrawEditor(EditorLayoutParams *params);
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_CORE_EDITOR_H
|
||||
#endif // YAZE_APP_CORE_EDITOR_H
|
||||
@@ -1,48 +1,39 @@
|
||||
#include "master_editor.h"
|
||||
|
||||
#include "ImGuiColorTextEdit/TextEditor.h"
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
#include "abseil-cpp/absl/strings/match.h"
|
||||
#include "imgui/backends/imgui_impl_sdl2.h"
|
||||
#include "imgui/backends/imgui_impl_sdlrenderer2.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
#include "editor_manager.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/common.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/core/platform/file_dialog.h"
|
||||
#include "app/core/project.h"
|
||||
#include "app/editor/code/assembly_editor.h"
|
||||
#include "app/editor/dungeon/dungeon_editor.h"
|
||||
#include "app/editor/graphics/graphics_editor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/graphics/screen_editor.h"
|
||||
#include "app/editor/music/music_editor.h"
|
||||
#include "app/editor/overworld_editor.h"
|
||||
#include "app/editor/overworld/overworld_editor.h"
|
||||
#include "app/editor/sprite/sprite_editor.h"
|
||||
#include "app/editor/utils/flags.h"
|
||||
#include "app/editor/utils/recent_files.h"
|
||||
#include "app/editor/system/flags.h"
|
||||
#include "app/emu/emulator.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/input.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/rom.h"
|
||||
#include "editor/editor.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
using namespace ImGui;
|
||||
using core::FileDialogWrapper;
|
||||
|
||||
namespace {
|
||||
|
||||
bool BeginCentered(const char *name) {
|
||||
ImGuiIO const &io = GetIO();
|
||||
|
||||
bool BeginCentered(const char* name) {
|
||||
ImGuiIO const& io = GetIO();
|
||||
ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f);
|
||||
SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
ImGuiWindowFlags flags =
|
||||
@@ -58,21 +49,18 @@ bool IsEditorActive(Editor* editor, std::vector<Editor*>& active_editors) {
|
||||
|
||||
} // namespace
|
||||
|
||||
void MasterEditor::SetupScreen(std::shared_ptr<SDL_Renderer> renderer,
|
||||
std::string filename) {
|
||||
sdl_renderer_ = renderer;
|
||||
rom()->SetupRenderer(renderer);
|
||||
void EditorManager::SetupScreen(std::string filename) {
|
||||
if (!filename.empty()) {
|
||||
PRINT_IF_ERROR(rom()->LoadFromFile(filename));
|
||||
}
|
||||
overworld_editor_.InitializeZeml();
|
||||
InitializeCommands();
|
||||
}
|
||||
|
||||
absl::Status MasterEditor::Update() {
|
||||
absl::Status EditorManager::Update() {
|
||||
ManageKeyboardShortcuts();
|
||||
|
||||
DrawYazeMenu();
|
||||
DrawFileDialog();
|
||||
DrawStatusPopup();
|
||||
DrawAboutPopup();
|
||||
DrawInfoPopup();
|
||||
@@ -85,12 +73,15 @@ absl::Status MasterEditor::Update() {
|
||||
rom_assets_loaded_ = true;
|
||||
}
|
||||
|
||||
ManageActiveEditors();
|
||||
if (dynamic_layout_)
|
||||
RETURN_IF_ERROR(DrawDynamicLayout())
|
||||
else
|
||||
ManageActiveEditors();
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void MasterEditor::ManageActiveEditors() {
|
||||
void EditorManager::ManageActiveEditors() {
|
||||
// Show popup pane to select an editor to add
|
||||
static bool show_add_editor = false;
|
||||
if (show_add_editor) OpenPopup("AddEditor");
|
||||
@@ -253,16 +244,23 @@ void MasterEditor::ManageActiveEditors() {
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::ManageKeyboardShortcuts() {
|
||||
absl::Status EditorManager::DrawDynamicLayout() {
|
||||
// Dynamic layout for multiple editors to be open at once
|
||||
// Allows for tiling and resizing of editors using ImGui
|
||||
return DrawEditor(&root_layout_);
|
||||
}
|
||||
|
||||
void EditorManager::ManageKeyboardShortcuts() {
|
||||
bool ctrl_or_super = (GetIO().KeyCtrl || GetIO().KeySuper);
|
||||
|
||||
editor_context_.command_manager.ShowWhichKey();
|
||||
|
||||
// If CMD + R is pressed, reload the top result of recent files
|
||||
if (IsKeyDown(ImGuiKey_R) && ctrl_or_super) {
|
||||
static RecentFilesManager manager("recent_files.txt");
|
||||
manager.Load();
|
||||
if (!manager.GetRecentFiles().empty()) {
|
||||
auto front = manager.GetRecentFiles().front();
|
||||
std::cout << "Reloading: " << front << std::endl;
|
||||
OpenRomOrProject(front);
|
||||
}
|
||||
}
|
||||
@@ -311,55 +309,113 @@ void MasterEditor::ManageKeyboardShortcuts() {
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawFileDialog() {
|
||||
gui::FileDialogPipeline("ChooseFileDlgKey", ".sfc,.smc", std::nullopt, [&]() {
|
||||
std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
|
||||
status_ = rom()->LoadFromFile(filePathName);
|
||||
static RecentFilesManager manager("recent_files.txt");
|
||||
void EditorManager::InitializeCommands() {
|
||||
if (root_layout_.editor == nullptr) {
|
||||
root_layout_.editor = &overworld_editor_;
|
||||
}
|
||||
|
||||
// Load existing recent files
|
||||
manager.Load();
|
||||
// New editor popup for window management commands
|
||||
static EditorLayoutParams new_layout;
|
||||
if (ImGui::BeginPopup("NewEditor")) {
|
||||
ImGui::Text("New Editor");
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("Overworld")) {
|
||||
new_layout.editor = &overworld_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Dungeon")) {
|
||||
new_layout.editor = &dungeon_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Graphics")) {
|
||||
new_layout.editor = &graphics_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Music")) {
|
||||
new_layout.editor = &music_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Palette")) {
|
||||
new_layout.editor = &palette_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Screen")) {
|
||||
new_layout.editor = &screen_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Sprite")) {
|
||||
new_layout.editor = &sprite_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Code")) {
|
||||
new_layout.editor = &assembly_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Settings")) {
|
||||
new_layout.editor = &settings_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Message")) {
|
||||
new_layout.editor = &message_editor_;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Add a new file
|
||||
manager.AddFile(filePathName);
|
||||
|
||||
// Save the updated list
|
||||
manager.Save();
|
||||
});
|
||||
editor_context_.command_manager.RegisterPrefix("window", 'w',
|
||||
"window management", "");
|
||||
editor_context_.command_manager.RegisterSubcommand(
|
||||
"window", "vsplit", '/', "vertical split",
|
||||
"split windows vertically and place editor in new window", [this]() {
|
||||
ImGui::OpenPopup("NewEditor");
|
||||
root_layout_.v_split = true;
|
||||
});
|
||||
editor_context_.command_manager.RegisterSubcommand(
|
||||
"window", "hsplit", '-', "horizontal split",
|
||||
"split windows horizontally and place editor in new window", [this]() {
|
||||
ImGui::OpenPopup("NewEditor");
|
||||
root_layout_.h_split = true;
|
||||
});
|
||||
editor_context_.command_manager.RegisterSubcommand(
|
||||
"window", "close", 'd', "close", "close the current editor", [this]() {
|
||||
if (root_layout_.editor != nullptr) {
|
||||
root_layout_.editor = nullptr;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MasterEditor::DrawStatusPopup() {
|
||||
void EditorManager::DrawStatusPopup() {
|
||||
static absl::Status prev_status;
|
||||
if (!status_.ok()) {
|
||||
show_status_ = true;
|
||||
prev_status_ = status_;
|
||||
prev_status = status_;
|
||||
}
|
||||
|
||||
if (show_status_ && (BeginCentered("StatusWindow"))) {
|
||||
Text("%s", ICON_MD_ERROR);
|
||||
Text("%s", prev_status_.ToString().c_str());
|
||||
Text("%s", prev_status.ToString().c_str());
|
||||
Spacing();
|
||||
NextColumn();
|
||||
Columns(1);
|
||||
Separator();
|
||||
NewLine();
|
||||
SameLine(128);
|
||||
if (Button("OK", gui::kDefaultModalSize) ||
|
||||
IsKeyPressed(GetKeyIndex(ImGuiKey_Space))) {
|
||||
if (Button("OK", gui::kDefaultModalSize) || IsKeyPressed(ImGuiKey_Space)) {
|
||||
show_status_ = false;
|
||||
status_ = absl::OkStatus();
|
||||
}
|
||||
SameLine();
|
||||
if (Button(ICON_MD_CONTENT_COPY, ImVec2(50, 0))) {
|
||||
SetClipboardText(prev_status_.ToString().c_str());
|
||||
SetClipboardText(prev_status.ToString().c_str());
|
||||
}
|
||||
End();
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawAboutPopup() {
|
||||
void EditorManager::DrawAboutPopup() {
|
||||
if (about_) OpenPopup("About");
|
||||
if (BeginPopupModal("About", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
Text("Yet Another Zelda3 Editor - v%.2f", core::kYazeVersion);
|
||||
Text("Yet Another Zelda3 Editor - v%s", core::kYazeVersion.data());
|
||||
Text("Written by: scawful");
|
||||
Spacing();
|
||||
Text("Special Thanks: Zarby89, JaredBrian");
|
||||
@@ -373,15 +429,15 @@ void MasterEditor::DrawAboutPopup() {
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawInfoPopup() {
|
||||
void EditorManager::DrawInfoPopup() {
|
||||
if (rom_info_) OpenPopup("ROM Information");
|
||||
if (BeginPopupModal("ROM Information", nullptr,
|
||||
ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
Text("Title: %s", rom()->title());
|
||||
Text("ROM Size: %ld", rom()->size());
|
||||
Text("Title: %s", rom()->title().c_str());
|
||||
Text("ROM Size: %s", core::UppercaseHexLongLong(rom()->size()).c_str());
|
||||
|
||||
if (Button("Close", gui::kDefaultModalSize) ||
|
||||
IsKeyPressed(GetKeyIndex(ImGuiKey_Space))) {
|
||||
IsKeyPressed(ImGuiKey_Escape)) {
|
||||
rom_info_ = false;
|
||||
CloseCurrentPopup();
|
||||
}
|
||||
@@ -389,33 +445,19 @@ void MasterEditor::DrawInfoPopup() {
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawYazeMenu() {
|
||||
void EditorManager::DrawYazeMenu() {
|
||||
static bool show_display_settings = false;
|
||||
static bool show_command_line_interface = false;
|
||||
|
||||
if (BeginMenuBar()) {
|
||||
DrawFileMenu();
|
||||
DrawEditMenu();
|
||||
DrawViewMenu();
|
||||
DrawTestMenu();
|
||||
DrawProjectMenu();
|
||||
DrawHelpMenu();
|
||||
|
||||
DrawYazeMenuBar();
|
||||
SameLine(GetWindowWidth() - GetStyle().ItemSpacing.x -
|
||||
CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 150);
|
||||
// Modify the style of the button to have no background color
|
||||
CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 110);
|
||||
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
if (Button(ICON_MD_DISPLAY_SETTINGS)) {
|
||||
show_display_settings = !show_display_settings;
|
||||
}
|
||||
|
||||
if (Button(ICON_MD_TERMINAL)) {
|
||||
show_command_line_interface = !show_command_line_interface;
|
||||
}
|
||||
PopStyleColor();
|
||||
|
||||
Text("%s", absl::StrCat("yaze v", core::kYazeVersion).c_str());
|
||||
|
||||
Text("yaze v%s", core::kYazeVersion.data());
|
||||
EndMenuBar();
|
||||
}
|
||||
|
||||
@@ -424,27 +466,9 @@ void MasterEditor::DrawYazeMenu() {
|
||||
gui::DrawDisplaySettings();
|
||||
End();
|
||||
}
|
||||
|
||||
if (show_command_line_interface) {
|
||||
Begin("Command Line Interface", &show_command_line_interface,
|
||||
ImGuiWindowFlags_None);
|
||||
Text("Enter a command:");
|
||||
End();
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::OpenRomOrProject(const std::string& filename) {
|
||||
if (absl::StrContains(filename, ".yaze")) {
|
||||
status_ = current_project_.Open(filename);
|
||||
if (status_.ok()) {
|
||||
status_ = OpenProject();
|
||||
}
|
||||
} else {
|
||||
status_ = rom()->LoadFromFile(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawFileMenu() {
|
||||
void EditorManager::DrawYazeMenuBar() {
|
||||
static bool save_as_menu = false;
|
||||
static bool new_project_menu = false;
|
||||
|
||||
@@ -476,7 +500,6 @@ void MasterEditor::DrawFileMenu() {
|
||||
MENU_ITEM("Save As..") { save_as_menu = true; }
|
||||
|
||||
if (rom()->is_loaded()) {
|
||||
MENU_ITEM("Reload") { status_ = rom()->Reload(); }
|
||||
MENU_ITEM("Close") {
|
||||
status_ = rom()->Close();
|
||||
rom_assets_loaded_ = false;
|
||||
@@ -492,8 +515,8 @@ void MasterEditor::DrawFileMenu() {
|
||||
}
|
||||
if (MenuItem("Open Project")) {
|
||||
// Open an existing project
|
||||
status_ =
|
||||
current_project_.Open(FileDialogWrapper::ShowOpenFileDialog());
|
||||
status_ = current_project_.Open(
|
||||
core::FileDialogWrapper::ShowOpenFileDialog());
|
||||
if (status_.ok()) {
|
||||
status_ = OpenProject();
|
||||
}
|
||||
@@ -582,9 +605,7 @@ void MasterEditor::DrawFileMenu() {
|
||||
}
|
||||
End();
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawEditMenu() {
|
||||
if (BeginMenu("Edit")) {
|
||||
MENU_ITEM2("Undo", "Ctrl+Z") { status_ = current_editor_->Undo(); }
|
||||
MENU_ITEM2("Redo", "Ctrl+Y") { status_ = current_editor_->Redo(); }
|
||||
@@ -593,12 +614,10 @@ void MasterEditor::DrawEditMenu() {
|
||||
MENU_ITEM2("Copy", "Ctrl+C") { status_ = current_editor_->Copy(); }
|
||||
MENU_ITEM2("Paste", "Ctrl+V") { status_ = current_editor_->Paste(); }
|
||||
Separator();
|
||||
MENU_ITEM2("Find", "Ctrl+F") {}
|
||||
MENU_ITEM2("Find", "Ctrl+F") { status_ = current_editor_->Find(); }
|
||||
EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawViewMenu() {
|
||||
static bool show_imgui_metrics = false;
|
||||
static bool show_memory_editor = false;
|
||||
static bool show_asm_editor = false;
|
||||
@@ -606,28 +625,17 @@ void MasterEditor::DrawViewMenu() {
|
||||
static bool show_palette_editor = false;
|
||||
static bool show_emulator = false;
|
||||
|
||||
if (show_imgui_demo) ShowDemoWindow();
|
||||
if (show_imgui_metrics) ShowMetricsWindow(&show_imgui_metrics);
|
||||
if (show_memory_editor) memory_editor_.Update(show_memory_editor);
|
||||
if (show_asm_editor) assembly_editor_.Update(show_asm_editor);
|
||||
|
||||
if (show_emulator) {
|
||||
Begin("Emulator", &show_emulator, ImGuiWindowFlags_MenuBar);
|
||||
emulator_.Run();
|
||||
End();
|
||||
}
|
||||
|
||||
if (show_imgui_metrics) {
|
||||
ShowMetricsWindow(&show_imgui_metrics);
|
||||
}
|
||||
|
||||
if (show_memory_editor) {
|
||||
memory_editor_.Update(show_memory_editor);
|
||||
}
|
||||
|
||||
if (show_imgui_demo) {
|
||||
ShowDemoWindow();
|
||||
}
|
||||
|
||||
if (show_asm_editor) {
|
||||
assembly_editor_.Update(show_asm_editor);
|
||||
}
|
||||
|
||||
if (show_palette_editor) {
|
||||
Begin("Palette Editor", &show_palette_editor);
|
||||
status_ = palette_editor_.Update();
|
||||
@@ -635,6 +643,7 @@ void MasterEditor::DrawViewMenu() {
|
||||
}
|
||||
|
||||
if (BeginMenu("View")) {
|
||||
MenuItem("Dynamic Layout", nullptr, &dynamic_layout_);
|
||||
MenuItem("Emulator", nullptr, &show_emulator);
|
||||
Separator();
|
||||
MenuItem("Memory Editor", nullptr, &show_memory_editor);
|
||||
@@ -647,23 +656,9 @@ void MasterEditor::DrawViewMenu() {
|
||||
MenuItem("ImGui Metrics", nullptr, &show_imgui_metrics);
|
||||
EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawTestMenu() {
|
||||
static bool show_tests_ = false;
|
||||
|
||||
if (BeginMenu("Tests")) {
|
||||
MenuItem("Run Tests", nullptr, &show_tests_);
|
||||
EndMenu();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MasterEditor::DrawProjectMenu() {
|
||||
static bool show_resource_label_manager = false;
|
||||
|
||||
if (current_project_.project_opened_) {
|
||||
// Project Menu
|
||||
if (BeginMenu("Project")) {
|
||||
Text("Name: %s", current_project_.name.c_str());
|
||||
Text("ROM: %s", current_project_.rom_filename_.c_str());
|
||||
@@ -674,16 +669,7 @@ void MasterEditor::DrawProjectMenu() {
|
||||
EndMenu();
|
||||
}
|
||||
}
|
||||
if (show_resource_label_manager) {
|
||||
rom()->resource_label()->DisplayLabels(&show_resource_label_manager);
|
||||
if (current_project_.project_opened_ &&
|
||||
!current_project_.labels_filename_.empty()) {
|
||||
current_project_.labels_filename_ = rom()->resource_label()->filename_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::DrawHelpMenu() {
|
||||
static bool open_rom_help = false;
|
||||
static bool open_supported_features = false;
|
||||
static bool open_manage_project = false;
|
||||
@@ -752,11 +738,10 @@ void MasterEditor::DrawHelpMenu() {
|
||||
Text("Project Menu");
|
||||
Text("Create a new project or open an existing one.");
|
||||
Text("Save the project to save the current state of the project.");
|
||||
Text(
|
||||
TextWrapped(
|
||||
"To save a project, you need to first open a ROM and initialize your "
|
||||
"code path and labels file. Label resource manager can be found in "
|
||||
"the "
|
||||
"View menu. Code path is set in the Code editor after opening a "
|
||||
"the View menu. Code path is set in the Code editor after opening a "
|
||||
"folder.");
|
||||
|
||||
if (Button("Close", gui::kDefaultModalSize)) {
|
||||
@@ -765,58 +750,51 @@ void MasterEditor::DrawHelpMenu() {
|
||||
}
|
||||
EndPopup();
|
||||
}
|
||||
|
||||
if (show_resource_label_manager) {
|
||||
rom()->resource_label()->DisplayLabels(&show_resource_label_manager);
|
||||
if (current_project_.project_opened_ &&
|
||||
!current_project_.labels_filename_.empty()) {
|
||||
current_project_.labels_filename_ = rom()->resource_label()->filename_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::LoadRom() {
|
||||
if (flags()->kNewFileDialogWrapper) {
|
||||
auto file_name = FileDialogWrapper::ShowOpenFileDialog();
|
||||
PRINT_IF_ERROR(rom()->LoadFromFile(file_name));
|
||||
void EditorManager::LoadRom() {
|
||||
auto file_name = FileDialogWrapper::ShowOpenFileDialog();
|
||||
auto load_rom = rom()->LoadFromFile(file_name);
|
||||
if (load_rom.ok()) {
|
||||
static RecentFilesManager manager("recent_files.txt");
|
||||
manager.Load();
|
||||
manager.AddFile(file_name);
|
||||
manager.Save();
|
||||
} else {
|
||||
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open ROM",
|
||||
".sfc,.smc", ".");
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEditor::SaveRom() {
|
||||
void EditorManager::SaveRom() {
|
||||
if (flags()->kSaveDungeonMaps) {
|
||||
status_ = screen_editor_.SaveDungeonMaps();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldMaps) {
|
||||
RETURN_VOID_IF_ERROR(
|
||||
status_ = overworld_editor_.overworld()->CreateTile32Tilemap());
|
||||
status_ = overworld_editor_.overworld()->SaveMap32Tiles();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
status_ = overworld_editor_.overworld()->SaveMap16Tiles();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
status_ = overworld_editor_.overworld()->SaveOverworldMaps();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldEntrances) {
|
||||
status_ = overworld_editor_.overworld()->SaveEntrances();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldExits) {
|
||||
status_ = overworld_editor_.overworld()->SaveExits();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldItems) {
|
||||
status_ = overworld_editor_.overworld()->SaveItems();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
}
|
||||
if (flags()->overworld.kSaveOverworldProperties) {
|
||||
status_ = overworld_editor_.overworld()->SaveMapProperties();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
}
|
||||
|
||||
status_ = overworld_editor_.Save();
|
||||
RETURN_VOID_IF_ERROR(status_);
|
||||
|
||||
status_ = rom()->SaveToFile(backup_rom_, save_new_auto_);
|
||||
}
|
||||
|
||||
absl::Status MasterEditor::OpenProject() {
|
||||
void EditorManager::OpenRomOrProject(const std::string& filename) {
|
||||
if (absl::StrContains(filename, ".yaze")) {
|
||||
status_ = current_project_.Open(filename);
|
||||
if (status_.ok()) {
|
||||
status_ = OpenProject();
|
||||
}
|
||||
} else {
|
||||
status_ = rom()->LoadFromFile(filename);
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status EditorManager::OpenProject() {
|
||||
RETURN_IF_ERROR(rom()->LoadFromFile(current_project_.rom_filename_));
|
||||
|
||||
if (!rom()->resource_label()->LoadLabels(current_project_.labels_filename_)) {
|
||||
@@ -1,17 +1,9 @@
|
||||
#ifndef YAZE_APP_EDITOR_MASTER_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_MASTER_EDITOR_H
|
||||
#ifndef YAZE_APP_EDITOR_EDITOR_MANAGER_H
|
||||
#define YAZE_APP_EDITOR_EDITOR_MANAGER_H
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
#include "ImGuiColorTextEdit/TextEditor.h"
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/core/project.h"
|
||||
#include "app/editor/code/assembly_editor.h"
|
||||
#include "app/editor/code/memory_editor.h"
|
||||
@@ -21,15 +13,10 @@
|
||||
#include "app/editor/graphics/screen_editor.h"
|
||||
#include "app/editor/message/message_editor.h"
|
||||
#include "app/editor/music/music_editor.h"
|
||||
#include "app/editor/overworld_editor.h"
|
||||
#include "app/editor/settings_editor.h"
|
||||
#include "app/editor/overworld/overworld_editor.h"
|
||||
#include "app/editor/sprite/sprite_editor.h"
|
||||
#include "app/editor/utils/gfx_context.h"
|
||||
#include "app/editor/system/settings_editor.h"
|
||||
#include "app/emu/emulator.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/input.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
@@ -38,28 +25,19 @@ namespace app {
|
||||
namespace editor {
|
||||
|
||||
/**
|
||||
* @class MasterEditor
|
||||
* @brief The MasterEditor class represents the main editor for a Rom in the
|
||||
* Yaze application.
|
||||
* @class EditorManager
|
||||
* @brief The EditorManager controls the main editor window and manages the
|
||||
* various editor classes.
|
||||
*
|
||||
* 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
|
||||
* The EditorManager 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 {
|
||||
class EditorManager : public SharedRom, public core::ExperimentFlags {
|
||||
public:
|
||||
MasterEditor() {
|
||||
EditorManager() {
|
||||
current_editor_ = &overworld_editor_;
|
||||
active_editors_.push_back(&overworld_editor_);
|
||||
active_editors_.push_back(&dungeon_editor_);
|
||||
@@ -67,37 +45,33 @@ class MasterEditor : public SharedRom,
|
||||
active_editors_.push_back(&palette_editor_);
|
||||
active_editors_.push_back(&sprite_editor_);
|
||||
active_editors_.push_back(&message_editor_);
|
||||
active_editors_.push_back(&screen_editor_);
|
||||
}
|
||||
|
||||
void SetupScreen(std::shared_ptr<SDL_Renderer> renderer,
|
||||
std::string filename = "");
|
||||
void SetupScreen(std::string filename = "");
|
||||
absl::Status Update();
|
||||
|
||||
auto emulator() -> emu::Emulator& { return emulator_; }
|
||||
auto emulator() -> emu::Emulator & { return emulator_; }
|
||||
auto quit() { return quit_; }
|
||||
auto overworld_editor() -> OverworldEditor& { return overworld_editor_; }
|
||||
|
||||
private:
|
||||
void ManageActiveEditors();
|
||||
void ManageKeyboardShortcuts();
|
||||
void OpenRomOrProject(const std::string& filename);
|
||||
absl::Status DrawDynamicLayout();
|
||||
|
||||
void ManageKeyboardShortcuts();
|
||||
void InitializeCommands();
|
||||
|
||||
void DrawFileDialog();
|
||||
void DrawStatusPopup();
|
||||
void DrawAboutPopup();
|
||||
void DrawInfoPopup();
|
||||
|
||||
void DrawYazeMenu();
|
||||
void DrawFileMenu();
|
||||
void DrawEditMenu();
|
||||
void DrawViewMenu();
|
||||
void DrawTestMenu();
|
||||
void DrawProjectMenu();
|
||||
void DrawHelpMenu();
|
||||
void DrawYazeMenuBar();
|
||||
|
||||
void LoadRom();
|
||||
void SaveRom();
|
||||
|
||||
void OpenRomOrProject(const std::string &filename);
|
||||
absl::Status OpenProject();
|
||||
|
||||
bool quit_ = false;
|
||||
@@ -107,16 +81,21 @@ class MasterEditor : public SharedRom,
|
||||
bool save_new_auto_ = true;
|
||||
bool show_status_ = false;
|
||||
bool rom_assets_loaded_ = false;
|
||||
bool dynamic_layout_ = false;
|
||||
|
||||
absl::Status status_;
|
||||
absl::Status prev_status_;
|
||||
|
||||
std::shared_ptr<SDL_Renderer> sdl_renderer_;
|
||||
|
||||
emu::Emulator emulator_;
|
||||
|
||||
Project current_project_;
|
||||
std::vector<Editor *> active_editors_;
|
||||
std::vector<EditorLayoutParams> active_layouts_;
|
||||
|
||||
EditorLayoutParams root_layout_;
|
||||
|
||||
Project current_project_;
|
||||
EditorContext editor_context_;
|
||||
|
||||
Editor *current_editor_ = nullptr;
|
||||
AssemblyEditor assembly_editor_;
|
||||
DungeonEditor dungeon_editor_;
|
||||
GraphicsEditor graphics_editor_;
|
||||
@@ -128,14 +107,10 @@ class MasterEditor : public SharedRom,
|
||||
SettingsEditor settings_editor_;
|
||||
MessageEditor message_editor_;
|
||||
MemoryEditorWithDiffChecker memory_editor_;
|
||||
|
||||
ImVector<int> active_tabs_;
|
||||
std::vector<Editor*> active_editors_;
|
||||
Editor* current_editor_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_MASTER_EDITOR_H
|
||||
#endif // YAZE_APP_EDITOR_EDITOR_MANAGER_H
|
||||
@@ -1,22 +1,14 @@
|
||||
#include "gfx_group_editor.h"
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "absl/strings/str_cat.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/color.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -27,7 +19,6 @@ using ImGui::BeginGroup;
|
||||
using ImGui::BeginTabBar;
|
||||
using ImGui::BeginTabItem;
|
||||
using ImGui::BeginTable;
|
||||
using ImGui::ColorButton;
|
||||
using ImGui::EndChild;
|
||||
using ImGui::EndGroup;
|
||||
using ImGui::EndTabBar;
|
||||
@@ -39,7 +30,6 @@ using ImGui::IsItemClicked;
|
||||
using ImGui::PopID;
|
||||
using ImGui::PushID;
|
||||
using ImGui::SameLine;
|
||||
using ImGui::Selectable;
|
||||
using ImGui::Separator;
|
||||
using ImGui::SetNextItemWidth;
|
||||
using ImGui::TableHeadersRow;
|
||||
@@ -123,7 +113,7 @@ void GfxGroupEditor::DrawBlocksetViewer(bool sheet_only) {
|
||||
BeginGroup();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int sheet_id = rom()->main_blockset_ids[selected_blockset_][i];
|
||||
auto sheet = rom()->bitmap_manager()[sheet_id];
|
||||
auto sheet = rom()->gfx_sheets().at(sheet_id);
|
||||
gui::BitmapCanvasPipeline(blockset_canvas_, sheet, 256, 0x10 * 0x04,
|
||||
0x20, true, false, 22);
|
||||
}
|
||||
@@ -176,7 +166,7 @@ void GfxGroupEditor::DrawRoomsetViewer() {
|
||||
BeginGroup();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int sheet_id = rom()->room_blockset_ids[selected_roomset_][i];
|
||||
auto sheet = rom()->bitmap_manager()[sheet_id];
|
||||
auto sheet = rom()->gfx_sheets().at(sheet_id);
|
||||
gui::BitmapCanvasPipeline(roomset_canvas_, sheet, 256, 0x10 * 0x04,
|
||||
0x20, true, false, 23);
|
||||
}
|
||||
@@ -214,7 +204,7 @@ void GfxGroupEditor::DrawSpritesetViewer(bool sheet_only) {
|
||||
BeginGroup();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int sheet_id = rom()->spriteset_ids[selected_spriteset_][i];
|
||||
auto sheet = rom()->bitmap_manager()[115 + sheet_id];
|
||||
auto sheet = rom()->gfx_sheets().at(115 + sheet_id);
|
||||
gui::BitmapCanvasPipeline(spriteset_canvas_, sheet, 256, 0x10 * 0x04,
|
||||
0x20, true, false, 24);
|
||||
}
|
||||
@@ -229,7 +219,7 @@ void DrawPaletteFromPaletteGroup(gfx::SnesPalette &palette) {
|
||||
if (palette.empty()) {
|
||||
return;
|
||||
}
|
||||
for (int n = 0; n < palette.size(); n++) {
|
||||
for (size_t n = 0; n < palette.size(); n++) {
|
||||
PushID(n);
|
||||
if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y);
|
||||
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
#ifndef YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.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/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -40,13 +29,7 @@ class GfxGroupEditor : public SharedRom {
|
||||
selected_spriteset_ = spriteset;
|
||||
}
|
||||
|
||||
void InitBlockset(gfx::Bitmap* tile16_blockset) {
|
||||
tile16_blockset_bmp_ = tile16_blockset;
|
||||
}
|
||||
|
||||
private:
|
||||
int preview_palette_id_ = 0;
|
||||
int last_sheet_id_ = 0;
|
||||
uint8_t selected_blockset_ = 0;
|
||||
uint8_t selected_roomset_ = 0;
|
||||
uint8_t selected_spriteset_ = 0;
|
||||
@@ -57,17 +40,9 @@ class GfxGroupEditor : public SharedRom {
|
||||
gui::Canvas spriteset_canvas_;
|
||||
|
||||
gfx::SnesPalette palette_;
|
||||
gfx::PaletteGroup palette_group_;
|
||||
gfx::Bitmap* tile16_blockset_bmp_;
|
||||
|
||||
std::vector<Bytes> tile16_individual_data_;
|
||||
std::vector<gfx::Bitmap> tile16_individual_;
|
||||
|
||||
gui::BitmapViewer gfx_group_viewer_;
|
||||
zelda3::overworld::Overworld overworld_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
#endif // YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H
|
||||
#endif // YAZE_APP_EDITOR_GFX_GROUP_EDITOR_H
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
#include "graphics_editor.h"
|
||||
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/platform/clipboard.h"
|
||||
#include "app/core/platform/renderer.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/compression.h"
|
||||
#include "app/gfx/scad_format.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gui/asset_browser.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/color.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/modules/asset_browser.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/rom.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
using core::Renderer;
|
||||
|
||||
using gfx::kPaletteGroupAddressesKeys;
|
||||
using ImGui::Button;
|
||||
using ImGui::InputInt;
|
||||
@@ -32,70 +35,56 @@ using ImGui::InputText;
|
||||
using ImGui::SameLine;
|
||||
using ImGui::TableNextColumn;
|
||||
|
||||
static constexpr absl::string_view kGfxToolsetColumnNames[] = {
|
||||
"#memoryEditor",
|
||||
"##separator_gfx1",
|
||||
};
|
||||
|
||||
constexpr ImGuiTableFlags kGfxEditTableFlags =
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
|
||||
ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable |
|
||||
ImGuiTableFlags_SizingFixedFit;
|
||||
|
||||
constexpr ImGuiTabBarFlags kGfxEditTabBarFlags =
|
||||
ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable |
|
||||
ImGuiTabBarFlags_FittingPolicyResizeDown |
|
||||
ImGuiTabBarFlags_TabListPopupButton;
|
||||
|
||||
constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable |
|
||||
ImGuiTableFlags_Resizable |
|
||||
ImGuiTableFlags_SizingStretchSame;
|
||||
|
||||
absl::Status GraphicsEditor::Update() {
|
||||
TAB_BAR("##TabBar")
|
||||
status_ = UpdateGfxEdit();
|
||||
TAB_ITEM("Sheet Browser")
|
||||
if (asset_browser_.Initialized == false) {
|
||||
asset_browser_.Initialize(rom()->mutable_bitmap_manager());
|
||||
if (ImGui::BeginTabBar("##TabBar")) {
|
||||
status_ = UpdateGfxEdit();
|
||||
TAB_ITEM("Sheet Browser")
|
||||
if (asset_browser_.Initialized == false) {
|
||||
asset_browser_.Initialize(rom()->gfx_sheets());
|
||||
}
|
||||
asset_browser_.Draw(rom()->gfx_sheets());
|
||||
END_TAB_ITEM()
|
||||
status_ = UpdateScadView();
|
||||
status_ = UpdateLinkGfxView();
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
asset_browser_.Draw(rom()->mutable_bitmap_manager());
|
||||
|
||||
END_TAB_ITEM()
|
||||
status_ = UpdateScadView();
|
||||
status_ = UpdateLinkGfxView();
|
||||
END_TAB_BAR()
|
||||
CLEAR_AND_RETURN_STATUS(status_)
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::UpdateGfxEdit() {
|
||||
TAB_ITEM("Sheet Editor")
|
||||
if (ImGui::BeginTabItem("Sheet Editor")) {
|
||||
if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags,
|
||||
ImVec2(0, 0))) {
|
||||
for (const auto& name :
|
||||
{"Tilesheets", "Current Graphics", "Palette Controls"})
|
||||
ImGui::TableSetupColumn(name);
|
||||
|
||||
if (ImGui::BeginTable("##GfxEditTable", 3, kGfxEditTableFlags,
|
||||
ImVec2(0, 0))) {
|
||||
for (const auto& name :
|
||||
{"Tilesheets", "Current Graphics", "Palette Controls"})
|
||||
ImGui::TableSetupColumn(name);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
NEXT_COLUMN();
|
||||
status_ = UpdateGfxSheetList();
|
||||
|
||||
NEXT_COLUMN();
|
||||
status_ = UpdateGfxSheetList();
|
||||
NEXT_COLUMN();
|
||||
if (rom()->is_loaded()) {
|
||||
DrawGfxEditToolset();
|
||||
status_ = UpdateGfxTabView();
|
||||
}
|
||||
|
||||
NEXT_COLUMN();
|
||||
if (rom()->is_loaded()) {
|
||||
DrawGfxEditToolset();
|
||||
status_ = UpdateGfxTabView();
|
||||
NEXT_COLUMN();
|
||||
if (rom()->is_loaded()) {
|
||||
status_ = UpdatePaletteColumn();
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
||||
NEXT_COLUMN();
|
||||
if (rom()->is_loaded()) {
|
||||
status_ = UpdatePaletteColumn();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
||||
END_TAB_ITEM()
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -127,8 +116,8 @@ void GraphicsEditor::DrawGfxEditToolset() {
|
||||
TableNextColumn();
|
||||
if (Button(ICON_MD_CONTENT_COPY)) {
|
||||
std::vector<uint8_t> png_data =
|
||||
rom()->bitmap_manager().shared_bitmap(current_sheet_).GetPngData();
|
||||
CopyImageToClipboard(png_data);
|
||||
rom()->gfx_sheets().at(current_sheet_).GetPngData();
|
||||
core::CopyImageToClipboard(png_data);
|
||||
}
|
||||
HOVER_HINT("Copy to Clipboard");
|
||||
|
||||
@@ -136,14 +125,14 @@ void GraphicsEditor::DrawGfxEditToolset() {
|
||||
if (Button(ICON_MD_CONTENT_PASTE)) {
|
||||
std::vector<uint8_t> png_data;
|
||||
int width, height;
|
||||
GetImageFromClipboard(png_data, width, height);
|
||||
core::GetImageFromClipboard(png_data, width, height);
|
||||
if (png_data.size() > 0) {
|
||||
rom()
|
||||
->mutable_bitmap_manager()
|
||||
->mutable_bitmap(current_sheet_)
|
||||
->Create(width, height, 8, png_data);
|
||||
rom()->UpdateBitmap(
|
||||
rom()->mutable_bitmap_manager()->mutable_bitmap(current_sheet_));
|
||||
->mutable_gfx_sheets()
|
||||
->at(current_sheet_)
|
||||
.Create(width, height, 8, png_data);
|
||||
Renderer::GetInstance().UpdateBitmap(
|
||||
&rom()->mutable_gfx_sheets()->at(current_sheet_));
|
||||
}
|
||||
}
|
||||
HOVER_HINT("Paste from Clipboard");
|
||||
@@ -163,7 +152,7 @@ void GraphicsEditor::DrawGfxEditToolset() {
|
||||
}
|
||||
|
||||
TableNextColumn();
|
||||
auto bitmap = rom()->bitmap_manager()[current_sheet_];
|
||||
auto bitmap = rom()->gfx_sheets()[current_sheet_];
|
||||
auto palette = bitmap.palette();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ImGui::SameLine();
|
||||
@@ -192,28 +181,28 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
|
||||
static ImGuiSelectionBasicStorage selection;
|
||||
ImGuiMultiSelectFlags flags =
|
||||
ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
|
||||
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(
|
||||
flags, selection.Size, rom()->bitmap_manager().size());
|
||||
ImGuiMultiSelectIO* ms_io =
|
||||
ImGui::BeginMultiSelect(flags, selection.Size, kNumGfxSheets);
|
||||
selection.ApplyRequests(ms_io);
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(rom()->bitmap_manager().size());
|
||||
clipper.Begin(kNumGfxSheets);
|
||||
if (ms_io->RangeSrcItem != -1)
|
||||
clipper.IncludeItemByIndex(
|
||||
(int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
|
||||
|
||||
for (auto& [key, value] : rom()->bitmap_manager()) {
|
||||
int key = 0;
|
||||
for (auto& value : rom()->gfx_sheets()) {
|
||||
ImGui::BeginChild(absl::StrFormat("##GfxSheet%02X", key).c_str(),
|
||||
ImVec2(0x100 + 1, 0x40 + 1), true,
|
||||
ImGuiWindowFlags_NoDecoration);
|
||||
ImGui::PopStyleVar();
|
||||
gui::Canvas graphics_bin_canvas_;
|
||||
|
||||
graphics_bin_canvas_.DrawBackground(ImVec2(0x100 + 1, 0x40 + 1));
|
||||
graphics_bin_canvas_.DrawContextMenu();
|
||||
if (value.is_active()) {
|
||||
auto texture = value.texture();
|
||||
graphics_bin_canvas_.draw_list()->AddImage(
|
||||
(void*)texture,
|
||||
(ImTextureID)(intptr_t)texture,
|
||||
ImVec2(graphics_bin_canvas_.zero_point().x + 2,
|
||||
graphics_bin_canvas_.zero_point().y + 2),
|
||||
ImVec2(graphics_bin_canvas_.zero_point().x +
|
||||
@@ -240,6 +229,8 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
|
||||
graphics_bin_canvas_.draw_list()->AddText(
|
||||
text_pos, IM_COL32(125, 255, 125, 255),
|
||||
absl::StrFormat("%02X", key).c_str());
|
||||
|
||||
key++;
|
||||
}
|
||||
graphics_bin_canvas_.DrawGrid(16.0f);
|
||||
graphics_bin_canvas_.DrawOverlay();
|
||||
@@ -256,6 +247,10 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
|
||||
|
||||
absl::Status GraphicsEditor::UpdateGfxTabView() {
|
||||
static int next_tab_id = 0;
|
||||
constexpr ImGuiTabBarFlags kGfxEditTabBarFlags =
|
||||
ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable |
|
||||
ImGuiTabBarFlags_FittingPolicyResizeDown |
|
||||
ImGuiTabBarFlags_TabListPopupButton;
|
||||
|
||||
if (ImGui::BeginTabBar("##GfxEditTabBar", kGfxEditTabBarFlags)) {
|
||||
if (ImGui::TabItemButton(ICON_MD_ADD, ImGuiTabItemFlags_Trailing |
|
||||
@@ -285,18 +280,17 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar |
|
||||
ImGuiWindowFlags_AlwaysHorizontalScrollbar);
|
||||
|
||||
gfx::Bitmap& current_bitmap =
|
||||
*rom()->mutable_bitmap_manager()->mutable_bitmap(sheet_id);
|
||||
gfx::Bitmap& current_bitmap = rom()->mutable_gfx_sheets()->at(sheet_id);
|
||||
|
||||
auto draw_tile_event = [&]() {
|
||||
current_sheet_canvas_.DrawTileOnBitmap(tile_size_, ¤t_bitmap,
|
||||
current_color_);
|
||||
rom()->UpdateBitmap(¤t_bitmap, true);
|
||||
Renderer::GetInstance().UpdateBitmap(¤t_bitmap);
|
||||
};
|
||||
|
||||
current_sheet_canvas_.UpdateColorPainter(
|
||||
rom()->bitmap_manager()[sheet_id], current_color_, draw_tile_event,
|
||||
tile_size_, current_scale_);
|
||||
rom()->mutable_gfx_sheets()->at(sheet_id), current_color_,
|
||||
draw_tile_event, tile_size_, current_scale_);
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::EndTabItem();
|
||||
@@ -328,7 +322,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
|
||||
current_sheet_ = id;
|
||||
// ImVec2(0x100, 0x40),
|
||||
current_sheet_canvas_.UpdateColorPainter(
|
||||
rom()->bitmap_manager()[id], current_color_,
|
||||
rom()->mutable_gfx_sheets()->at(id), current_color_,
|
||||
[&]() {
|
||||
|
||||
},
|
||||
@@ -365,11 +359,12 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
|
||||
|
||||
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_),
|
||||
true);
|
||||
rom()
|
||||
->mutable_gfx_sheets()
|
||||
->data()[current_sheet_]
|
||||
.ApplyPaletteWithTransparent(palette, edit_palette_sub_index_));
|
||||
Renderer::GetInstance().UpdateBitmap(
|
||||
&rom()->mutable_gfx_sheets()->data()[current_sheet_]);
|
||||
refresh_graphics_ = false;
|
||||
}
|
||||
}
|
||||
@@ -391,9 +386,9 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() {
|
||||
link_canvas_.DrawGrid(16.0f);
|
||||
|
||||
int i = 0;
|
||||
for (auto [key, link_sheet] : *rom()->mutable_link_graphics()) {
|
||||
for (auto link_sheet : *rom()->mutable_link_graphics()) {
|
||||
int x_offset = 0;
|
||||
int y_offset = core::kTilesheetHeight * i * 4;
|
||||
int y_offset = gfx::kTilesheetHeight * i * 4;
|
||||
link_canvas_.DrawContextMenu(&link_sheet);
|
||||
link_canvas_.DrawBitmap(link_sheet, x_offset, y_offset, 4);
|
||||
i++;
|
||||
@@ -435,6 +430,10 @@ absl::Status GraphicsEditor::UpdateScadView() {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable |
|
||||
ImGuiTableFlags_Resizable |
|
||||
ImGuiTableFlags_SizingStretchSame;
|
||||
|
||||
BEGIN_TABLE("#gfxEditTable", 4, kGfxEditFlags)
|
||||
SETUP_COLUMN("File Import (BIN, CGX, ROM)")
|
||||
SETUP_COLUMN("Palette (COL)")
|
||||
@@ -458,17 +457,18 @@ absl::Status GraphicsEditor::UpdateScadView() {
|
||||
|
||||
NEXT_COLUMN()
|
||||
if (super_donkey_) {
|
||||
if (refresh_graphics_) {
|
||||
for (int i = 0; i < graphics_bin_.size(); i++) {
|
||||
status_ = graphics_bin_[i].ApplyPalette(
|
||||
col_file_palette_group_[current_palette_index_]);
|
||||
rom()->UpdateBitmap(&graphics_bin_[i]);
|
||||
}
|
||||
refresh_graphics_ = false;
|
||||
}
|
||||
// TODO: Implement the Super Donkey 1 graphics decompression
|
||||
// if (refresh_graphics_) {
|
||||
// for (int i = 0; i < kNumGfxSheets; i++) {
|
||||
// status_ = graphics_bin_[i].ApplyPalette(
|
||||
// col_file_palette_group_[current_palette_index_]);
|
||||
// Renderer::GetInstance().UpdateBitmap(&graphics_bin_[i]);
|
||||
// }
|
||||
// refresh_graphics_ = false;
|
||||
// }
|
||||
// Load the full graphics space from `super_donkey_1.bin`
|
||||
gui::GraphicsBinCanvasPipeline(0x100, 0x40, 0x20, num_sheets_to_load_, 3,
|
||||
super_donkey_, graphics_bin_);
|
||||
// gui::GraphicsBinCanvasPipeline(0x100, 0x40, 0x20, num_sheets_to_load_, 3,
|
||||
// super_donkey_, graphics_bin_);
|
||||
} else if (cgx_loaded_ && col_file_) {
|
||||
// Load the CGX graphics
|
||||
gui::BitmapCanvasPipeline(import_canvas_, cgx_bitmap_, 0x100, 16384, 0x20,
|
||||
@@ -485,6 +485,11 @@ absl::Status GraphicsEditor::UpdateScadView() {
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::DrawToolset() {
|
||||
static constexpr absl::string_view kGfxToolsetColumnNames[] = {
|
||||
"#memoryEditor",
|
||||
"##separator_gfx1",
|
||||
};
|
||||
|
||||
if (ImGui::BeginTable("GraphicsToolset", 2, ImGuiTableFlags_SizingFixedFit,
|
||||
ImVec2(0, 0))) {
|
||||
for (const auto& name : kGfxToolsetColumnNames)
|
||||
@@ -535,7 +540,7 @@ absl::Status GraphicsEditor::DrawCgxImport() {
|
||||
cgx_bitmap_.Create(0x80, 0x200, 8, decoded_cgx_);
|
||||
if (col_file_) {
|
||||
cgx_bitmap_.ApplyPalette(decoded_col_);
|
||||
rom()->RenderBitmap(&cgx_bitmap_);
|
||||
Renderer::GetInstance().RenderBitmap(&cgx_bitmap_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,7 +575,7 @@ absl::Status GraphicsEditor::DrawScrImport() {
|
||||
scr_bitmap_.Create(0x100, 0x100, 8, decoded_scr_data_);
|
||||
if (scr_loaded_) {
|
||||
scr_bitmap_.ApplyPalette(decoded_col_);
|
||||
rom()->RenderBitmap(&scr_bitmap_);
|
||||
Renderer::GetInstance().RenderBitmap(&scr_bitmap_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,7 +599,7 @@ absl::Status GraphicsEditor::DrawPaletteControls() {
|
||||
/*z3_load=*/false);
|
||||
auto col_data_ = gfx::GetColFileData(temp_rom_.data());
|
||||
if (col_file_palette_group_.size() != 0) {
|
||||
col_file_palette_group_.Clear();
|
||||
col_file_palette_group_.clear();
|
||||
}
|
||||
auto col_file_palette_group_status =
|
||||
gfx::CreatePaletteGroupFromColFile(col_data_);
|
||||
@@ -707,7 +712,8 @@ absl::Status GraphicsEditor::DrawClipboardImport() {
|
||||
if (Button("Paste From Clipboard")) {
|
||||
const char* text = ImGui::GetClipboardText();
|
||||
if (text) {
|
||||
const auto clipboard_data = Bytes(text, text + strlen(text));
|
||||
const auto clipboard_data =
|
||||
std::vector<uint8_t>(text, text + strlen(text));
|
||||
ImGui::MemFree((void*)text);
|
||||
status_ = temp_rom_.LoadFromBytes(clipboard_data);
|
||||
is_open_ = true;
|
||||
@@ -762,7 +768,7 @@ absl::Status GraphicsEditor::DecompressImportData(int size) {
|
||||
temp_rom_.data(), current_offset_, size))
|
||||
|
||||
auto converted_sheet = gfx::SnesTo8bppSheet(import_data_, 3);
|
||||
bin_bitmap_.Create(core::kTilesheetWidth, 0x2000, core::kTilesheetDepth,
|
||||
bin_bitmap_.Create(gfx::kTilesheetWidth, 0x2000, gfx::kTilesheetDepth,
|
||||
converted_sheet);
|
||||
|
||||
if (rom()->is_loaded()) {
|
||||
@@ -775,7 +781,7 @@ absl::Status GraphicsEditor::DecompressImportData(int size) {
|
||||
}
|
||||
}
|
||||
|
||||
rom()->RenderBitmap(&bin_bitmap_);
|
||||
Renderer::GetInstance().RenderBitmap(&bin_bitmap_);
|
||||
gfx_loaded_ = true;
|
||||
|
||||
return absl::OkStatus();
|
||||
@@ -790,11 +796,10 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
|
||||
auto decompressed_data,
|
||||
gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000))
|
||||
auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3);
|
||||
graphics_bin_[i] =
|
||||
gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight,
|
||||
core::kTilesheetDepth, converted_sheet);
|
||||
gfx_sheets_[i] = gfx::Bitmap(gfx::kTilesheetWidth, gfx::kTilesheetHeight,
|
||||
gfx::kTilesheetDepth, converted_sheet);
|
||||
if (col_file_) {
|
||||
status_ = graphics_bin_[i].ApplyPalette(
|
||||
status_ = gfx_sheets_[i].ApplyPalette(
|
||||
col_file_palette_group_[current_palette_index_]);
|
||||
} else {
|
||||
// ROM palette
|
||||
@@ -802,10 +807,10 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
|
||||
auto palette_group = rom()->palette_group().get_group(
|
||||
kPaletteGroupAddressesKeys[current_palette_]);
|
||||
z3_rom_palette_ = *palette_group->mutable_palette(current_palette_index_);
|
||||
status_ = graphics_bin_[i].ApplyPalette(z3_rom_palette_);
|
||||
status_ = gfx_sheets_[i].ApplyPalette(z3_rom_palette_);
|
||||
}
|
||||
|
||||
rom()->RenderBitmap(&graphics_bin_[i]);
|
||||
Renderer::GetInstance().RenderBitmap(&gfx_sheets_[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -816,21 +821,20 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
|
||||
auto decompressed_data,
|
||||
gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000))
|
||||
auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3);
|
||||
graphics_bin_[i] =
|
||||
gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight,
|
||||
core::kTilesheetDepth, converted_sheet);
|
||||
gfx_sheets_[i] = gfx::Bitmap(gfx::kTilesheetWidth, gfx::kTilesheetHeight,
|
||||
gfx::kTilesheetDepth, converted_sheet);
|
||||
if (col_file_) {
|
||||
status_ = graphics_bin_[i].ApplyPalette(
|
||||
status_ = gfx_sheets_[i].ApplyPalette(
|
||||
col_file_palette_group_[current_palette_index_]);
|
||||
} else {
|
||||
// ROM palette
|
||||
auto palette_group = rom()->palette_group().get_group(
|
||||
kPaletteGroupAddressesKeys[current_palette_]);
|
||||
z3_rom_palette_ = *palette_group->mutable_palette(current_palette_index_);
|
||||
status_ = graphics_bin_[i].ApplyPalette(z3_rom_palette_);
|
||||
status_ = gfx_sheets_[i].ApplyPalette(z3_rom_palette_);
|
||||
}
|
||||
|
||||
rom()->RenderBitmap(&graphics_bin_[i]);
|
||||
Renderer::GetInstance().RenderBitmap(&gfx_sheets_[i]);
|
||||
i++;
|
||||
}
|
||||
super_donkey_ = true;
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
#ifndef YAZE_APP_EDITOR_GRAPHICS_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_GRAPHICS_EDITOR_H
|
||||
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
#include <stack>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gui/asset_browser.h"
|
||||
#include "app/gui/modules/asset_browser.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -167,8 +164,8 @@ class GraphicsEditor : public SharedRom, public Editor {
|
||||
MemoryEditor cgx_memory_editor_;
|
||||
MemoryEditor col_memory_editor_;
|
||||
PaletteEditor palette_editor_;
|
||||
Bytes import_data_;
|
||||
Bytes graphics_buffer_;
|
||||
std::vector<uint8_t> import_data_;
|
||||
std::vector<uint8_t> graphics_buffer_;
|
||||
std::vector<uint8_t> decoded_cgx_;
|
||||
std::vector<uint8_t> cgx_data_;
|
||||
std::vector<uint8_t> extra_cgx_data_;
|
||||
@@ -179,9 +176,8 @@ class GraphicsEditor : public SharedRom, public Editor {
|
||||
gfx::Bitmap scr_bitmap_;
|
||||
gfx::Bitmap bin_bitmap_;
|
||||
gfx::Bitmap link_full_sheet_;
|
||||
gfx::BitmapTable graphics_bin_;
|
||||
gfx::BitmapTable clipboard_graphics_bin_;
|
||||
gfx::BitmapTable link_graphics_;
|
||||
std::array<gfx::Bitmap, kNumGfxSheets> gfx_sheets_;
|
||||
|
||||
gfx::PaletteGroup col_file_palette_group_;
|
||||
gfx::SnesPalette z3_rom_palette_;
|
||||
gfx::SnesPalette col_file_palette_;
|
||||
@@ -189,11 +185,12 @@ class GraphicsEditor : public SharedRom, public Editor {
|
||||
gui::Canvas import_canvas_;
|
||||
gui::Canvas scr_canvas_;
|
||||
gui::Canvas super_donkey_canvas_;
|
||||
gui::Canvas graphics_bin_canvas_;
|
||||
gui::Canvas current_sheet_canvas_{"CurrentSheetCanvas", ImVec2(0x80, 0x20),
|
||||
gui::CanvasGridSize::k8x8};
|
||||
gui::Canvas link_canvas_{
|
||||
"LinkCanvas",
|
||||
ImVec2(core::kTilesheetWidth * 4, core::kTilesheetHeight * 0x10 * 4),
|
||||
ImVec2(gfx::kTilesheetWidth * 4, gfx::kTilesheetHeight * 0x10 * 4),
|
||||
gui::CanvasGridSize::k16x16};
|
||||
absl::Status status_;
|
||||
};
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#include "palette_editor.h"
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/color.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -86,6 +84,93 @@ static inline float color_saturate(float f) {
|
||||
0.5f)) // Saturated, always output 0..255
|
||||
} // namespace
|
||||
|
||||
absl::Status DisplayPalette(gfx::SnesPalette& palette, bool loaded) {
|
||||
static ImVec4 color = ImVec4(0, 0, 0, 255.f);
|
||||
static ImVec4 current_palette[256] = {};
|
||||
ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
|
||||
ImGuiColorEditFlags_NoDragDrop |
|
||||
ImGuiColorEditFlags_NoOptions;
|
||||
|
||||
// Generate a default palette. The palette will persist and can be edited.
|
||||
static bool init = false;
|
||||
if (loaded && !init) {
|
||||
for (int n = 0; n < palette.size(); n++) {
|
||||
ASSIGN_OR_RETURN(auto color, palette.GetColor(n));
|
||||
current_palette[n].x = color.rgb().x / 255;
|
||||
current_palette[n].y = color.rgb().y / 255;
|
||||
current_palette[n].z = color.rgb().z / 255;
|
||||
current_palette[n].w = 255; // Alpha
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
|
||||
static ImVec4 backup_color;
|
||||
bool open_popup = ColorButton("MyColor##3b", color, misc_flags);
|
||||
SameLine(0, GetStyle().ItemInnerSpacing.x);
|
||||
open_popup |= Button("Palette");
|
||||
if (open_popup) {
|
||||
OpenPopup("mypicker");
|
||||
backup_color = color;
|
||||
}
|
||||
|
||||
if (BeginPopup("mypicker")) {
|
||||
TEXT_WITH_SEPARATOR("Current Overworld Palette");
|
||||
ColorPicker4("##picker", (float*)&color,
|
||||
misc_flags | ImGuiColorEditFlags_NoSidePreview |
|
||||
ImGuiColorEditFlags_NoSmallPreview);
|
||||
SameLine();
|
||||
|
||||
BeginGroup(); // Lock X position
|
||||
Text("Current ==>");
|
||||
SameLine();
|
||||
Text("Previous");
|
||||
|
||||
if (Button("Update Map Palette")) {
|
||||
}
|
||||
|
||||
ColorButton(
|
||||
"##current", color,
|
||||
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
|
||||
ImVec2(60, 40));
|
||||
SameLine();
|
||||
|
||||
if (ColorButton(
|
||||
"##previous", backup_color,
|
||||
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
|
||||
ImVec2(60, 40)))
|
||||
color = backup_color;
|
||||
|
||||
// List of Colors in Overworld Palette
|
||||
Separator();
|
||||
Text("Palette");
|
||||
for (int n = 0; n < IM_ARRAYSIZE(current_palette); n++) {
|
||||
PushID(n);
|
||||
if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y);
|
||||
|
||||
if (ColorButton("##palette", current_palette[n], kPalButtonFlags2,
|
||||
ImVec2(20, 20)))
|
||||
color = ImVec4(current_palette[n].x, current_palette[n].y,
|
||||
current_palette[n].z, color.w); // Preserve alpha!
|
||||
|
||||
if (BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload =
|
||||
AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
|
||||
memcpy((float*)¤t_palette[n], payload->Data, sizeof(float) * 3);
|
||||
if (const ImGuiPayload* payload =
|
||||
AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
|
||||
memcpy((float*)¤t_palette[n], payload->Data, sizeof(float) * 4);
|
||||
EndDragDropTarget();
|
||||
}
|
||||
|
||||
PopID();
|
||||
}
|
||||
EndGroup();
|
||||
EndPopup();
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status PaletteEditor::Update() {
|
||||
if (rom()->is_loaded()) {
|
||||
// Initialize the labels
|
||||
@@ -348,7 +433,7 @@ absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i,
|
||||
|
||||
// SNES Format
|
||||
CustomFormatString(buf, IM_ARRAYSIZE(buf), "$%04X",
|
||||
ConvertRGBtoSNES(ImVec4(col[0], col[1], col[2], 1.0f)));
|
||||
ConvertRgbToSnes(ImVec4(col[0], col[1], col[2], 1.0f)));
|
||||
if (Selectable(buf)) SetClipboardText(buf);
|
||||
|
||||
EndPopup();
|
||||
@@ -358,84 +443,6 @@ absl::Status PaletteEditor::HandleColorPopup(gfx::SnesPalette& palette, int i,
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void PaletteEditor::DisplayPalette(gfx::SnesPalette& palette, bool loaded) {
|
||||
static ImVec4 color = ImVec4(0, 0, 0, 255.f);
|
||||
ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
|
||||
ImGuiColorEditFlags_NoDragDrop |
|
||||
ImGuiColorEditFlags_NoOptions;
|
||||
|
||||
// Generate a default palette. The palette will persist and can be edited.
|
||||
static bool init = false;
|
||||
if (loaded && !init) {
|
||||
status_ = InitializeSavedPalette(palette);
|
||||
init = true;
|
||||
}
|
||||
|
||||
static ImVec4 backup_color;
|
||||
bool open_popup = ColorButton("MyColor##3b", color, misc_flags);
|
||||
SameLine(0, GetStyle().ItemInnerSpacing.x);
|
||||
open_popup |= Button("Palette");
|
||||
if (open_popup) {
|
||||
OpenPopup("mypicker");
|
||||
backup_color = color;
|
||||
}
|
||||
|
||||
if (BeginPopup("mypicker")) {
|
||||
TEXT_WITH_SEPARATOR("Current Overworld Palette");
|
||||
ColorPicker4("##picker", (float*)&color,
|
||||
misc_flags | ImGuiColorEditFlags_NoSidePreview |
|
||||
ImGuiColorEditFlags_NoSmallPreview);
|
||||
SameLine();
|
||||
|
||||
BeginGroup(); // Lock X position
|
||||
Text("Current ==>");
|
||||
SameLine();
|
||||
Text("Previous");
|
||||
|
||||
if (Button("Update Map Palette")) {
|
||||
}
|
||||
|
||||
ColorButton(
|
||||
"##current", color,
|
||||
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
|
||||
ImVec2(60, 40));
|
||||
SameLine();
|
||||
|
||||
if (ColorButton(
|
||||
"##previous", backup_color,
|
||||
ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
|
||||
ImVec2(60, 40)))
|
||||
color = backup_color;
|
||||
|
||||
// List of Colors in Overworld Palette
|
||||
Separator();
|
||||
Text("Palette");
|
||||
for (int n = 0; n < IM_ARRAYSIZE(saved_palette_); n++) {
|
||||
PushID(n);
|
||||
if ((n % 8) != 0) SameLine(0.0f, GetStyle().ItemSpacing.y);
|
||||
|
||||
if (ColorButton("##palette", saved_palette_[n], kPalButtonFlags2,
|
||||
ImVec2(20, 20)))
|
||||
color = ImVec4(saved_palette_[n].x, saved_palette_[n].y,
|
||||
saved_palette_[n].z, color.w); // Preserve alpha!
|
||||
|
||||
if (BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload* payload =
|
||||
AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
|
||||
memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 3);
|
||||
if (const ImGuiPayload* payload =
|
||||
AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
|
||||
memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 4);
|
||||
EndDragDropTarget();
|
||||
}
|
||||
|
||||
PopID();
|
||||
}
|
||||
EndGroup();
|
||||
EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status PaletteEditor::EditColorInPalette(gfx::SnesPalette& palette,
|
||||
int index) {
|
||||
if (index >= palette.size()) {
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
#ifndef YAZE_APP_EDITOR_PALETTE_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_PALETTE_EDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/editor/graphics/gfx_group_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gfx/snes_color.h"
|
||||
#include "app/rom.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -26,56 +28,51 @@ struct PaletteChange {
|
||||
|
||||
class PaletteEditorHistory {
|
||||
public:
|
||||
// Record a change in the palette editor
|
||||
void RecordChange(const std::string& groupName, size_t paletteIndex,
|
||||
size_t colorIndex, const gfx::SnesColor& originalColor,
|
||||
const gfx::SnesColor& newColor) {
|
||||
// Check size and remove the oldest if necessary
|
||||
if (recentChanges.size() >= maxHistorySize) {
|
||||
recentChanges.pop_front();
|
||||
void RecordChange(const std::string& group_name, size_t palette_index,
|
||||
size_t color_index, const gfx::SnesColor& original_color,
|
||||
const gfx::SnesColor& new_color) {
|
||||
if (recent_changes_.size() >= kMaxHistorySize) {
|
||||
recent_changes_.pop_front();
|
||||
}
|
||||
|
||||
// Push the new change
|
||||
recentChanges.push_back(
|
||||
{groupName, paletteIndex, colorIndex, originalColor, newColor});
|
||||
recent_changes_.push_back(
|
||||
{group_name, palette_index, color_index, original_color, new_color});
|
||||
}
|
||||
|
||||
// Get recent changes for display in the palette editor
|
||||
const std::deque<PaletteChange>& GetRecentChanges() const {
|
||||
return recentChanges;
|
||||
}
|
||||
|
||||
// Restore the original color
|
||||
gfx::SnesColor RestoreOriginalColor(const std::string& groupName,
|
||||
size_t paletteIndex,
|
||||
size_t colorIndex) const {
|
||||
for (const auto& change : recentChanges) {
|
||||
if (change.group_name == groupName &&
|
||||
change.palette_index == paletteIndex &&
|
||||
change.color_index == colorIndex) {
|
||||
gfx::SnesColor RestoreOriginalColor(const std::string& group_name,
|
||||
size_t palette_index,
|
||||
size_t color_index) const {
|
||||
for (const auto& change : recent_changes_) {
|
||||
if (change.group_name == group_name &&
|
||||
change.palette_index == palette_index &&
|
||||
change.color_index == color_index) {
|
||||
return change.original_color;
|
||||
}
|
||||
}
|
||||
// Handle error or return default (this is just an example,
|
||||
// handle as appropriate for your application)
|
||||
return gfx::SnesColor();
|
||||
}
|
||||
|
||||
auto size() const { return recentChanges.size(); }
|
||||
auto size() const { return recent_changes_.size(); }
|
||||
|
||||
gfx::SnesColor& GetModifiedColor(size_t index) {
|
||||
return recentChanges[index].new_color;
|
||||
return recent_changes_[index].new_color;
|
||||
}
|
||||
gfx::SnesColor& GetOriginalColor(size_t index) {
|
||||
return recentChanges[index].original_color;
|
||||
return recent_changes_[index].original_color;
|
||||
}
|
||||
|
||||
const std::deque<PaletteChange>& GetRecentChanges() const {
|
||||
return recent_changes_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::deque<PaletteChange> recentChanges;
|
||||
static const size_t maxHistorySize = 50; // or any other number you deem fit
|
||||
std::deque<PaletteChange> recent_changes_;
|
||||
static const size_t kMaxHistorySize = 50;
|
||||
};
|
||||
} // namespace palette_internal
|
||||
|
||||
absl::Status DisplayPalette(gfx::SnesPalette& palette, bool loaded);
|
||||
|
||||
/**
|
||||
* @class PaletteEditor
|
||||
* @brief Allows the user to view and edit in game palettes.
|
||||
@@ -101,7 +98,6 @@ class PaletteEditor : public SharedRom, public Editor {
|
||||
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);
|
||||
absl::Status DrawPaletteGroup(int category, bool right_side = false);
|
||||
|
||||
void DrawCustomPalette();
|
||||
@@ -110,16 +106,6 @@ class PaletteEditor : public SharedRom, public Editor {
|
||||
|
||||
private:
|
||||
absl::Status HandleColorPopup(gfx::SnesPalette& palette, int i, int j, int n);
|
||||
absl::Status InitializeSavedPalette(const gfx::SnesPalette& palette) {
|
||||
for (int n = 0; n < palette.size(); n++) {
|
||||
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_;
|
||||
gfx::SnesColor current_color_;
|
||||
@@ -137,4 +123,4 @@ class PaletteEditor : public SharedRom, public Editor {
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,44 +1,45 @@
|
||||
#include "screen_editor.h"
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/core/platform/file_dialog.h"
|
||||
#include "app/core/platform/renderer.h"
|
||||
#include "app/gfx/bitmap.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"
|
||||
#include "app/zelda3/dungeon/room.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
absl::Status ScreenEditor::Update() {
|
||||
TAB_BAR("##TabBar")
|
||||
TAB_ITEM("Dungeon Maps")
|
||||
if (rom()->is_loaded()) {
|
||||
DrawDungeonMapsEditor();
|
||||
}
|
||||
END_TAB_ITEM()
|
||||
DrawInventoryMenuEditor();
|
||||
DrawOverworldMapEditor();
|
||||
DrawTitleScreenEditor();
|
||||
DrawNamingScreenEditor();
|
||||
END_TAB_BAR()
|
||||
using core::Renderer;
|
||||
|
||||
return absl::OkStatus();
|
||||
constexpr uint32_t kRedPen = 0xFF0000FF;
|
||||
|
||||
absl::Status ScreenEditor::Update() {
|
||||
if (ImGui::BeginTabBar("##ScreenEditorTabBar")) {
|
||||
if (ImGui::BeginTabItem("Dungeon Maps")) {
|
||||
if (rom()->is_loaded()) {
|
||||
DrawDungeonMapsEditor();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
DrawInventoryMenuEditor();
|
||||
DrawOverworldMapEditor();
|
||||
DrawTitleScreenEditor();
|
||||
DrawNamingScreenEditor();
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
return status_;
|
||||
}
|
||||
|
||||
void ScreenEditor::DrawInventoryMenuEditor() {
|
||||
@@ -121,16 +122,16 @@ absl::Status ScreenEditor::LoadDungeonMaps() {
|
||||
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
|
||||
int ptr_gfx,
|
||||
rom()->ReadWord(zelda3::screen::kDungeonMapGfxPtr + (d * 2)));
|
||||
ptr |= 0x0A0000; // Add bank to the short ptr
|
||||
ptr_gfx |= 0x0A0000; // Add bank to the short ptr
|
||||
int pc_ptr = core::SnesToPc(ptr); // Contains data for the next 25 rooms
|
||||
int pc_ptr_gfx =
|
||||
core::SnesToPc(ptr_gfx); // Contains data for the next 25 rooms
|
||||
|
||||
ASSIGN_OR_RETURN(
|
||||
ushort bossRoomD,
|
||||
ushort boss_room_d,
|
||||
rom()->ReadWord(zelda3::screen::kDungeonMapBossRooms + (d * 2)));
|
||||
|
||||
ASSIGN_OR_RETURN(
|
||||
@@ -157,14 +158,13 @@ absl::Status ScreenEditor::LoadDungeonMaps() {
|
||||
|
||||
// for each room on the floor
|
||||
for (int j = 0; j < 25; j++) {
|
||||
// rdata[j] = 0x0F;
|
||||
gdata[j] = 0xFF;
|
||||
rdata[j] = rom()->data()[pcPtr + j + (i * 25)]; // Set the rooms
|
||||
rdata[j] = rom()->data()[pc_ptr + j + (i * 25)]; // Set the rooms
|
||||
|
||||
if (rdata[j] == 0x0F) {
|
||||
gdata[j] = 0xFF;
|
||||
} else {
|
||||
gdata[j] = rom()->data()[pcPtrGFX++];
|
||||
gdata[j] = rom()->data()[pc_ptr_gfx++];
|
||||
}
|
||||
|
||||
std::string label = core::UppercaseHexByte(rdata[j]);
|
||||
@@ -175,7 +175,7 @@ absl::Status ScreenEditor::LoadDungeonMaps() {
|
||||
current_floor_rooms_d.push_back(rdata); // Add new floor data
|
||||
}
|
||||
|
||||
dungeon_maps_.emplace_back(bossRoomD, nbr_floor_d, nbr_basement_d,
|
||||
dungeon_maps_.emplace_back(boss_room_d, nbr_floor_d, nbr_basement_d,
|
||||
current_floor_rooms_d, current_floor_gfx_d);
|
||||
}
|
||||
|
||||
@@ -185,23 +185,19 @@ absl::Status ScreenEditor::LoadDungeonMaps() {
|
||||
absl::Status ScreenEditor::SaveDungeonMaps() {
|
||||
for (int d = 0; d < 14; d++) {
|
||||
int ptr = zelda3::screen::kDungeonMapRoomsPtr + (d * 2);
|
||||
int ptrGFX = zelda3::screen::kDungeonMapGfxPtr + (d * 2);
|
||||
int pcPtr = core::SnesToPc(ptr);
|
||||
int pcPtrGFX = core::SnesToPc(ptrGFX);
|
||||
int ptr_gfx = zelda3::screen::kDungeonMapGfxPtr + (d * 2);
|
||||
int pc_ptr = core::SnesToPc(ptr);
|
||||
int pc_ptr_gfx = core::SnesToPc(ptr_gfx);
|
||||
|
||||
const int nbr_floors = dungeon_maps_[d].nbr_of_floor;
|
||||
const int nbr_basements = dungeon_maps_[d].nbr_of_basement;
|
||||
for (int i = 0; i < nbr_floors + nbr_basements; i++) {
|
||||
for (int j = 0; j < 25; j++) {
|
||||
// rom()->data()[pcPtr + j + (i * 25)] =
|
||||
// dungeon_maps_[d].floor_rooms[i][j];
|
||||
// rom()->data()[pcPtrGFX++] = dungeon_maps_[d].floor_gfx[i][j];
|
||||
|
||||
RETURN_IF_ERROR(rom()->WriteByte(ptr + j + (i * 25),
|
||||
RETURN_IF_ERROR(rom()->WriteByte(pc_ptr + j + (i * 25),
|
||||
dungeon_maps_[d].floor_rooms[i][j]));
|
||||
RETURN_IF_ERROR(rom()->WriteByte(ptrGFX + j + (i * 25),
|
||||
RETURN_IF_ERROR(rom()->WriteByte(pc_ptr_gfx + j + (i * 25),
|
||||
dungeon_maps_[d].floor_gfx[i][j]));
|
||||
pcPtrGFX++;
|
||||
pc_ptr_gfx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,7 +205,8 @@ absl::Status ScreenEditor::SaveDungeonMaps() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ScreenEditor::LoadDungeonMapTile16() {
|
||||
absl::Status ScreenEditor::LoadDungeonMapTile16(
|
||||
const std::vector<uint8_t>& gfx_data, bool bin_mode) {
|
||||
tile16_sheet_.Init(256, 192, gfx::TileType::Tile16);
|
||||
|
||||
for (int i = 0; i < 186; i++) {
|
||||
@@ -230,69 +227,99 @@ absl::Status ScreenEditor::LoadDungeonMapTile16() {
|
||||
ASSIGN_OR_RETURN(auto br, rom()->ReadWord(addr + 6 + (i * 8)));
|
||||
gfx::TileInfo t4 = gfx::WordToTileInfo(br); // Bottom right
|
||||
|
||||
tile16_sheet_.ComposeTile16(rom()->graphics_buffer(), t1, t2, t3, t4);
|
||||
int sheet_offset = 212;
|
||||
if (bin_mode) {
|
||||
sheet_offset = 0;
|
||||
}
|
||||
tile16_sheet_.ComposeTile16(gfx_data, t1, t2, t3, t4, sheet_offset);
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(tile16_sheet_.mutable_bitmap()->ApplyPalette(
|
||||
*rom()->mutable_dungeon_palette(3)));
|
||||
rom()->RenderBitmap(&*tile16_sheet_.mutable_bitmap().get());
|
||||
Renderer::GetInstance().RenderBitmap(&*tile16_sheet_.mutable_bitmap().get());
|
||||
|
||||
for (int i = 0; i < tile16_sheet_.num_tiles(); ++i) {
|
||||
if (tile16_individual_.count(i) == 0) {
|
||||
auto tile = tile16_sheet_.GetTile16(i);
|
||||
tile16_individual_[i] = tile;
|
||||
rom()->RenderBitmap(&tile16_individual_[i]);
|
||||
}
|
||||
auto tile = tile16_sheet_.GetTile16(i);
|
||||
tile16_individual_[i] = tile;
|
||||
RETURN_IF_ERROR(
|
||||
tile16_individual_[i].ApplyPalette(*rom()->mutable_dungeon_palette(3)));
|
||||
Renderer::GetInstance().RenderBitmap(&tile16_individual_[i]);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ScreenEditor::SaveDungeonMapTile16() {
|
||||
for (int i = 0; i < 186; i++) {
|
||||
int addr = zelda3::screen::kDungeonMapTile16;
|
||||
if (rom()->data()[zelda3::screen::kDungeonMapExpCheck] != 0xB9) {
|
||||
addr = zelda3::screen::kDungeonMapTile16Expanded;
|
||||
}
|
||||
|
||||
gfx::TileInfo t1 = tile16_sheet_.tile_info()[i].tiles[0];
|
||||
gfx::TileInfo t2 = tile16_sheet_.tile_info()[i].tiles[1];
|
||||
gfx::TileInfo t3 = tile16_sheet_.tile_info()[i].tiles[2];
|
||||
gfx::TileInfo t4 = tile16_sheet_.tile_info()[i].tiles[3];
|
||||
|
||||
auto tl = gfx::TileInfoToWord(t1);
|
||||
RETURN_IF_ERROR(rom()->WriteWord(addr + (i * 8), tl));
|
||||
|
||||
auto tr = gfx::TileInfoToWord(t2);
|
||||
RETURN_IF_ERROR(rom()->WriteWord(addr + 2 + (i * 8), tr));
|
||||
|
||||
auto bl = gfx::TileInfoToWord(t3);
|
||||
RETURN_IF_ERROR(rom()->WriteWord(addr + 4 + (i * 8), bl));
|
||||
|
||||
auto br = gfx::TileInfoToWord(t4);
|
||||
RETURN_IF_ERROR(rom()->WriteWord(addr + 6 + (i * 8), br));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void ScreenEditor::DrawDungeonMapsTabs() {
|
||||
auto current_dungeon = dungeon_maps_[selected_dungeon];
|
||||
auto& current_dungeon = dungeon_maps_[selected_dungeon];
|
||||
if (ImGui::BeginTabBar("##DungeonMapTabs")) {
|
||||
auto nbr_floors =
|
||||
current_dungeon.nbr_of_floor + current_dungeon.nbr_of_basement;
|
||||
for (int i = 0; i < nbr_floors; i++) {
|
||||
std::string tab_name = absl::StrFormat("Floor %d", i + 1);
|
||||
if (i >= current_dungeon.nbr_of_floor) {
|
||||
tab_name = absl::StrFormat("Basement %d",
|
||||
i - current_dungeon.nbr_of_floor + 1);
|
||||
int basement_num = current_dungeon.nbr_of_basement - i;
|
||||
std::string tab_name = absl::StrFormat("Basement %d", basement_num);
|
||||
if (i >= current_dungeon.nbr_of_basement) {
|
||||
tab_name = absl::StrFormat("Floor %d",
|
||||
i - current_dungeon.nbr_of_basement + 1);
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem(tab_name.c_str())) {
|
||||
floor_number = i;
|
||||
// screen_canvas_.LoadCustomLabels(dungeon_map_labels_[selected_dungeon]);
|
||||
// screen_canvas_.set_current_labels(floor_number);
|
||||
screen_canvas_.DrawBackground(ImVec2(325, 325));
|
||||
screen_canvas_.DrawTileSelector(64.f);
|
||||
|
||||
auto boss_room = current_dungeon.boss_room;
|
||||
for (int j = 0; j < 25; j++) {
|
||||
if (current_dungeon.floor_rooms[floor_number][j] != 0x0F) {
|
||||
int tile16_id = current_dungeon.floor_rooms[floor_number][j];
|
||||
int tile_x = (tile16_id % 16) * 16;
|
||||
int tile_y = (tile16_id / 16) * 16;
|
||||
int tile16_id = current_dungeon.floor_gfx[floor_number][j];
|
||||
int posX = ((j % 5) * 32);
|
||||
int posY = ((j / 5) * 32);
|
||||
|
||||
if (tile16_individual_.count(tile16_id) == 0) {
|
||||
auto tile = tile16_sheet_.GetTile16(tile16_id);
|
||||
std::cout << "Tile16: " << tile16_id << std::endl;
|
||||
rom()->RenderBitmap(&tile);
|
||||
tile16_individual_[tile16_id] = tile;
|
||||
tile16_individual_[tile16_id] =
|
||||
tile16_sheet_.GetTile16(tile16_id);
|
||||
Renderer::GetInstance().RenderBitmap(
|
||||
&tile16_individual_[tile16_id]);
|
||||
}
|
||||
screen_canvas_.DrawBitmap(tile16_individual_[tile16_id], (posX * 2),
|
||||
(posY * 2), 4.0f);
|
||||
|
||||
if (current_dungeon.floor_rooms[floor_number][j] == boss_room) {
|
||||
screen_canvas_.DrawOutlineWithColor((posX * 2), (posY * 2), 64,
|
||||
64, core::kRedPen);
|
||||
64, kRedPen);
|
||||
}
|
||||
|
||||
std::string label =
|
||||
dungeon_map_labels_[selected_dungeon][floor_number][j];
|
||||
screen_canvas_.DrawText(label, (posX * 2), (posY * 2));
|
||||
std::string gfx_id = core::UppercaseHexByte(tile16_id);
|
||||
screen_canvas_.DrawText(gfx_id, (posX * 2), (posY * 2) + 16);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,31 +343,76 @@ void ScreenEditor::DrawDungeonMapsTabs() {
|
||||
|
||||
gui::InputHexWord("Boss Room", ¤t_dungeon.boss_room);
|
||||
|
||||
if (ImGui::Button("Copy Floor", ImVec2(100, 0))) {
|
||||
const ImVec2 button_size = ImVec2(130, 0);
|
||||
|
||||
// Add Floor Button
|
||||
if (ImGui::Button("Add Floor", button_size) &&
|
||||
current_dungeon.nbr_of_floor < 8) {
|
||||
current_dungeon.nbr_of_floor++;
|
||||
dungeon_map_labels_[selected_dungeon].emplace_back();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Remove Floor", button_size) &&
|
||||
current_dungeon.nbr_of_floor > 0) {
|
||||
current_dungeon.nbr_of_floor--;
|
||||
dungeon_map_labels_[selected_dungeon].pop_back();
|
||||
}
|
||||
|
||||
// Add Basement Button
|
||||
if (ImGui::Button("Add Basement", button_size) &&
|
||||
current_dungeon.nbr_of_basement < 8) {
|
||||
current_dungeon.nbr_of_basement++;
|
||||
dungeon_map_labels_[selected_dungeon].emplace_back();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Remove Basement", button_size) &&
|
||||
current_dungeon.nbr_of_basement > 0) {
|
||||
current_dungeon.nbr_of_basement--;
|
||||
dungeon_map_labels_[selected_dungeon].pop_back();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Copy Floor", button_size)) {
|
||||
copy_button_pressed = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Paste Floor", ImVec2(100, 0))) {
|
||||
if (ImGui::Button("Paste Floor", button_size)) {
|
||||
paste_button_pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenEditor::DrawDungeonMapsEditor() {
|
||||
if (!dungeon_maps_loaded_) {
|
||||
if (LoadDungeonMaps().ok()) {
|
||||
if (LoadDungeonMapTile16().ok()) {
|
||||
auto bitmap_manager = rom()->mutable_bitmap_manager();
|
||||
sheets_.emplace(0, *bitmap_manager->mutable_bitmap(212));
|
||||
sheets_.emplace(1, *bitmap_manager->mutable_bitmap(213));
|
||||
sheets_.emplace(2, *bitmap_manager->mutable_bitmap(214));
|
||||
sheets_.emplace(3, *bitmap_manager->mutable_bitmap(215));
|
||||
dungeon_maps_loaded_ = true;
|
||||
} else {
|
||||
ImGui::Text("Failed to load dungeon map tile16");
|
||||
}
|
||||
} else {
|
||||
if (!LoadDungeonMaps().ok()) {
|
||||
ImGui::Text("Failed to load dungeon maps");
|
||||
}
|
||||
|
||||
if (LoadDungeonMapTile16(rom()->graphics_buffer()).ok()) {
|
||||
// TODO: Load roomset gfx based on dungeon ID
|
||||
sheets_.emplace(0, rom()->gfx_sheets()[212]);
|
||||
sheets_.emplace(1, rom()->gfx_sheets()[213]);
|
||||
sheets_.emplace(2, rom()->gfx_sheets()[214]);
|
||||
sheets_.emplace(3, rom()->gfx_sheets()[215]);
|
||||
dungeon_maps_loaded_ = true;
|
||||
} else {
|
||||
ImGui::Text("Failed to load dungeon map tile16");
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("##DungeonMapToolset", 2, ImGuiTableFlags_SizingFixedFit)) {
|
||||
ImGui::TableSetupColumn("Draw Mode");
|
||||
ImGui::TableSetupColumn("Edit Mode");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Button(ICON_MD_DRAW)) {
|
||||
current_mode_ = EditingMode::DRAW;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Button(ICON_MD_EDIT)) {
|
||||
current_mode_ = EditingMode::EDIT;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
static std::vector<std::string> dungeon_names = {
|
||||
@@ -350,7 +422,10 @@ void ScreenEditor::DrawDungeonMapsEditor() {
|
||||
"Thieves' Town", "Ice Palace", "Misery Mire",
|
||||
"Turtle Rock", "Ganon's Tower"};
|
||||
|
||||
if (ImGui::BeginTable("DungeonMapsTable", 4, ImGuiTableFlags_Resizable)) {
|
||||
if (ImGui::BeginTable("DungeonMapsTable", 4,
|
||||
ImGuiTableFlags_Resizable |
|
||||
ImGuiTableFlags_Reorderable |
|
||||
ImGuiTableFlags_Hideable)) {
|
||||
ImGui::TableSetupColumn("Dungeon");
|
||||
ImGui::TableSetupColumn("Map");
|
||||
ImGui::TableSetupColumn("Rooms Gfx");
|
||||
@@ -384,32 +459,113 @@ void ScreenEditor::DrawDungeonMapsEditor() {
|
||||
if (!tilesheet_canvas_.points().empty()) {
|
||||
selected_tile16_ = tilesheet_canvas_.points().front().x / 32 +
|
||||
(tilesheet_canvas_.points().front().y / 32) * 16;
|
||||
current_tile16_info = tile16_sheet_.tile_info().at(selected_tile16_);
|
||||
|
||||
// Draw the selected tile
|
||||
if (!screen_canvas_.points().empty()) {
|
||||
dungeon_maps_[selected_dungeon]
|
||||
.floor_gfx[floor_number][selected_room] = selected_tile16_;
|
||||
tilesheet_canvas_.mutable_points()->clear();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
current_tile_canvas_.DrawBackground(ImVec2(64 * 2 + 2, 64 * 2 + 4));
|
||||
current_tile_canvas_.DrawContextMenu();
|
||||
current_tile_canvas_.DrawBitmap(tile16_individual_[selected_tile16_], 2,
|
||||
4.0f);
|
||||
current_tile_canvas_.DrawGrid(16.f);
|
||||
current_tile_canvas_.DrawOverlay();
|
||||
|
||||
gui::InputTileInfo("TL", ¤t_tile16_info.tiles[0]);
|
||||
ImGui::SameLine();
|
||||
gui::InputTileInfo("TR", ¤t_tile16_info.tiles[1]);
|
||||
gui::InputTileInfo("BL", ¤t_tile16_info.tiles[2]);
|
||||
ImGui::SameLine();
|
||||
gui::InputTileInfo("BR", ¤t_tile16_info.tiles[3]);
|
||||
|
||||
if (ImGui::Button("Modify Tile16")) {
|
||||
tile16_sheet_.ModifyTile16(
|
||||
rom()->graphics_buffer(), current_tile16_info.tiles[0],
|
||||
current_tile16_info.tiles[1], current_tile16_info.tiles[2],
|
||||
current_tile16_info.tiles[3], selected_tile16_, 212);
|
||||
tile16_individual_[selected_tile16_] =
|
||||
tile16_sheet_.GetTile16(selected_tile16_);
|
||||
RETURN_VOID_IF_ERROR(tile16_individual_[selected_tile16_].ApplyPalette(
|
||||
*rom()->mutable_dungeon_palette(3)));
|
||||
Renderer::GetInstance().RenderBitmap(
|
||||
&tile16_individual_[selected_tile16_]);
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
tilemap_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4));
|
||||
tilemap_canvas_.DrawBackground();
|
||||
tilemap_canvas_.DrawContextMenu();
|
||||
if (tilemap_canvas_.DrawTileSelector(16.f)) {
|
||||
// Get the tile8 ID to use for the tile16 drawing above
|
||||
selected_tile8_ = tilemap_canvas_.GetTileIdFromMousePos();
|
||||
}
|
||||
tilemap_canvas_.DrawBitmapTable(sheets_);
|
||||
tilemap_canvas_.DrawGrid();
|
||||
tilemap_canvas_.DrawOverlay();
|
||||
|
||||
ImGui::Text("Selected tile8: %d", selected_tile8_);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("For use with custom inserted graphics assembly patches.");
|
||||
if (ImGui::Button("Load GFX from BIN file")) LoadBinaryGfx();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenEditor::LoadBinaryGfx() {
|
||||
std::string bin_file = core::FileDialogWrapper::ShowOpenFileDialog();
|
||||
if (!bin_file.empty()) {
|
||||
std::ifstream file(bin_file, std::ios::binary);
|
||||
if (file.is_open()) {
|
||||
// Read the gfx data into a buffer
|
||||
std::vector<uint8_t> bin_data((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
auto converted_bin = gfx::SnesTo8bppSheet(bin_data, 4, 4);
|
||||
gfx_bin_data_ = converted_bin;
|
||||
tile16_sheet_.clear();
|
||||
if (LoadDungeonMapTile16(converted_bin, true).ok()) {
|
||||
sheets_.clear();
|
||||
std::vector<std::vector<uint8_t>> gfx_sheets;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000),
|
||||
converted_bin.begin() + ((i + 1) * 0x1000));
|
||||
sheets_.emplace(i, gfx::Bitmap(128, 32, 8, gfx_sheets[i]));
|
||||
sheets_[i].ApplyPalette(*rom()->mutable_dungeon_palette(3));
|
||||
Renderer::GetInstance().RenderBitmap(&sheets_[i]);
|
||||
}
|
||||
binary_gfx_loaded_ = true;
|
||||
} else {
|
||||
status_ = absl::InternalError("Failed to load dungeon map tile16");
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenEditor::DrawTitleScreenEditor() {
|
||||
TAB_ITEM("Title Screen")
|
||||
END_TAB_ITEM()
|
||||
if (ImGui::BeginTabItem("Title Screen")) {
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenEditor::DrawNamingScreenEditor() {
|
||||
TAB_ITEM("Naming Screen")
|
||||
END_TAB_ITEM()
|
||||
if (ImGui::BeginTabItem("Naming Screen")) {
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenEditor::DrawOverworldMapEditor() {
|
||||
TAB_ITEM("Overworld Map")
|
||||
END_TAB_ITEM()
|
||||
if (ImGui::BeginTabItem("Overworld Map")) {
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenEditor::DrawToolset() {
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
#ifndef YAZE_APP_EDITOR_SCREEN_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_SCREEN_EDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/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/color.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/screen/dungeon_map.h"
|
||||
#include "app/zelda3/screen/inventory.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -38,7 +33,7 @@ namespace editor {
|
||||
* The class inherits from the SharedRom class.
|
||||
*/
|
||||
class ScreenEditor : public SharedRom, public Editor {
|
||||
public:
|
||||
public:
|
||||
ScreenEditor() {
|
||||
screen_canvas_.SetCanvasSize(ImVec2(512, 512));
|
||||
type_ = EditorType::kScreen;
|
||||
@@ -55,7 +50,7 @@ class ScreenEditor : public SharedRom, public Editor {
|
||||
|
||||
absl::Status SaveDungeonMaps();
|
||||
|
||||
private:
|
||||
private:
|
||||
void DrawTitleScreenEditor();
|
||||
void DrawNamingScreenEditor();
|
||||
void DrawOverworldMapEditor();
|
||||
@@ -65,42 +60,58 @@ class ScreenEditor : public SharedRom, public Editor {
|
||||
void DrawInventoryToolset();
|
||||
|
||||
absl::Status LoadDungeonMaps();
|
||||
absl::Status LoadDungeonMapTile16();
|
||||
absl::Status LoadDungeonMapTile16(const std::vector<uint8_t> &gfx_data,
|
||||
bool bin_mode = false);
|
||||
absl::Status SaveDungeonMapTile16();
|
||||
void DrawDungeonMapsTabs();
|
||||
void DrawDungeonMapsEditor();
|
||||
|
||||
std::vector<zelda3::screen::DungeonMap> dungeon_maps_;
|
||||
std::vector<std::vector<std::array<std::string, 25>>> dungeon_map_labels_;
|
||||
void LoadBinaryGfx();
|
||||
|
||||
std::unordered_map<int, gfx::Bitmap> tile16_individual_;
|
||||
enum class EditingMode { DRAW, EDIT };
|
||||
|
||||
EditingMode current_mode_ = EditingMode::DRAW;
|
||||
|
||||
bool dungeon_maps_loaded_ = false;
|
||||
bool binary_gfx_loaded_ = false;
|
||||
|
||||
int selected_tile16_ = 0;
|
||||
int selected_dungeon = 0;
|
||||
uint8_t selected_room = 0;
|
||||
uint8_t boss_room = 0;
|
||||
|
||||
int selected_tile16_ = 0;
|
||||
int selected_tile8_ = 0;
|
||||
int selected_dungeon = 0;
|
||||
int floor_number = 1;
|
||||
|
||||
bool copy_button_pressed = false;
|
||||
bool paste_button_pressed = false;
|
||||
|
||||
Bytes all_gfx_;
|
||||
zelda3::screen::Inventory inventory_;
|
||||
gfx::SnesPalette palette_;
|
||||
gui::Canvas screen_canvas_;
|
||||
gui::Canvas tilesheet_canvas_;
|
||||
gui::Canvas tilemap_canvas_;
|
||||
|
||||
gfx::BitmapTable sheets_;
|
||||
|
||||
gfx::Tilesheet tile16_sheet_;
|
||||
std::vector<uint8_t> all_gfx_;
|
||||
std::unordered_map<int, gfx::Bitmap> tile16_individual_;
|
||||
std::vector<zelda3::screen::DungeonMap> dungeon_maps_;
|
||||
std::vector<std::vector<std::array<std::string, 25>>> dungeon_map_labels_;
|
||||
std::array<uint16_t, 4> current_tile16_data_;
|
||||
std::vector<uint8_t> gfx_bin_data_;
|
||||
|
||||
absl::Status status_;
|
||||
|
||||
gfx::SnesPalette palette_;
|
||||
gfx::BitmapTable sheets_;
|
||||
gfx::Tilesheet tile16_sheet_;
|
||||
gfx::InternalTile16 current_tile16_info;
|
||||
|
||||
gui::Canvas current_tile_canvas_{"##CurrentTileCanvas"};
|
||||
gui::Canvas screen_canvas_;
|
||||
gui::Canvas tilesheet_canvas_;
|
||||
gui::Canvas tilemap_canvas_{"##TilemapCanvas",
|
||||
ImVec2(128 + 2, (192) + 4),
|
||||
gui::CanvasGridSize::k8x8, 2.f};
|
||||
|
||||
zelda3::screen::Inventory inventory_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#include "tile16_editor.h"
|
||||
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "ImGuiFileDialog/ImGuiFileDialog.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/platform/renderer.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
@@ -19,11 +18,14 @@
|
||||
#include "app/gui/style.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
using core::Renderer;
|
||||
|
||||
using ImGui::BeginChild;
|
||||
using ImGui::BeginMenu;
|
||||
using ImGui::BeginMenuBar;
|
||||
@@ -48,14 +50,13 @@ using ImGui::TableSetupColumn;
|
||||
using ImGui::Text;
|
||||
|
||||
absl::Status Tile16Editor::InitBlockset(
|
||||
gfx::Bitmap* tile16_blockset_bmp, gfx::Bitmap current_gfx_bmp,
|
||||
const gfx::Bitmap& tile16_blockset_bmp, const 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_IF_ERROR(LoadTile8());
|
||||
ImVector<std::string> tile16_names;
|
||||
for (int i = 0; i < 0x200; ++i) {
|
||||
@@ -75,7 +76,7 @@ absl::Status Tile16Editor::Update() {
|
||||
|
||||
RETURN_IF_ERROR(DrawMenu());
|
||||
if (BeginTabBar("Tile16 Editor Tabs")) {
|
||||
RETURN_IF_ERROR(DrawTile16Editor());
|
||||
DrawTile16Editor();
|
||||
RETURN_IF_ERROR(UpdateTile16Transfer());
|
||||
EndTabBar();
|
||||
}
|
||||
@@ -97,7 +98,7 @@ absl::Status Tile16Editor::DrawMenu() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::DrawTile16Editor() {
|
||||
void Tile16Editor::DrawTile16Editor() {
|
||||
if (BeginTabItem("Tile16 Editing")) {
|
||||
if (BeginTable("#Tile16EditorTable", 2, TABLE_BORDERS_RESIZABLE,
|
||||
ImVec2(0, 0))) {
|
||||
@@ -108,18 +109,23 @@ absl::Status Tile16Editor::DrawTile16Editor() {
|
||||
TableHeadersRow();
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
RETURN_IF_ERROR(UpdateBlockset());
|
||||
status_ = UpdateBlockset();
|
||||
if (!status_.ok()) {
|
||||
EndTable();
|
||||
}
|
||||
|
||||
TableNextColumn();
|
||||
RETURN_IF_ERROR(UpdateTile16Edit());
|
||||
RETURN_IF_ERROR(DrawTileEditControls());
|
||||
status_ = UpdateTile16Edit();
|
||||
if (status_ != absl::OkStatus()) {
|
||||
EndTable();
|
||||
}
|
||||
status_ = DrawTileEditControls();
|
||||
|
||||
EndTable();
|
||||
}
|
||||
|
||||
EndTabItem();
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::UpdateBlockset() {
|
||||
@@ -127,14 +133,12 @@ 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();
|
||||
EndChild();
|
||||
}
|
||||
blockset_canvas_.DrawContextMenu();
|
||||
blockset_canvas_.DrawTileSelector(32);
|
||||
blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 0, map_blockset_loaded_);
|
||||
blockset_canvas_.DrawGrid();
|
||||
blockset_canvas_.DrawOverlay();
|
||||
EndChild();
|
||||
|
||||
if (!blockset_canvas_.points().empty()) {
|
||||
notify_tile16.mutable_get() = blockset_canvas_.GetTileIdFromMousePos();
|
||||
@@ -142,11 +146,11 @@ absl::Status Tile16Editor::UpdateBlockset() {
|
||||
|
||||
if (notify_tile16.modified()) {
|
||||
current_tile16_ = notify_tile16.get();
|
||||
current_tile16_bmp_ = &tile16_individual_[notify_tile16];
|
||||
current_tile16_bmp_ = tile16_individual_[notify_tile16];
|
||||
auto ow_main_pal_group = rom()->palette_group().overworld_main;
|
||||
RETURN_IF_ERROR(current_tile16_bmp_->ApplyPalette(
|
||||
RETURN_IF_ERROR(current_tile16_bmp_.ApplyPalette(
|
||||
ow_main_pal_group[current_palette_]));
|
||||
rom()->RenderBitmap(current_tile16_bmp_);
|
||||
Renderer::GetInstance().RenderBitmap(¤t_tile16_bmp_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,8 +170,8 @@ absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) {
|
||||
|
||||
// Calculate the pixel start position within the Tile16
|
||||
ImVec2 start_position;
|
||||
start_position.x = ((tile_index_x) / 4) * 0x40;
|
||||
start_position.y = ((tile_index_y) / 4) * 0x40;
|
||||
start_position.x = tile_index_x * 0x40;
|
||||
start_position.y = tile_index_y * 0x40;
|
||||
std::cout << "Start Position X: " << start_position.x << std::endl;
|
||||
std::cout << "Start Position Y: " << start_position.y << std::endl;
|
||||
|
||||
@@ -177,7 +181,7 @@ absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) {
|
||||
int pixel_index =
|
||||
(start_position.y + y) * tile16_size + ((start_position.x) + x);
|
||||
int gfx_pixel_index = y * tile8_size + x;
|
||||
current_tile16_bmp_->WriteToPixel(
|
||||
current_tile16_bmp_.WriteToPixel(
|
||||
pixel_index,
|
||||
current_gfx_individual_[current_tile8_].data()[gfx_pixel_index]);
|
||||
}
|
||||
@@ -197,7 +201,8 @@ absl::Status Tile16Editor::UpdateTile16Edit() {
|
||||
RETURN_IF_ERROR(
|
||||
current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
|
||||
ow_main_pal_group[0], current_palette_));
|
||||
rom()->UpdateBitmap(¤t_gfx_individual_[current_tile8_]);
|
||||
Renderer::GetInstance().UpdateBitmap(
|
||||
¤t_gfx_individual_[current_tile8_]);
|
||||
}
|
||||
tile8_source_canvas_.DrawBitmap(current_gfx_bmp_, 0, 0, 4.0f);
|
||||
tile8_source_canvas_.DrawGrid();
|
||||
@@ -214,20 +219,21 @@ absl::Status Tile16Editor::UpdateTile16Edit() {
|
||||
RETURN_IF_ERROR(
|
||||
current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
|
||||
ow_main_pal_group[0], current_palette_));
|
||||
rom()->UpdateBitmap(¤t_gfx_individual_[current_tile8_]);
|
||||
Renderer::GetInstance().UpdateBitmap(
|
||||
¤t_gfx_individual_[current_tile8_]);
|
||||
}
|
||||
|
||||
if (BeginChild("Tile16 Editor Options",
|
||||
ImVec2(GetContentRegionAvail().x, 0x50), true)) {
|
||||
tile16_edit_canvas_.DrawBackground();
|
||||
tile16_edit_canvas_.DrawContextMenu(current_tile16_bmp_);
|
||||
tile16_edit_canvas_.DrawBitmap(*current_tile16_bmp_, 0, 0, 4.0f);
|
||||
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(
|
||||
current_gfx_individual_[current_tile8_], 16, 2.0f)) {
|
||||
RETURN_IF_ERROR(
|
||||
DrawToCurrentTile16(tile16_edit_canvas_.drawn_tile_position()));
|
||||
rom()->UpdateBitmap(current_tile16_bmp_);
|
||||
Renderer::GetInstance().UpdateBitmap(¤t_tile16_bmp_);
|
||||
}
|
||||
}
|
||||
tile16_edit_canvas_.DrawGrid();
|
||||
@@ -258,10 +264,11 @@ absl::Status Tile16Editor::DrawTileEditControls() {
|
||||
if (value > 0x00) {
|
||||
RETURN_IF_ERROR(
|
||||
current_gfx_bmp_.ApplyPaletteWithTransparent(palette, value));
|
||||
Renderer::GetInstance().UpdateBitmap(¤t_gfx_bmp_);
|
||||
|
||||
RETURN_IF_ERROR(
|
||||
current_tile16_bmp_->ApplyPaletteWithTransparent(palette, value));
|
||||
rom()->UpdateBitmap(¤t_gfx_bmp_);
|
||||
rom()->UpdateBitmap(current_tile16_bmp_);
|
||||
current_tile16_bmp_.ApplyPaletteWithTransparent(palette, value));
|
||||
Renderer::GetInstance().UpdateBitmap(¤t_tile16_bmp_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +297,6 @@ absl::Status Tile16Editor::LoadTile8() {
|
||||
|
||||
// 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);
|
||||
@@ -310,7 +316,7 @@ absl::Status Tile16Editor::LoadTile8() {
|
||||
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]);
|
||||
Renderer::GetInstance().RenderBitmap(¤t_gfx_individual_[index]);
|
||||
}
|
||||
|
||||
map_blockset_loaded_ = true;
|
||||
@@ -318,8 +324,17 @@ absl::Status Tile16Editor::LoadTile8() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Tile16 Transfer
|
||||
absl::Status Tile16Editor::SetCurrentTile(int id) {
|
||||
current_tile16_ = id;
|
||||
current_tile16_bmp_ = tile16_individual_[id];
|
||||
auto ow_main_pal_group = rom()->palette_group().overworld_main;
|
||||
RETURN_IF_ERROR(
|
||||
current_tile16_bmp_.ApplyPalette(ow_main_pal_group[current_palette_]));
|
||||
Renderer::GetInstance().RenderBitmap(¤t_tile16_bmp_);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
#pragma mark - Tile16Transfer
|
||||
|
||||
absl::Status Tile16Editor::UpdateTile16Transfer() {
|
||||
if (BeginTabItem("Tile16 Transfer")) {
|
||||
@@ -363,16 +378,15 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() {
|
||||
// TODO: Implement tile16 transfer
|
||||
if (transfer_started_ && !transfer_blockset_loaded_) {
|
||||
PRINT_IF_ERROR(transfer_rom_.LoadAllGraphicsData())
|
||||
graphics_bin_ = transfer_rom_.graphics_bin();
|
||||
|
||||
// Load the Link to the Past overworld.
|
||||
PRINT_IF_ERROR(transfer_overworld_.Load(transfer_rom_))
|
||||
transfer_overworld_.set_current_map(0);
|
||||
palette_ = transfer_overworld_.AreaPalette();
|
||||
palette_ = transfer_overworld_.current_area_palette();
|
||||
|
||||
// Create the tile16 blockset image
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
|
||||
0x80, 0x2000, 0x80, transfer_overworld_.Tile16Blockset(),
|
||||
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
|
||||
0x80, 0x2000, 0x80, transfer_overworld_.tile16_blockset_data(),
|
||||
transfer_blockset_bmp_, palette_));
|
||||
transfer_blockset_loaded_ = true;
|
||||
}
|
||||
@@ -385,16 +399,6 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Tile16Editor::SetCurrentTile(int id) {
|
||||
current_tile16_ = id;
|
||||
current_tile16_bmp_ = &tile16_individual_[id];
|
||||
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(current_tile16_bmp_);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
#ifndef YAZE_APP_EDITOR_TILE16EDITOR_H
|
||||
#define YAZE_APP_EDITOR_TILE16EDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/utils/gfx_context.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/rom.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -26,17 +19,17 @@ namespace editor {
|
||||
/**
|
||||
* @brief Popup window to edit Tile16 data
|
||||
*/
|
||||
class Tile16Editor : public context::GfxContext, public SharedRom {
|
||||
class Tile16Editor : public GfxContext, public SharedRom {
|
||||
public:
|
||||
absl::Status InitBlockset(gfx::Bitmap* tile16_blockset_bmp,
|
||||
gfx::Bitmap current_gfx_bmp,
|
||||
absl::Status InitBlockset(const gfx::Bitmap& tile16_blockset_bmp,
|
||||
const gfx::Bitmap& current_gfx_bmp,
|
||||
const std::vector<gfx::Bitmap>& tile16_individual,
|
||||
uint8_t all_tiles_types[0x200]);
|
||||
|
||||
absl::Status Update();
|
||||
absl::Status DrawMenu();
|
||||
|
||||
absl::Status DrawTile16Editor();
|
||||
void DrawTile16Editor();
|
||||
absl::Status UpdateTile16Transfer();
|
||||
absl::Status UpdateBlockset();
|
||||
|
||||
@@ -75,38 +68,32 @@ class Tile16Editor : public context::GfxContext, public SharedRom {
|
||||
// Tile16 blockset for selecting the tile to edit
|
||||
gui::Canvas blockset_canvas_{"blocksetCanvas", ImVec2(0x100, 0x4000),
|
||||
gui::CanvasGridSize::k32x32};
|
||||
gfx::Bitmap* tile16_blockset_bmp_;
|
||||
gfx::Bitmap tile16_blockset_bmp_;
|
||||
|
||||
// Canvas for editing the selected tile
|
||||
gui::Canvas tile16_edit_canvas_{"Tile16EditCanvas", ImVec2(0x40, 0x40),
|
||||
gui::CanvasGridSize::k64x64};
|
||||
gfx::Bitmap* current_tile16_bmp_;
|
||||
gfx::Bitmap current_tile16_bmp_;
|
||||
|
||||
// Tile8 canvas to get the tile to drawing in the tile16_edit_canvas_
|
||||
gui::Canvas tile8_source_canvas_{
|
||||
"Tile8SourceCanvas",
|
||||
ImVec2(core::kTilesheetWidth * 4, core::kTilesheetHeight * 0x10 * 4),
|
||||
ImVec2(gfx::kTilesheetWidth * 4, gfx::kTilesheetHeight * 0x10 * 4),
|
||||
gui::CanvasGridSize::k32x32};
|
||||
gfx::Bitmap current_gfx_bmp_;
|
||||
|
||||
gui::Canvas transfer_canvas_;
|
||||
gfx::Bitmap transfer_blockset_bmp_;
|
||||
|
||||
std::vector<Bytes> tile16_individual_data_;
|
||||
std::vector<gfx::Bitmap> tile16_individual_;
|
||||
|
||||
std::vector<gfx::Bitmap> current_gfx_individual_;
|
||||
|
||||
std::vector<uint8_t> current_tile16_data_;
|
||||
|
||||
std::vector<uint8_t> tile8_gfx_data_;
|
||||
|
||||
PaletteEditor palette_editor_;
|
||||
|
||||
gfx::SnesPalette palette_;
|
||||
zelda3::overworld::Overworld transfer_overworld_;
|
||||
|
||||
gfx::BitmapTable graphics_bin_;
|
||||
absl::Status status_;
|
||||
|
||||
Rom transfer_rom_;
|
||||
absl::Status transfer_status_;
|
||||
@@ -115,4 +102,4 @@ class Tile16Editor : public context::GfxContext, public SharedRom {
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
#endif // YAZE_APP_EDITOR_TILE16EDITOR_H
|
||||
#endif // YAZE_APP_EDITOR_TILE16EDITOR_H
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "master_editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
182
src/app/editor/message/message_data.cc
Normal file
182
src/app/editor/message/message_data.cc
Normal file
@@ -0,0 +1,182 @@
|
||||
#include "message_data.h"
|
||||
|
||||
#include "app/core/common.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
uint8_t FindMatchingCharacter(char value) {
|
||||
for (const auto [key, char_value] : CharEncoder) {
|
||||
if (value == char_value) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
uint8_t FindDictionaryEntry(uint8_t value) {
|
||||
if (value < DICTOFF || value == 0xFF) {
|
||||
return -1;
|
||||
}
|
||||
return value - DICTOFF;
|
||||
}
|
||||
|
||||
TextElement FindMatchingCommand(uint8_t b) {
|
||||
TextElement empty_element;
|
||||
for (const auto& text_element : TextCommands) {
|
||||
if (text_element.ID == b) {
|
||||
return text_element;
|
||||
}
|
||||
}
|
||||
return empty_element;
|
||||
}
|
||||
|
||||
TextElement FindMatchingSpecial(uint8_t value) {
|
||||
auto it = std::find_if(SpecialChars.begin(), SpecialChars.end(),
|
||||
[value](const TextElement& text_element) {
|
||||
return text_element.ID == value;
|
||||
});
|
||||
if (it != SpecialChars.end()) {
|
||||
return *it;
|
||||
}
|
||||
|
||||
return TextElement();
|
||||
}
|
||||
|
||||
ParsedElement FindMatchingElement(const std::string& str) {
|
||||
std::smatch match;
|
||||
for (auto& textElement : TextCommands) {
|
||||
match = textElement.MatchMe(str);
|
||||
if (match.size() > 0) {
|
||||
if (textElement.HasArgument) {
|
||||
return ParsedElement(textElement,
|
||||
std::stoi(match[1].str(), nullptr, 16));
|
||||
} else {
|
||||
return ParsedElement(textElement, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto dictionary_element =
|
||||
TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
|
||||
|
||||
match = dictionary_element.MatchMe(str);
|
||||
if (match.size() > 0) {
|
||||
return ParsedElement(dictionary_element,
|
||||
DICTOFF + std::stoi(match[1].str(), nullptr, 16));
|
||||
}
|
||||
return ParsedElement();
|
||||
}
|
||||
|
||||
std::string ParseTextDataByte(uint8_t value) {
|
||||
if (CharEncoder.contains(value)) {
|
||||
char c = CharEncoder.at(value);
|
||||
std::string str = "";
|
||||
str.push_back(c);
|
||||
return str;
|
||||
}
|
||||
|
||||
// Check for command.
|
||||
TextElement textElement = FindMatchingCommand(value);
|
||||
if (!textElement.Empty()) {
|
||||
return textElement.GenericToken;
|
||||
}
|
||||
|
||||
// Check for special characters.
|
||||
textElement = FindMatchingSpecial(value);
|
||||
if (!textElement.Empty()) {
|
||||
return textElement.GenericToken;
|
||||
}
|
||||
|
||||
// Check for dictionary.
|
||||
int dictionary = FindDictionaryEntry(value);
|
||||
if (dictionary >= 0) {
|
||||
return absl::StrFormat("[%s:%X]", DICTIONARYTOKEN, dictionary);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ParseMessageToData(std::string str) {
|
||||
std::vector<uint8_t> bytes;
|
||||
std::string temp_string = str;
|
||||
int pos = 0;
|
||||
|
||||
while (pos < temp_string.size()) {
|
||||
// Get next text fragment.
|
||||
if (temp_string[pos] == '[') {
|
||||
int next = temp_string.find(']', pos);
|
||||
if (next == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
ParsedElement parsedElement =
|
||||
FindMatchingElement(temp_string.substr(pos, next - pos + 1));
|
||||
|
||||
const auto dictionary_element =
|
||||
TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
|
||||
|
||||
if (!parsedElement.Active) {
|
||||
core::logf("Error parsing message: %s", temp_string);
|
||||
break;
|
||||
} else if (parsedElement.Parent == dictionary_element) {
|
||||
bytes.push_back(parsedElement.Value);
|
||||
} else {
|
||||
bytes.push_back(parsedElement.Parent.ID);
|
||||
|
||||
if (parsedElement.Parent.HasArgument) {
|
||||
bytes.push_back(parsedElement.Value);
|
||||
}
|
||||
}
|
||||
|
||||
pos = next + 1;
|
||||
continue;
|
||||
} else {
|
||||
uint8_t bb = FindMatchingCharacter(temp_string[pos++]);
|
||||
|
||||
if (bb != 0xFF) {
|
||||
core::logf("Error parsing message: %s", temp_string);
|
||||
bytes.push_back(bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
std::vector<DictionaryEntry> BuildDictionaryEntries(app::Rom* rom) {
|
||||
std::vector<DictionaryEntry> AllDictionaries;
|
||||
for (int i = 0; i < kNumDictionaryEntries; i++) {
|
||||
std::vector<uint8_t> bytes;
|
||||
std::stringstream stringBuilder;
|
||||
|
||||
int address = core::SnesToPc(
|
||||
kTextData + (rom->data()[kPointersDictionaries + (i * 2) + 1] << 8) +
|
||||
rom->data()[kPointersDictionaries + (i * 2)]);
|
||||
|
||||
int temppush_backress = core::SnesToPc(
|
||||
kTextData +
|
||||
(rom->data()[kPointersDictionaries + ((i + 1) * 2) + 1] << 8) +
|
||||
rom->data()[kPointersDictionaries + ((i + 1) * 2)]);
|
||||
|
||||
while (address < temppush_backress) {
|
||||
uint8_t uint8_tDictionary = rom->data()[address++];
|
||||
bytes.push_back(uint8_tDictionary);
|
||||
stringBuilder << ParseTextDataByte(uint8_tDictionary);
|
||||
}
|
||||
|
||||
AllDictionaries.push_back(DictionaryEntry{(uint8_t)i, stringBuilder.str()});
|
||||
}
|
||||
|
||||
std::sort(AllDictionaries.begin(), AllDictionaries.end(),
|
||||
[](const DictionaryEntry& a, const DictionaryEntry& b) {
|
||||
return a.Contents.size() > b.Contents.size();
|
||||
});
|
||||
|
||||
return AllDictionaries;
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -1,23 +1,90 @@
|
||||
#ifndef YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
|
||||
#define YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
const uint8_t MESSAGETERMINATOR = 0x7F;
|
||||
const uint8_t kMessageTerminator = 0x7F;
|
||||
const std::string BANKToken = "BANK";
|
||||
const std::string DICTIONARYTOKEN = "D";
|
||||
constexpr uint8_t DICTOFF = 0x88;
|
||||
|
||||
static std::string AddNewLinesToCommands(std::string str);
|
||||
static std::string ReplaceAllDictionaryWords(std::string str);
|
||||
static std::vector<uint8_t> ParseMessageToData(std::string str);
|
||||
static const std::unordered_map<uint8_t, wchar_t> CharEncoder = {
|
||||
{0x00, 'A'}, {0x01, 'B'}, {0x02, 'C'}, {0x03, 'D'}, {0x04, 'E'},
|
||||
{0x05, 'F'}, {0x06, 'G'}, {0x07, 'H'}, {0x08, 'I'}, {0x09, 'J'},
|
||||
{0x0A, 'K'}, {0x0B, 'L'}, {0x0C, 'M'}, {0x0D, 'N'}, {0x0E, 'O'},
|
||||
{0x0F, 'P'}, {0x10, 'Q'}, {0x11, 'R'}, {0x12, 'S'}, {0x13, 'T'},
|
||||
{0x14, 'U'}, {0x15, 'V'}, {0x16, 'W'}, {0x17, 'X'}, {0x18, 'Y'},
|
||||
{0x19, 'Z'}, {0x1A, 'a'}, {0x1B, 'b'}, {0x1C, 'c'}, {0x1D, 'd'},
|
||||
{0x1E, 'e'}, {0x1F, 'f'}, {0x20, 'g'}, {0x21, 'h'}, {0x22, 'i'},
|
||||
{0x23, 'j'}, {0x24, 'k'}, {0x25, 'l'}, {0x26, 'm'}, {0x27, 'n'},
|
||||
{0x28, 'o'}, {0x29, 'p'}, {0x2A, 'q'}, {0x2B, 'r'}, {0x2C, 's'},
|
||||
{0x2D, 't'}, {0x2E, 'u'}, {0x2F, 'v'}, {0x30, 'w'}, {0x31, 'x'},
|
||||
{0x32, 'y'}, {0x33, 'z'}, {0x34, '0'}, {0x35, '1'}, {0x36, '2'},
|
||||
{0x37, '3'}, {0x38, '4'}, {0x39, '5'}, {0x3A, '6'}, {0x3B, '7'},
|
||||
{0x3C, '8'}, {0x3D, '9'}, {0x3E, '!'}, {0x3F, '?'}, {0x40, '-'},
|
||||
{0x41, '.'}, {0x42, ','}, {0x44, '>'}, {0x45, '('}, {0x46, ')'},
|
||||
{0x4C, '"'}, {0x51, '\''}, {0x59, ' '}, {0x5A, '<'}, {0x5F, L'¡'},
|
||||
{0x60, L'¡'}, {0x61, L'¡'}, {0x62, L' '}, {0x63, L' '}, {0x64, L' '},
|
||||
{0x65, ' '}, {0x66, '_'},
|
||||
};
|
||||
|
||||
const std::string CHEESE = "\uBEBE"; // Inserted into commands to protect
|
||||
// them from dictionary replacements.
|
||||
uint8_t FindMatchingCharacter(char value);
|
||||
uint8_t FindDictionaryEntry(uint8_t value);
|
||||
|
||||
std::vector<uint8_t> ParseMessageToData(std::string str);
|
||||
|
||||
struct DictionaryEntry {
|
||||
uint8_t ID;
|
||||
std::string Contents;
|
||||
std::vector<uint8_t> Data;
|
||||
int Length;
|
||||
std::string Token;
|
||||
|
||||
DictionaryEntry() = default;
|
||||
DictionaryEntry(uint8_t i, std::string s)
|
||||
: Contents(s), ID(i), Length(s.length()) {
|
||||
Token = absl::StrFormat("[%s:%00X]", DICTIONARYTOKEN, ID);
|
||||
Data = ParseMessageToData(Contents);
|
||||
}
|
||||
|
||||
bool ContainedInString(std::string s) {
|
||||
return s.find(Contents) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string ReplaceInstancesOfIn(std::string s) {
|
||||
std::string replacedString = s;
|
||||
size_t pos = replacedString.find(Contents);
|
||||
while (pos != std::string::npos) {
|
||||
replacedString.replace(pos, Contents.length(), Token);
|
||||
pos = replacedString.find(Contents, pos + Token.length());
|
||||
}
|
||||
return replacedString;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int kTextData = 0xE0000;
|
||||
constexpr int kTextDataEnd = 0xE7FFF;
|
||||
constexpr int kNumDictionaryEntries = 97;
|
||||
constexpr int kPointersDictionaries = 0x74703;
|
||||
|
||||
std::vector<DictionaryEntry> BuildDictionaryEntries(app::Rom* rom);
|
||||
|
||||
std::string ReplaceAllDictionaryWords(std::string str,
|
||||
std::vector<DictionaryEntry> dictionary);
|
||||
|
||||
// Inserted into commands to protect them from dictionary replacements.
|
||||
const std::string CHEESE = "\uBEBE";
|
||||
|
||||
struct MessageData {
|
||||
int ID;
|
||||
@@ -49,35 +116,13 @@ struct MessageData {
|
||||
ContentsParsed = other.ContentsParsed;
|
||||
}
|
||||
|
||||
void SetMessage(std::string messageString) {
|
||||
ContentsParsed = messageString;
|
||||
RawString = OptimizeMessageForDictionary(messageString);
|
||||
RecalculateData();
|
||||
}
|
||||
|
||||
std::string ToString() {
|
||||
return absl::StrFormat("%0X - %s", ID, ContentsParsed);
|
||||
}
|
||||
|
||||
std::string GetReadableDumpedContents() {
|
||||
std::stringstream stringBuilder;
|
||||
for (const auto& b : Data) {
|
||||
stringBuilder << absl::StrFormat("%0X ", b);
|
||||
}
|
||||
stringBuilder << absl::StrFormat("%00X", MESSAGETERMINATOR);
|
||||
|
||||
return absl::StrFormat(
|
||||
"[[[[\r\nMessage "
|
||||
"%000X]]]]\r\n[Contents]\r\n%s\r\n\r\n[Data]\r\n%s"
|
||||
"\r\n\r\n\r\n\r\n",
|
||||
ID, AddNewLinesToCommands(ContentsParsed), stringBuilder.str());
|
||||
}
|
||||
|
||||
std::string GetDumpedContents() {
|
||||
return absl::StrFormat("%000X : %s\r\n\r\n", ID, ContentsParsed);
|
||||
}
|
||||
|
||||
std::string OptimizeMessageForDictionary(std::string messageString) {
|
||||
std::string OptimizeMessageForDictionary(
|
||||
std::string messageString,
|
||||
const std::vector<DictionaryEntry>& dictionary) {
|
||||
std::stringstream protons;
|
||||
bool command = false;
|
||||
for (const auto& c : messageString) {
|
||||
@@ -94,16 +139,18 @@ struct MessageData {
|
||||
}
|
||||
|
||||
std::string protonsString = protons.str();
|
||||
std::string replacedString = ReplaceAllDictionaryWords(protonsString);
|
||||
std::string replacedString =
|
||||
ReplaceAllDictionaryWords(protonsString, dictionary);
|
||||
std::string finalString =
|
||||
absl::StrReplaceAll(replacedString, {{CHEESE, ""}});
|
||||
|
||||
return finalString;
|
||||
}
|
||||
|
||||
void RecalculateData() {
|
||||
Data = ParseMessageToData(RawString);
|
||||
DataParsed = ParseMessageToData(ContentsParsed);
|
||||
void SetMessage(const std::string& message,
|
||||
const std::vector<DictionaryEntry>& dictionary) {
|
||||
RawString = message;
|
||||
ContentsParsed = OptimizeMessageForDictionary(message, dictionary);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -155,8 +202,64 @@ struct TextElement {
|
||||
}
|
||||
|
||||
bool Empty() { return ID == 0; }
|
||||
|
||||
// Comparison operator
|
||||
bool operator==(const TextElement& other) const { return ID == other.ID; }
|
||||
};
|
||||
|
||||
static const std::vector<TextElement> TextCommands = {
|
||||
TextElement(0x6B, "W", true, "Window border"),
|
||||
TextElement(0x6D, "P", true, "Window position"),
|
||||
TextElement(0x6E, "SPD", true, "Scroll speed"),
|
||||
TextElement(0x7A, "S", true, "Text draw speed"),
|
||||
TextElement(0x77, "C", true, "Text color"),
|
||||
TextElement(0x6A, "L", false, "Player name"),
|
||||
TextElement(0x74, "1", false, "Line 1"),
|
||||
TextElement(0x75, "2", false, "Line 2"),
|
||||
TextElement(0x76, "3", false, "Line 3"),
|
||||
TextElement(0x7E, "K", false, "Wait for key"),
|
||||
TextElement(0x73, "V", false, "Scroll text"),
|
||||
TextElement(0x78, "WT", true, "Delay X"),
|
||||
TextElement(0x6C, "N", true, "BCD number"),
|
||||
TextElement(0x79, "SFX", true, "Sound effect"),
|
||||
TextElement(0x71, "CH3", false, "Choose 3"),
|
||||
TextElement(0x72, "CH2", false, "Choose 2 high"),
|
||||
TextElement(0x6F, "CH2L", false, "Choose 2 low"),
|
||||
TextElement(0x68, "CH2I", false, "Choose 2 indented"),
|
||||
TextElement(0x69, "CHI", false, "Choose item"),
|
||||
TextElement(0x67, "IMG", false, "Next attract image"),
|
||||
TextElement(0x80, BANKToken, false, "Bank marker (automatic)"),
|
||||
TextElement(0x70, "NONO", false, "Crash"),
|
||||
};
|
||||
|
||||
TextElement FindMatchingCommand(uint8_t b);
|
||||
|
||||
static const std::vector<TextElement> SpecialChars = {
|
||||
TextElement(0x43, "...", false, "Ellipsis …"),
|
||||
TextElement(0x4D, "UP", false, "Arrow ↑"),
|
||||
TextElement(0x4E, "DOWN", false, "Arrow ↓"),
|
||||
TextElement(0x4F, "LEFT", false, "Arrow ←"),
|
||||
TextElement(0x50, "RIGHT", false, "Arrow →"),
|
||||
TextElement(0x5B, "A", false, "Button Ⓐ"),
|
||||
TextElement(0x5C, "B", false, "Button Ⓑ"),
|
||||
TextElement(0x5D, "X", false, "Button ⓧ"),
|
||||
TextElement(0x5E, "Y", false, "Button ⓨ"),
|
||||
TextElement(0x52, "HP1L", false, "1 HP left"),
|
||||
TextElement(0x53, "HP1R", false, "1 HP right"),
|
||||
TextElement(0x54, "HP2L", false, "2 HP left"),
|
||||
TextElement(0x55, "HP3L", false, "3 HP left"),
|
||||
TextElement(0x56, "HP3R", false, "3 HP right"),
|
||||
TextElement(0x57, "HP4L", false, "4 HP left"),
|
||||
TextElement(0x58, "HP4R", false, "4 HP right"),
|
||||
TextElement(0x47, "HY0", false, "Hieroglyph ☥"),
|
||||
TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"),
|
||||
TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"),
|
||||
TextElement(0x4A, "LFL", false, "Link face left"),
|
||||
TextElement(0x4B, "LFR", false, "Link face right"),
|
||||
};
|
||||
|
||||
TextElement FindMatchingSpecial(uint8_t b);
|
||||
|
||||
struct ParsedElement {
|
||||
TextElement Parent;
|
||||
uint8_t Value;
|
||||
@@ -170,8 +273,12 @@ struct ParsedElement {
|
||||
}
|
||||
};
|
||||
|
||||
ParsedElement FindMatchingElement(const std::string& str);
|
||||
|
||||
std::string ParseTextDataByte(uint8_t value);
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
|
||||
#endif // YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "message_editor.h"
|
||||
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -9,26 +7,24 @@
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/core/platform/renderer.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/rom.h"
|
||||
#include "imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
using ImGui::Begin;
|
||||
using core::Renderer;
|
||||
|
||||
using ImGui::BeginChild;
|
||||
using ImGui::BeginTable;
|
||||
using ImGui::Button;
|
||||
using ImGui::End;
|
||||
using ImGui::EndChild;
|
||||
using ImGui::EndTable;
|
||||
using ImGui::InputText;
|
||||
@@ -37,216 +33,24 @@ using ImGui::SameLine;
|
||||
using ImGui::Separator;
|
||||
using ImGui::TableHeadersRow;
|
||||
using ImGui::TableNextColumn;
|
||||
using ImGui::TableNextRow;
|
||||
using ImGui::TableSetupColumn;
|
||||
using ImGui::Text;
|
||||
using ImGui::TextWrapped;
|
||||
using ImGui::TreeNode;
|
||||
|
||||
static ParsedElement FindMatchingElement(string str) {
|
||||
std::smatch match;
|
||||
for (auto& textElement : TextCommands) {
|
||||
match = textElement.MatchMe(str);
|
||||
if (match.size() > 0) {
|
||||
if (textElement.HasArgument) {
|
||||
return ParsedElement(textElement,
|
||||
std::stoi(match[1].str(), nullptr, 16));
|
||||
} else {
|
||||
return ParsedElement(textElement, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr ImGuiTableFlags kMessageTableFlags = ImGuiTableFlags_Hideable |
|
||||
ImGuiTableFlags_Borders |
|
||||
ImGuiTableFlags_Resizable;
|
||||
|
||||
match = DictionaryElement.MatchMe(str);
|
||||
if (match.size() > 0) {
|
||||
return ParsedElement(DictionaryElement,
|
||||
DICTOFF + std::stoi(match[1].str(), nullptr, 16));
|
||||
}
|
||||
return ParsedElement();
|
||||
}
|
||||
|
||||
static string ReplaceAllDictionaryWords(string str) {
|
||||
string temp = str;
|
||||
for (const auto& entry : AllDictionaries) {
|
||||
if (absl::StrContains(temp, entry.Contents)) {
|
||||
temp = absl::StrReplaceAll(temp, {{entry.Contents, entry.Contents}});
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> ParseMessageToData(string str) {
|
||||
std::vector<uint8_t> bytes;
|
||||
string tempString = str;
|
||||
int pos = 0;
|
||||
|
||||
while (pos < tempString.size()) {
|
||||
// Get next text fragment.
|
||||
if (tempString[pos] == '[') {
|
||||
int next = tempString.find(']', pos);
|
||||
if (next == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
ParsedElement parsedElement =
|
||||
FindMatchingElement(tempString.substr(pos, next - pos + 1));
|
||||
if (!parsedElement.Active) {
|
||||
break; // TODO: handle badness.
|
||||
// } else if (parsedElement.Parent == DictionaryElement) {
|
||||
// bytes.push_back(parsedElement.Value);
|
||||
} else {
|
||||
bytes.push_back(parsedElement.Parent.ID);
|
||||
|
||||
if (parsedElement.Parent.HasArgument) {
|
||||
bytes.push_back(parsedElement.Value);
|
||||
}
|
||||
}
|
||||
|
||||
pos = next + 1;
|
||||
continue;
|
||||
} else {
|
||||
uint8_t bb = MessageEditor::FindMatchingCharacter(tempString[pos++]);
|
||||
|
||||
if (bb != 0xFF) {
|
||||
// TODO: handle badness.
|
||||
bytes.push_back(bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
absl::Status MessageEditor::Update() {
|
||||
if (rom()->is_loaded() && !data_loaded_) {
|
||||
RETURN_IF_ERROR(Initialize());
|
||||
CurrentMessage = ListOfTexts[1];
|
||||
data_loaded_ = true;
|
||||
}
|
||||
|
||||
if (BeginTable("##MessageEditor", 3,
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) {
|
||||
TableSetupColumn("List");
|
||||
TableSetupColumn("Contents");
|
||||
TableSetupColumn("Commands");
|
||||
|
||||
TableHeadersRow();
|
||||
|
||||
TableNextColumn();
|
||||
DrawMessageList();
|
||||
|
||||
TableNextColumn();
|
||||
DrawCurrentMessage();
|
||||
|
||||
TableNextColumn();
|
||||
DrawTextCommands();
|
||||
|
||||
EndTable();
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void MessageEditor::DrawMessageList() {
|
||||
if (InputText("Search", &search_text_)) {
|
||||
DisplayedMessages.clear();
|
||||
for (const auto& message : ListOfTexts) {
|
||||
if (absl::StrContains(message.ContentsParsed, search_text_)) {
|
||||
DisplayedMessages.push_back(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BeginChild("##MessagesList", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
if (BeginTable("##MessagesTable", 3,
|
||||
ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders |
|
||||
ImGuiTableFlags_Resizable)) {
|
||||
TableSetupColumn("ID");
|
||||
TableSetupColumn("Contents");
|
||||
TableSetupColumn("Data");
|
||||
|
||||
TableHeadersRow();
|
||||
|
||||
for (const auto& message : ListOfTexts) {
|
||||
TableNextColumn();
|
||||
if (Button(core::UppercaseHexWord(message.ID).c_str())) {
|
||||
CurrentMessage = message;
|
||||
DrawMessagePreview();
|
||||
}
|
||||
TableNextColumn();
|
||||
TextWrapped("%s", ParsedMessages[message.ID].c_str());
|
||||
TableNextColumn();
|
||||
TextWrapped(
|
||||
"%s",
|
||||
core::UppercaseHexLong(ListOfTexts[message.ID].Address).c_str());
|
||||
}
|
||||
|
||||
EndTable();
|
||||
}
|
||||
EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageEditor::DrawCurrentMessage() {
|
||||
Button(absl::StrCat("Message ", CurrentMessage.ID).c_str());
|
||||
if (InputTextMultiline("##MessageEditor", &ParsedMessages[CurrentMessage.ID],
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
|
||||
CurrentMessage.Data = ParseMessageToData(message_text_box_.text);
|
||||
DrawMessagePreview();
|
||||
}
|
||||
Separator();
|
||||
|
||||
Text("Font Graphics");
|
||||
gui::BeginPadding(1);
|
||||
BeginChild("MessageEditorCanvas", ImVec2(0, 130));
|
||||
font_gfx_canvas_.DrawBackground();
|
||||
font_gfx_canvas_.DrawContextMenu();
|
||||
font_gfx_canvas_.DrawBitmap(font_gfx_bitmap_, 0, 0);
|
||||
font_gfx_canvas_.DrawGrid();
|
||||
font_gfx_canvas_.DrawOverlay();
|
||||
EndChild();
|
||||
gui::EndPadding();
|
||||
Separator();
|
||||
|
||||
Text("Message Preview");
|
||||
if (Button("Refresh Bitmap")) {
|
||||
rom()->UpdateBitmap(¤t_font_gfx16_bitmap_);
|
||||
}
|
||||
gui::BeginPadding(1);
|
||||
BeginChild("CurrentGfxFont", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
current_font_gfx16_canvas_.DrawBackground();
|
||||
gui::EndPadding();
|
||||
current_font_gfx16_canvas_.DrawContextMenu();
|
||||
current_font_gfx16_canvas_.DrawBitmap(current_font_gfx16_bitmap_, 0, 0);
|
||||
current_font_gfx16_canvas_.DrawGrid();
|
||||
current_font_gfx16_canvas_.DrawOverlay();
|
||||
EndChild();
|
||||
}
|
||||
|
||||
void MessageEditor::DrawTextCommands() {
|
||||
if (BeginChild("##TextCommands", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
for (const auto& text_element : TextCommands) {
|
||||
if (Button(text_element.GenericToken.c_str())) {
|
||||
}
|
||||
SameLine();
|
||||
TextWrapped("%s", text_element.Description.c_str());
|
||||
Separator();
|
||||
}
|
||||
EndChild();
|
||||
}
|
||||
}
|
||||
constexpr ImGuiTableFlags kDictTableFlags =
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable;
|
||||
|
||||
absl::Status MessageEditor::Initialize() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
for (int i = 0; i < kWidthArraySize; i++) {
|
||||
width_array[i] = rom()->data()[kCharactersWidth + i];
|
||||
}
|
||||
|
||||
BuildDictionaryEntries();
|
||||
ReadAllTextData();
|
||||
all_dictionaries_ = BuildDictionaryEntries(rom());
|
||||
ReadAllTextDataV2();
|
||||
|
||||
font_preview_colors_.AddColor(0x7FFF); // White
|
||||
font_preview_colors_.AddColor(0x7C00); // Red
|
||||
@@ -257,21 +61,23 @@ absl::Status MessageEditor::Initialize() {
|
||||
for (int i = 0; i < 0x4000; i++) {
|
||||
data[i] = rom()->data()[kGfxFont + i];
|
||||
}
|
||||
font_gfx16_data = gfx::SnesTo8bppSheet(data, /*bpp=*/2);
|
||||
font_gfx16_data_ = gfx::SnesTo8bppSheet(data, /*bpp=*/2, /*num_sheets=*/2);
|
||||
|
||||
// 4bpp
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
|
||||
128, 128, 8, font_gfx16_data, font_gfx_bitmap_, font_preview_colors_))
|
||||
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
|
||||
kFontGfxMessageSize, kFontGfxMessageSize, kFontGfxMessageDepth,
|
||||
font_gfx16_data_, font_gfx_bitmap_, font_preview_colors_))
|
||||
|
||||
current_font_gfx16_data_.reserve(172 * 4096);
|
||||
for (int i = 0; i < 172 * 4096; i++) {
|
||||
current_font_gfx16_data_.reserve(kCurrentMessageWidth *
|
||||
kCurrentMessageHeight);
|
||||
for (int i = 0; i < kCurrentMessageWidth * kCurrentMessageHeight; i++) {
|
||||
current_font_gfx16_data_.push_back(0);
|
||||
}
|
||||
|
||||
// 8bpp
|
||||
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
|
||||
172, 4096, 64, current_font_gfx16_data_, current_font_gfx16_bitmap_,
|
||||
font_preview_colors_))
|
||||
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
|
||||
kCurrentMessageWidth, kCurrentMessageHeight, 64, current_font_gfx16_data_,
|
||||
current_font_gfx16_bitmap_, font_preview_colors_))
|
||||
|
||||
gfx::SnesPalette color_palette = font_gfx_bitmap_.palette();
|
||||
for (int i = 0; i < font_preview_colors_.size(); i++) {
|
||||
@@ -280,11 +86,11 @@ absl::Status MessageEditor::Initialize() {
|
||||
|
||||
*font_gfx_bitmap_.mutable_palette() = color_palette;
|
||||
|
||||
for (const auto& message : ListOfTexts) {
|
||||
DisplayedMessages.push_back(message);
|
||||
}
|
||||
for (const auto& each_message : list_of_texts_) {
|
||||
std::cout << "Message #" << each_message.ID << " at address "
|
||||
<< core::UppercaseHexLong(each_message.Address) << std::endl;
|
||||
std::cout << " " << each_message.RawString << std::endl;
|
||||
|
||||
for (const auto& each_message : ListOfTexts) {
|
||||
// Each string has a [:XX] char encoded
|
||||
// The corresponding character is found in CharEncoder unordered_map
|
||||
std::string parsed_message = "";
|
||||
@@ -313,7 +119,8 @@ absl::Status MessageEditor::Initialize() {
|
||||
}
|
||||
}
|
||||
}
|
||||
ParsedMessages.push_back(parsed_message);
|
||||
std::cout << " > " << parsed_message << std::endl;
|
||||
parsed_messages_.push_back(parsed_message);
|
||||
}
|
||||
|
||||
DrawMessagePreview();
|
||||
@@ -321,38 +128,245 @@ absl::Status MessageEditor::Initialize() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void MessageEditor::BuildDictionaryEntries() {
|
||||
for (int i = 0; i < 97; i++) {
|
||||
std::vector<uint8_t> bytes;
|
||||
std::stringstream stringBuilder;
|
||||
|
||||
int address = core::SnesToPc(
|
||||
0x0E0000 + (rom()->data()[kPointersDictionaries + (i * 2) + 1] << 8) +
|
||||
rom()->data()[kPointersDictionaries + (i * 2)]);
|
||||
|
||||
int temppush_backress = core::SnesToPc(
|
||||
0x0E0000 +
|
||||
(rom()->data()[kPointersDictionaries + ((i + 1) * 2) + 1] << 8) +
|
||||
rom()->data()[kPointersDictionaries + ((i + 1) * 2)]);
|
||||
|
||||
while (address < temppush_backress) {
|
||||
uint8_t uint8_tDictionary = rom()->data()[address++];
|
||||
bytes.push_back(uint8_tDictionary);
|
||||
stringBuilder << ParseTextDataByte(uint8_tDictionary);
|
||||
}
|
||||
|
||||
// AllDictionaries[i] = DictionaryEntry{(uint8_t)i, stringBuilder.str()};
|
||||
AllDictionaries.push_back(DictionaryEntry{(uint8_t)i, stringBuilder.str()});
|
||||
absl::Status MessageEditor::Update() {
|
||||
if (rom()->is_loaded() && !data_loaded_) {
|
||||
RETURN_IF_ERROR(Initialize());
|
||||
current_message_ = list_of_texts_[1];
|
||||
data_loaded_ = true;
|
||||
}
|
||||
|
||||
// AllDictionaries.OrderByDescending(dictionary = > dictionary.Length);
|
||||
AllDictionaries[0].Length = 0;
|
||||
if (BeginTable("##MessageEditor", 4, kDictTableFlags)) {
|
||||
TableSetupColumn("List");
|
||||
TableSetupColumn("Contents");
|
||||
TableSetupColumn("Commands");
|
||||
TableSetupColumn("Dictionary");
|
||||
|
||||
TableHeadersRow();
|
||||
|
||||
TableNextColumn();
|
||||
DrawMessageList();
|
||||
|
||||
TableNextColumn();
|
||||
DrawCurrentMessage();
|
||||
|
||||
TableNextColumn();
|
||||
DrawTextCommands();
|
||||
|
||||
TableNextColumn();
|
||||
DrawDictionary();
|
||||
|
||||
EndTable();
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void MessageEditor::DrawMessageList() {
|
||||
if (InputText("Search", &search_text_)) {
|
||||
// TODO: ImGui style text filtering
|
||||
}
|
||||
|
||||
if (BeginChild("##MessagesList", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
if (BeginTable("##MessagesTable", 3, kMessageTableFlags)) {
|
||||
TableSetupColumn("ID");
|
||||
TableSetupColumn("Contents");
|
||||
TableSetupColumn("Data");
|
||||
|
||||
TableHeadersRow();
|
||||
|
||||
for (const auto& message : list_of_texts_) {
|
||||
TableNextColumn();
|
||||
if (Button(core::UppercaseHexWord(message.ID).c_str())) {
|
||||
current_message_ = message;
|
||||
DrawMessagePreview();
|
||||
}
|
||||
TableNextColumn();
|
||||
TextWrapped("%s", parsed_messages_[message.ID].c_str());
|
||||
TableNextColumn();
|
||||
TextWrapped(
|
||||
"%s",
|
||||
core::UppercaseHexLong(list_of_texts_[message.ID].Address).c_str());
|
||||
}
|
||||
|
||||
EndTable();
|
||||
}
|
||||
EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageEditor::DrawCurrentMessage() {
|
||||
Button(absl::StrCat("Message ", current_message_.ID).c_str());
|
||||
if (InputTextMultiline("##MessageEditor",
|
||||
&parsed_messages_[current_message_.ID],
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
|
||||
current_message_.Data = ParseMessageToData(message_text_box_.text);
|
||||
DrawMessagePreview();
|
||||
}
|
||||
Separator();
|
||||
|
||||
Text("Font Graphics");
|
||||
gui::BeginPadding(1);
|
||||
BeginChild("MessageEditorCanvas", ImVec2(0, 130));
|
||||
font_gfx_canvas_.DrawBackground();
|
||||
font_gfx_canvas_.DrawContextMenu();
|
||||
font_gfx_canvas_.DrawBitmap(font_gfx_bitmap_, 0, 0);
|
||||
font_gfx_canvas_.DrawGrid();
|
||||
font_gfx_canvas_.DrawOverlay();
|
||||
EndChild();
|
||||
gui::EndPadding();
|
||||
Separator();
|
||||
|
||||
Text("Message Preview");
|
||||
if (Button("Refresh Bitmap")) {
|
||||
Renderer::GetInstance().UpdateBitmap(¤t_font_gfx16_bitmap_);
|
||||
}
|
||||
gui::BeginPadding(1);
|
||||
BeginChild("CurrentGfxFont", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
current_font_gfx16_canvas_.DrawBackground();
|
||||
gui::EndPadding();
|
||||
current_font_gfx16_canvas_.DrawContextMenu();
|
||||
current_font_gfx16_canvas_.DrawBitmap(current_font_gfx16_bitmap_, 0, 0);
|
||||
current_font_gfx16_canvas_.DrawGrid();
|
||||
current_font_gfx16_canvas_.DrawOverlay();
|
||||
EndChild();
|
||||
}
|
||||
|
||||
void MessageEditor::DrawTextCommands() {
|
||||
if (BeginChild("##TextCommands", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
for (const auto& text_element : TextCommands) {
|
||||
if (Button(text_element.GenericToken.c_str())) {
|
||||
}
|
||||
SameLine();
|
||||
TextWrapped("%s", text_element.Description.c_str());
|
||||
Separator();
|
||||
}
|
||||
EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageEditor::DrawDictionary() {
|
||||
if (ImGui::BeginChild("##DictionaryChild", ImVec2(0, 0), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
if (BeginTable("##Dictionary", 2, kDictTableFlags)) {
|
||||
TableSetupColumn("ID");
|
||||
TableSetupColumn("Contents");
|
||||
|
||||
for (const auto& dictionary : all_dictionaries_) {
|
||||
TableNextColumn();
|
||||
Text("%s", core::UppercaseHexWord(dictionary.ID).c_str());
|
||||
TableNextColumn();
|
||||
Text("%s", dictionary.Contents.c_str());
|
||||
}
|
||||
EndTable();
|
||||
}
|
||||
|
||||
EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Fix the command parsing.
|
||||
void MessageEditor::ReadAllTextDataV2() {
|
||||
// Read all text data from the ROM.
|
||||
int pos = kTextData;
|
||||
int message_id = 0;
|
||||
|
||||
std::vector<uint8_t> raw_message;
|
||||
std::vector<uint8_t> parsed_message;
|
||||
|
||||
std::string current_raw_message;
|
||||
std::string current_parsed_message;
|
||||
|
||||
uint8_t current_byte = 0;
|
||||
while (current_byte != 0xFF) {
|
||||
current_byte = rom()->data()[pos++];
|
||||
if (current_byte == kMessageTerminator) {
|
||||
auto message =
|
||||
MessageData(message_id++, pos, current_raw_message, raw_message,
|
||||
current_parsed_message, parsed_message);
|
||||
|
||||
list_of_texts_.push_back(message);
|
||||
|
||||
raw_message.clear();
|
||||
parsed_message.clear();
|
||||
current_raw_message.clear();
|
||||
current_parsed_message.clear();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
raw_message.push_back(current_byte);
|
||||
|
||||
// Check for command.
|
||||
TextElement text_element = FindMatchingCommand(current_byte);
|
||||
if (!text_element.Empty()) {
|
||||
parsed_message.push_back(current_byte);
|
||||
if (text_element.HasArgument) {
|
||||
current_byte = rom()->data()[pos++];
|
||||
raw_message.push_back(current_byte);
|
||||
parsed_message.push_back(current_byte);
|
||||
}
|
||||
|
||||
current_raw_message.append(
|
||||
text_element.GetParameterizedToken(current_byte));
|
||||
current_parsed_message.append(
|
||||
text_element.GetParameterizedToken(current_byte));
|
||||
|
||||
if (text_element.Token == BANKToken) {
|
||||
pos = kTextData2;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for special characters.
|
||||
text_element = FindMatchingSpecial(current_byte);
|
||||
if (!text_element.Empty()) {
|
||||
current_raw_message.append(text_element.GetParameterizedToken());
|
||||
current_parsed_message.append(text_element.GetParameterizedToken());
|
||||
parsed_message.push_back(current_byte);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for dictionary.
|
||||
int dictionary = FindDictionaryEntry(current_byte);
|
||||
if (dictionary >= 0) {
|
||||
current_raw_message.append("[");
|
||||
current_raw_message.append(DICTIONARYTOKEN);
|
||||
current_raw_message.append(":");
|
||||
current_raw_message.append(core::UppercaseHexWord(dictionary));
|
||||
current_raw_message.append("]");
|
||||
|
||||
uint32_t address = core::Get24LocalFromPC(
|
||||
rom()->data(), kPointersDictionaries + (dictionary * 2));
|
||||
uint32_t address_end = core::Get24LocalFromPC(
|
||||
rom()->data(), kPointersDictionaries + ((dictionary + 1) * 2));
|
||||
|
||||
for (uint32_t i = address; i < address_end; i++) {
|
||||
parsed_message.push_back(rom()->data()[i]);
|
||||
current_parsed_message.append(ParseTextDataByte(rom()->data()[i]));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Everything else.
|
||||
if (CharEncoder.contains(current_byte)) {
|
||||
std::string str = "";
|
||||
str.push_back(CharEncoder.at(current_byte));
|
||||
current_raw_message.append(str);
|
||||
current_parsed_message.append(str);
|
||||
parsed_message.push_back(current_byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageEditor::ReadAllTextData() {
|
||||
int messageID = 0;
|
||||
uint8_t current_byte;
|
||||
int pos = kTextData;
|
||||
int message_id = 0;
|
||||
uint8_t current_byte;
|
||||
std::vector<uint8_t> temp_bytes_raw;
|
||||
std::vector<uint8_t> temp_bytes_parsed;
|
||||
|
||||
@@ -363,12 +377,12 @@ void MessageEditor::ReadAllTextData() {
|
||||
while (true) {
|
||||
current_byte = rom()->data()[pos++];
|
||||
|
||||
if (current_byte == MESSAGETERMINATOR) {
|
||||
if (current_byte == kMessageTerminator) {
|
||||
auto message =
|
||||
MessageData(messageID++, pos, current_message_raw, temp_bytes_raw,
|
||||
MessageData(message_id++, pos, current_message_raw, temp_bytes_raw,
|
||||
current_message_parsed, temp_bytes_parsed);
|
||||
|
||||
ListOfTexts.push_back(message);
|
||||
list_of_texts_.push_back(message);
|
||||
|
||||
temp_bytes_raw.clear();
|
||||
temp_bytes_parsed.clear();
|
||||
@@ -407,7 +421,6 @@ void MessageEditor::ReadAllTextData() {
|
||||
|
||||
// Check for special characters.
|
||||
text_element = FindMatchingSpecial(current_byte);
|
||||
|
||||
if (!text_element.Empty()) {
|
||||
current_message_raw.append(text_element.GetParameterizedToken());
|
||||
current_message_parsed.append(text_element.GetParameterizedToken());
|
||||
@@ -449,83 +462,29 @@ void MessageEditor::ReadAllTextData() {
|
||||
}
|
||||
}
|
||||
|
||||
TextElement MessageEditor::FindMatchingCommand(uint8_t b) {
|
||||
TextElement empty_element;
|
||||
for (const auto text_element : TextCommands) {
|
||||
if (text_element.ID == b) {
|
||||
return text_element;
|
||||
std::string ReplaceAllDictionaryWords(std::string str,
|
||||
std::vector<DictionaryEntry> dictionary) {
|
||||
std::string temp = str;
|
||||
for (const auto& entry : dictionary) {
|
||||
if (absl::StrContains(temp, entry.Contents)) {
|
||||
temp = absl::StrReplaceAll(temp, {{entry.Contents, entry.Contents}});
|
||||
}
|
||||
}
|
||||
return empty_element;
|
||||
return temp;
|
||||
}
|
||||
|
||||
TextElement MessageEditor::FindMatchingSpecial(uint8_t value) {
|
||||
TextElement empty_element;
|
||||
for (const auto text_element : SpecialChars) {
|
||||
if (text_element.ID == value) {
|
||||
return text_element;
|
||||
}
|
||||
}
|
||||
return empty_element;
|
||||
}
|
||||
|
||||
MessageEditor::DictionaryEntry MessageEditor::GetDictionaryFromID(
|
||||
uint8_t value) {
|
||||
if (value < 0 || value >= AllDictionaries.size()) {
|
||||
DictionaryEntry MessageEditor::GetDictionaryFromID(uint8_t value) {
|
||||
if (value < 0 || value >= all_dictionaries_.size()) {
|
||||
return DictionaryEntry();
|
||||
}
|
||||
return AllDictionaries[value];
|
||||
}
|
||||
|
||||
uint8_t MessageEditor::FindDictionaryEntry(uint8_t value) {
|
||||
if (value < DICTOFF || value == 0xFF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return value - DICTOFF;
|
||||
}
|
||||
|
||||
uint8_t MessageEditor::FindMatchingCharacter(char value) {
|
||||
for (const auto [key, char_value] : CharEncoder) {
|
||||
if (value == char_value) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
string MessageEditor::ParseTextDataByte(uint8_t value) {
|
||||
if (CharEncoder.contains(value)) {
|
||||
char c = CharEncoder.at(value);
|
||||
string str = "";
|
||||
str.push_back(c);
|
||||
return str;
|
||||
}
|
||||
|
||||
// Check for command.
|
||||
TextElement textElement = FindMatchingCommand(value);
|
||||
if (!textElement.Empty()) {
|
||||
return textElement.GenericToken;
|
||||
}
|
||||
|
||||
// Check for special characters.
|
||||
textElement = FindMatchingSpecial(value);
|
||||
if (!textElement.Empty()) {
|
||||
return textElement.GenericToken;
|
||||
}
|
||||
|
||||
// Check for dictionary.
|
||||
int dictionary = FindDictionaryEntry(value);
|
||||
if (dictionary >= 0) {
|
||||
return absl::StrFormat("[%s:%X]", DICTIONARYTOKEN, dictionary);
|
||||
}
|
||||
|
||||
return "";
|
||||
return all_dictionaries_[value];
|
||||
}
|
||||
|
||||
void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
|
||||
int sizex, int sizey) {
|
||||
int drawid = srcx + (srcy * 32);
|
||||
const int num_x_tiles = 16;
|
||||
const int img_width = 512; // (imgwidth/2)
|
||||
int draw_id = srcx + (srcy * 32);
|
||||
for (int yl = 0; yl < sizey * 8; yl++) {
|
||||
for (int xl = 0; xl < 4; xl++) {
|
||||
int mx = xl;
|
||||
@@ -533,8 +492,9 @@ void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
|
||||
|
||||
// Formula information to get tile index position in the array.
|
||||
// ((ID / nbrofXtiles) * (imgwidth/2) + (ID - ((ID/16)*16) ))
|
||||
int tx = ((drawid / 16) * 512) + ((drawid - ((drawid / 16) * 16)) * 4);
|
||||
uint8_t pixel = font_gfx16_data[tx + (yl * 64) + xl];
|
||||
int tx = ((draw_id / num_x_tiles) * img_width) +
|
||||
((draw_id - ((draw_id / 16) * 16)) * 4);
|
||||
uint8_t pixel = font_gfx16_data_[tx + (yl * 64) + xl];
|
||||
|
||||
// nx,ny = object position, xx,yy = tile position, xl,yl = pixel
|
||||
// position
|
||||
@@ -552,7 +512,7 @@ void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
|
||||
}
|
||||
}
|
||||
|
||||
void MessageEditor::DrawStringToPreview(string str) {
|
||||
void MessageEditor::DrawStringToPreview(std::string str) {
|
||||
for (const auto c : str) {
|
||||
DrawCharacterToPreview(c);
|
||||
}
|
||||
@@ -573,25 +533,25 @@ void MessageEditor::DrawCharacterToPreview(const std::vector<uint8_t>& text) {
|
||||
int srcy = value / 16;
|
||||
int srcx = value - (value & (~0xF));
|
||||
|
||||
if (text_pos >= 170) {
|
||||
text_pos = 0;
|
||||
text_line++;
|
||||
if (text_position_ >= 170) {
|
||||
text_position_ = 0;
|
||||
text_line_++;
|
||||
}
|
||||
|
||||
DrawTileToPreview(text_pos, text_line * 16, srcx, srcy, 0, 1, 2);
|
||||
text_pos += width_array[value];
|
||||
DrawTileToPreview(text_position_, text_line_ * 16, srcx, srcy, 0, 1, 2);
|
||||
text_position_ += width_array[value];
|
||||
} else if (value == kLine1) {
|
||||
text_pos = 0;
|
||||
text_line = 0;
|
||||
text_position_ = 0;
|
||||
text_line_ = 0;
|
||||
} else if (value == kScrollVertical) {
|
||||
text_pos = 0;
|
||||
text_line += 1;
|
||||
text_position_ = 0;
|
||||
text_line_ += 1;
|
||||
} else if (value == kLine2) {
|
||||
text_pos = 0;
|
||||
text_line = 1;
|
||||
text_position_ = 0;
|
||||
text_line_ = 1;
|
||||
} else if (value == kLine3) {
|
||||
text_pos = 0;
|
||||
text_line = 2;
|
||||
text_position_ = 0;
|
||||
text_line_ = 2;
|
||||
} else if (value == 0x6B || value == 0x6D || value == 0x6E ||
|
||||
value == 0x77 || value == 0x78 || value == 0x79 ||
|
||||
value == 0x7A) {
|
||||
@@ -615,15 +575,15 @@ void MessageEditor::DrawCharacterToPreview(const std::vector<uint8_t>& text) {
|
||||
}
|
||||
}
|
||||
|
||||
void MessageEditor::DrawMessagePreview() // From Parsing.
|
||||
{
|
||||
text_line = 0;
|
||||
void MessageEditor::DrawMessagePreview() {
|
||||
// From Parsing.
|
||||
text_line_ = 0;
|
||||
for (int i = 0; i < (172 * 4096); i++) {
|
||||
current_font_gfx16_data_[i] = 0;
|
||||
}
|
||||
text_pos = 0;
|
||||
DrawCharacterToPreview(CurrentMessage.Data);
|
||||
shown_lines = 0;
|
||||
text_position_ = 0;
|
||||
DrawCharacterToPreview(current_message_.Data);
|
||||
shown_lines_ = 0;
|
||||
}
|
||||
|
||||
absl::Status MessageEditor::Cut() {
|
||||
@@ -675,7 +635,7 @@ absl::Status MessageEditor::Save() {
|
||||
int pos = kTextData;
|
||||
bool in_second_bank = false;
|
||||
|
||||
for (const auto& message : ListOfTexts) {
|
||||
for (const auto& message : list_of_texts_) {
|
||||
for (const auto value : message.Data) {
|
||||
RETURN_IF_ERROR(rom()->Write(pos, value));
|
||||
|
||||
@@ -695,7 +655,7 @@ absl::Status MessageEditor::Save() {
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(
|
||||
rom()->Write(pos++, MESSAGETERMINATOR)); // , true, "Terminator text"
|
||||
rom()->Write(pos++, kMessageTerminator)); // , true, "Terminator text"
|
||||
}
|
||||
|
||||
// Verify that we didn't go over the space available for the second block.
|
||||
@@ -712,9 +672,10 @@ absl::Status MessageEditor::Save() {
|
||||
|
||||
std::string MessageEditor::DisplayTextOverflowError(int pos, bool bank) {
|
||||
int space = bank ? kTextDataEnd - kTextData : kTextData2End - kTextData2;
|
||||
string bankSTR = bank ? "1st" : "2nd";
|
||||
string posSTR = bank ? absl::StrFormat("%X4", pos & 0xFFFF)
|
||||
: absl::StrFormat("%X4", (pos - kTextData2) & 0xFFFF);
|
||||
std::string bankSTR = bank ? "1st" : "2nd";
|
||||
std::string posSTR =
|
||||
bank ? absl::StrFormat("%X4", pos & 0xFFFF)
|
||||
: absl::StrFormat("%X4", (pos - kTextData2) & 0xFFFF);
|
||||
std::string message = absl::StrFormat(
|
||||
"There is too much text data in the %s block to save.\n"
|
||||
"Available: %X4 | Used: %s",
|
||||
@@ -722,30 +683,6 @@ std::string MessageEditor::DisplayTextOverflowError(int pos, bool bank) {
|
||||
return message;
|
||||
}
|
||||
|
||||
// push_backs a command to the text field when the push_back command button is
|
||||
// pressed or the command is double clicked in the list.
|
||||
void MessageEditor::InsertCommandButton_Click_1() {
|
||||
// InsertSelectedText(
|
||||
// TextCommands[TextCommandList.SelectedIndex].GetParameterizedToken(
|
||||
// (uint8_t)ParamsBox.HexValue));
|
||||
}
|
||||
|
||||
// push_backs a special character to the text field when the push_back command
|
||||
// button is pressed or the character is double clicked in the list.
|
||||
void MessageEditor::InsertSpecialButton_Click() {
|
||||
// InsertSelectedText(
|
||||
// SpecialChars[SpecialsList.SelectedIndex].GetParameterizedToken());
|
||||
}
|
||||
|
||||
void MessageEditor::InsertSelectedText(string str) {
|
||||
int textboxPos = message_text_box_.selection_start;
|
||||
from_form = true;
|
||||
// message_text_box_.Text = message_text_box_.Text.Insert(textboxPos, str);
|
||||
from_form = false;
|
||||
message_text_box_.selection_start = textboxPos + str.size();
|
||||
message_text_box_.Focus();
|
||||
}
|
||||
|
||||
void MessageEditor::Delete() {
|
||||
// Determine if any text is selected in the TextBox control.
|
||||
if (message_text_box_.selection_length == 0) {
|
||||
|
||||
@@ -1,229 +1,54 @@
|
||||
#ifndef YAZE_APP_EDITOR_MESSAGE_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_MESSAGE_EDITOR_H
|
||||
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "app/editor/message/message_data.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
using std::string;
|
||||
|
||||
// TEXT EDITOR RELATED CONSTANTS
|
||||
const int kGfxFont = 0x70000; // 2bpp format
|
||||
const int kTextData = 0xE0000;
|
||||
const int kTextDataEnd = 0xE7FFF;
|
||||
const int kTextData2 = 0x75F40;
|
||||
const int kTextData2End = 0x773FF;
|
||||
const int kPointersDictionaries = 0x74703;
|
||||
const int kCharactersWidth = 0x74ADF;
|
||||
|
||||
const string DICTIONARYTOKEN = "D";
|
||||
const uint8_t DICTOFF = 0x88;
|
||||
const string BANKToken = "BANK";
|
||||
const uint8_t BANKID = 0x80;
|
||||
constexpr int kGfxFont = 0x70000; // 2bpp format
|
||||
constexpr int kTextData2 = 0x75F40;
|
||||
constexpr int kTextData2End = 0x773FF;
|
||||
constexpr int kCharactersWidth = 0x74ADF;
|
||||
constexpr int kNumMessages = 396;
|
||||
constexpr int kCurrentMessageWidth = 172;
|
||||
constexpr int kCurrentMessageHeight = 4096;
|
||||
constexpr int kFontGfxMessageSize = 128;
|
||||
constexpr int kFontGfxMessageDepth = 8;
|
||||
|
||||
constexpr uint8_t kWidthArraySize = 100;
|
||||
constexpr uint8_t kBlockTerminator = 0x80;
|
||||
|
||||
static std::vector<uint8_t> ParseMessageToData(string str);
|
||||
|
||||
static ParsedElement FindMatchingElement(string str);
|
||||
|
||||
constexpr uint8_t kMessageBankChangeId = 0x80;
|
||||
constexpr uint8_t kScrollVertical = 0x73;
|
||||
constexpr uint8_t kLine1 = 0x74;
|
||||
constexpr uint8_t kLine2 = 0x75;
|
||||
constexpr uint8_t kLine3 = 0x76;
|
||||
|
||||
static const TextElement TextCommands[] = {
|
||||
TextElement(0x6B, "W", true, "Window border"),
|
||||
TextElement(0x6D, "P", true, "Window position"),
|
||||
TextElement(0x6E, "SPD", true, "Scroll speed"),
|
||||
TextElement(0x7A, "S", true, "Text draw speed"),
|
||||
TextElement(0x77, "C", true, "Text color"),
|
||||
TextElement(0x6A, "L", false, "Player name"),
|
||||
TextElement(0x74, "1", false, "Line 1"),
|
||||
TextElement(0x75, "2", false, "Line 2"),
|
||||
TextElement(0x76, "3", false, "Line 3"),
|
||||
TextElement(0x7E, "K", false, "Wait for key"),
|
||||
TextElement(0x73, "V", false, "Scroll text"),
|
||||
TextElement(0x78, "WT", true, "Delay X"),
|
||||
TextElement(0x6C, "N", true, "BCD number"),
|
||||
TextElement(0x79, "SFX", true, "Sound effect"),
|
||||
TextElement(0x71, "CH3", false, "Choose 3"),
|
||||
TextElement(0x72, "CH2", false, "Choose 2 high"),
|
||||
TextElement(0x6F, "CH2L", false, "Choose 2 low"),
|
||||
TextElement(0x68, "CH2I", false, "Choose 2 indented"),
|
||||
TextElement(0x69, "CHI", false, "Choose item"),
|
||||
TextElement(0x67, "IMG", false, "Next attract image"),
|
||||
TextElement(0x80, BANKToken, false, "Bank marker (automatic)"),
|
||||
TextElement(0x70, "NONO", false, "Crash"),
|
||||
};
|
||||
|
||||
static std::vector<TextElement> SpecialChars = {
|
||||
TextElement(0x43, "...", false, "Ellipsis …"),
|
||||
TextElement(0x4D, "UP", false, "Arrow ↑"),
|
||||
TextElement(0x4E, "DOWN", false, "Arrow ↓"),
|
||||
TextElement(0x4F, "LEFT", false, "Arrow ←"),
|
||||
TextElement(0x50, "RIGHT", false, "Arrow →"),
|
||||
TextElement(0x5B, "A", false, "Button Ⓐ"),
|
||||
TextElement(0x5C, "B", false, "Button Ⓑ"),
|
||||
TextElement(0x5D, "X", false, "Button ⓧ"),
|
||||
TextElement(0x5E, "Y", false, "Button ⓨ"),
|
||||
TextElement(0x52, "HP1L", false, "1 HP left"),
|
||||
TextElement(0x53, "HP1R", false, "1 HP right"),
|
||||
TextElement(0x54, "HP2L", false, "2 HP left"),
|
||||
TextElement(0x55, "HP3L", false, "3 HP left"),
|
||||
TextElement(0x56, "HP3R", false, "3 HP right"),
|
||||
TextElement(0x57, "HP4L", false, "4 HP left"),
|
||||
TextElement(0x58, "HP4R", false, "4 HP right"),
|
||||
TextElement(0x47, "HY0", false, "Hieroglyph ☥"),
|
||||
TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"),
|
||||
TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"),
|
||||
TextElement(0x4A, "LFL", false, "Link face left"),
|
||||
TextElement(0x4B, "LFR", false, "Link face right"),
|
||||
};
|
||||
|
||||
static const std::unordered_map<uint8_t, wchar_t> CharEncoder = {
|
||||
{0x00, 'A'},
|
||||
{0x01, 'B'},
|
||||
{0x02, 'C'},
|
||||
{0x03, 'D'},
|
||||
{0x04, 'E'},
|
||||
{0x05, 'F'},
|
||||
{0x06, 'G'},
|
||||
{0x07, 'H'},
|
||||
{0x08, 'I'},
|
||||
{0x09, 'J'},
|
||||
{0x0A, 'K'},
|
||||
{0x0B, 'L'},
|
||||
{0x0C, 'M'},
|
||||
{0x0D, 'N'},
|
||||
{0x0E, 'O'},
|
||||
{0x0F, 'P'},
|
||||
{0x10, 'Q'},
|
||||
{0x11, 'R'},
|
||||
{0x12, 'S'},
|
||||
{0x13, 'T'},
|
||||
{0x14, 'U'},
|
||||
{0x15, 'V'},
|
||||
{0x16, 'W'},
|
||||
{0x17, 'X'},
|
||||
{0x18, 'Y'},
|
||||
{0x19, 'Z'},
|
||||
{0x1A, 'a'},
|
||||
{0x1B, 'b'},
|
||||
{0x1C, 'c'},
|
||||
{0x1D, 'd'},
|
||||
{0x1E, 'e'},
|
||||
{0x1F, 'f'},
|
||||
{0x20, 'g'},
|
||||
{0x21, 'h'},
|
||||
{0x22, 'i'},
|
||||
{0x23, 'j'},
|
||||
{0x24, 'k'},
|
||||
{0x25, 'l'},
|
||||
{0x26, 'm'},
|
||||
{0x27, 'n'},
|
||||
{0x28, 'o'},
|
||||
{0x29, 'p'},
|
||||
{0x2A, 'q'},
|
||||
{0x2B, 'r'},
|
||||
{0x2C, 's'},
|
||||
{0x2D, 't'},
|
||||
{0x2E, 'u'},
|
||||
{0x2F, 'v'},
|
||||
{0x30, 'w'},
|
||||
{0x31, 'x'},
|
||||
{0x32, 'y'},
|
||||
{0x33, 'z'},
|
||||
{0x34, '0'},
|
||||
{0x35, '1'},
|
||||
{0x36, '2'},
|
||||
{0x37, '3'},
|
||||
{0x38, '4'},
|
||||
{0x39, '5'},
|
||||
{0x3A, '6'},
|
||||
{0x3B, '7'},
|
||||
{0x3C, '8'},
|
||||
{0x3D, '9'},
|
||||
{0x3E, '!'},
|
||||
{0x3F, '?'},
|
||||
{0x40, '-'},
|
||||
{0x41, '.'},
|
||||
{0x42, ','},
|
||||
{0x44, '>'},
|
||||
{0x45, '('},
|
||||
{0x46, ')'},
|
||||
{0x4C, '"'},
|
||||
{0x51, '\''},
|
||||
{0x59, ' '},
|
||||
{0x5A, '<'},
|
||||
// {0x5F, '¡'}, {0x60, '¡'}, {0x61, '¡'}, {0x62, ' '}, {0x63, ' '}, {0x64,
|
||||
// ' '},
|
||||
{0x65, ' '},
|
||||
{0x66, '_'},
|
||||
};
|
||||
|
||||
static TextElement DictionaryElement =
|
||||
TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
|
||||
|
||||
class MessageEditor : public Editor, public SharedRom {
|
||||
public:
|
||||
struct DictionaryEntry {
|
||||
uint8_t ID;
|
||||
std::string Contents;
|
||||
std::vector<uint8_t> Data;
|
||||
int Length;
|
||||
std::string Token;
|
||||
|
||||
DictionaryEntry() = default;
|
||||
DictionaryEntry(uint8_t i, std::string s)
|
||||
: Contents(s), ID(i), Length(s.length()) {
|
||||
Token = absl::StrFormat("[%s:%00X]", DICTIONARYTOKEN, ID);
|
||||
Data = ParseMessageToData(Contents);
|
||||
}
|
||||
|
||||
bool ContainedInString(std::string s) {
|
||||
return s.find(Contents) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string ReplaceInstancesOfIn(std::string s) {
|
||||
std::string replacedString = s;
|
||||
size_t pos = replacedString.find(Contents);
|
||||
while (pos != std::string::npos) {
|
||||
replacedString.replace(pos, Contents.length(), Token);
|
||||
pos = replacedString.find(Contents, pos + Token.length());
|
||||
}
|
||||
return replacedString;
|
||||
}
|
||||
};
|
||||
|
||||
MessageEditor() { type_ = EditorType::kMessage; }
|
||||
|
||||
absl::Status Initialize();
|
||||
absl::Status Update() override;
|
||||
void DrawMessageList();
|
||||
void DrawCurrentMessage();
|
||||
void DrawTextCommands();
|
||||
void DrawDictionary();
|
||||
|
||||
absl::Status Initialize();
|
||||
void ReadAllTextData();
|
||||
void BuildDictionaryEntries();
|
||||
void ReadAllTextDataV2();
|
||||
[[deprecated]] void ReadAllTextData();
|
||||
|
||||
absl::Status Cut() override;
|
||||
absl::Status Copy() override;
|
||||
@@ -238,67 +63,47 @@ class MessageEditor : public Editor, public SharedRom {
|
||||
absl::Status Save();
|
||||
void Delete();
|
||||
void SelectAll();
|
||||
// void RegisterTests(ImGuiTestEngine* e) override;
|
||||
|
||||
TextElement FindMatchingCommand(uint8_t byte);
|
||||
TextElement FindMatchingSpecial(uint8_t value);
|
||||
string ParseTextDataByte(uint8_t value);
|
||||
DictionaryEntry GetDictionaryFromID(uint8_t value);
|
||||
|
||||
static uint8_t FindDictionaryEntry(uint8_t value);
|
||||
static uint8_t FindMatchingCharacter(char value);
|
||||
void DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
|
||||
int sizex = 1, int sizey = 1);
|
||||
void DrawCharacterToPreview(char c);
|
||||
void DrawCharacterToPreview(const std::vector<uint8_t>& text);
|
||||
|
||||
void DrawStringToPreview(string str);
|
||||
void DrawStringToPreview(std::string str);
|
||||
void DrawMessagePreview();
|
||||
std::string DisplayTextOverflowError(int pos, bool bank);
|
||||
|
||||
void InsertCommandButton_Click_1();
|
||||
void InsertSpecialButton_Click();
|
||||
void InsertSelectedText(string str);
|
||||
|
||||
static const std::vector<DictionaryEntry> AllDicts;
|
||||
|
||||
uint8_t width_array[100];
|
||||
string romname = "";
|
||||
|
||||
int text_line = 0;
|
||||
int text_pos = 0;
|
||||
int shown_lines = 0;
|
||||
int selected_tile = 0;
|
||||
|
||||
bool skip_next = false;
|
||||
bool from_form = false;
|
||||
|
||||
std::vector<MessageData> ListOfTexts;
|
||||
std::vector<MessageData> DisplayedMessages;
|
||||
std::vector<std::string> ParsedMessages;
|
||||
|
||||
MessageData CurrentMessage;
|
||||
|
||||
private:
|
||||
static const TextElement DictionaryElement;
|
||||
|
||||
bool skip_next = false;
|
||||
bool data_loaded_ = false;
|
||||
int current_message_id_ = 0;
|
||||
|
||||
int text_line_ = 0;
|
||||
int text_position_ = 0;
|
||||
int shown_lines_ = 0;
|
||||
|
||||
uint8_t width_array[kWidthArraySize];
|
||||
|
||||
std::string search_text_ = "";
|
||||
|
||||
std::vector<uint8_t> font_gfx16_data_;
|
||||
std::vector<uint8_t> current_font_gfx16_data_;
|
||||
std::vector<std::string> parsed_messages_;
|
||||
|
||||
std::vector<MessageData> list_of_texts_;
|
||||
|
||||
std::vector<DictionaryEntry> all_dictionaries_;
|
||||
|
||||
MessageData current_message_;
|
||||
|
||||
gfx::Bitmap font_gfx_bitmap_;
|
||||
gfx::Bitmap current_font_gfx16_bitmap_;
|
||||
gfx::SnesPalette font_preview_colors_;
|
||||
|
||||
gui::Canvas font_gfx_canvas_{"##FontGfxCanvas", ImVec2(128, 128)};
|
||||
gui::Canvas current_font_gfx16_canvas_{"##CurrentMessageGfx",
|
||||
ImVec2(172, 4096)};
|
||||
|
||||
gfx::Bitmap font_gfx_bitmap_;
|
||||
gfx::Bitmap current_font_gfx16_bitmap_;
|
||||
|
||||
Bytes font_gfx16_data;
|
||||
Bytes current_font_gfx16_data_;
|
||||
|
||||
gfx::SnesPalette font_preview_colors_;
|
||||
|
||||
struct TextBox {
|
||||
std::string text;
|
||||
std::string buffer;
|
||||
@@ -357,8 +162,6 @@ class MessageEditor : public Editor, public SharedRom {
|
||||
TextBox message_text_box_;
|
||||
};
|
||||
|
||||
static std::vector<MessageEditor::DictionaryEntry> AllDictionaries;
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#include "message_editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -1,19 +1,15 @@
|
||||
#ifndef YAZE_APP_EDITOR_MUSIC_EDITOR_H
|
||||
#define YAZE_APP_EDITOR_MUSIC_EDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/editor/code/assembly_editor.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/music/tracker.h"
|
||||
// #include "snes_spc/demo/demo_util.h"
|
||||
// #include "snes_spc/demo/wave_writer.h"
|
||||
// #include "snes_spc/snes_spc/spc.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -81,20 +77,11 @@ class MusicEditor : public SharedRom, public Editor {
|
||||
|
||||
zelda3::music::Tracker music_tracker_;
|
||||
|
||||
// Mix_Music* current_song_ = NULL;
|
||||
|
||||
AssemblyEditor assembly_editor_;
|
||||
ImGuiTableFlags toolset_table_flags_ = ImGuiTableFlags_SizingFixedFit;
|
||||
ImGuiTableFlags music_editor_flags_ = ImGuiTableFlags_SizingFixedFit |
|
||||
ImGuiTableFlags_Resizable |
|
||||
ImGuiTableFlags_Reorderable;
|
||||
|
||||
ImGuiTableFlags channel_table_flags_ =
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable |
|
||||
ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable |
|
||||
ImGuiTableFlags_SortMulti | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV |
|
||||
ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollY;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "app/editor/overworld/entity.h"
|
||||
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/style.h"
|
||||
|
||||
@@ -8,7 +9,6 @@ namespace app {
|
||||
namespace editor {
|
||||
|
||||
using ImGui::BeginChild;
|
||||
using ImGui::BeginGroup;
|
||||
using ImGui::Button;
|
||||
using ImGui::Checkbox;
|
||||
using ImGui::EndChild;
|
||||
@@ -16,7 +16,9 @@ using ImGui::SameLine;
|
||||
using ImGui::Selectable;
|
||||
using ImGui::Text;
|
||||
|
||||
bool IsMouseHoveringOverEntity(const zelda3::OverworldEntity &entity,
|
||||
constexpr float kInputFieldSize = 30.f;
|
||||
|
||||
bool IsMouseHoveringOverEntity(const zelda3::GameEntity &entity,
|
||||
ImVec2 canvas_p0, ImVec2 scrolling) {
|
||||
// Get the mouse position relative to the canvas
|
||||
const ImGuiIO &io = ImGui::GetIO();
|
||||
@@ -31,7 +33,7 @@ bool IsMouseHoveringOverEntity(const zelda3::OverworldEntity &entity,
|
||||
return false;
|
||||
}
|
||||
|
||||
void MoveEntityOnGrid(zelda3::OverworldEntity *entity, ImVec2 canvas_p0,
|
||||
void MoveEntityOnGrid(zelda3::GameEntity *entity, ImVec2 canvas_p0,
|
||||
ImVec2 scrolling, bool free_movement) {
|
||||
// Get the mouse position relative to the canvas
|
||||
const ImGuiIO &io = ImGui::GetIO();
|
||||
@@ -51,19 +53,20 @@ void MoveEntityOnGrid(zelda3::OverworldEntity *entity, ImVec2 canvas_p0,
|
||||
entity->set_y(new_y);
|
||||
}
|
||||
|
||||
void HandleEntityDragging(zelda3::OverworldEntity *entity, ImVec2 canvas_p0,
|
||||
void HandleEntityDragging(zelda3::GameEntity *entity, ImVec2 canvas_p0,
|
||||
ImVec2 scrolling, bool &is_dragging_entity,
|
||||
zelda3::OverworldEntity *&dragged_entity,
|
||||
zelda3::OverworldEntity *¤t_entity,
|
||||
zelda3::GameEntity *&dragged_entity,
|
||||
zelda3::GameEntity *¤t_entity,
|
||||
bool free_movement) {
|
||||
std::string entity_type = "Entity";
|
||||
if (entity->type_ == zelda3::OverworldEntity::EntityType::kExit) {
|
||||
if (entity->entity_type_ == zelda3::GameEntity::EntityType::kExit) {
|
||||
entity_type = "Exit";
|
||||
} else if (entity->type_ == zelda3::OverworldEntity::EntityType::kEntrance) {
|
||||
} else if (entity->entity_type_ ==
|
||||
zelda3::GameEntity::EntityType::kEntrance) {
|
||||
entity_type = "Entrance";
|
||||
} else if (entity->type_ == zelda3::OverworldEntity::EntityType::kSprite) {
|
||||
} else if (entity->entity_type_ == zelda3::GameEntity::EntityType::kSprite) {
|
||||
entity_type = "Sprite";
|
||||
} else if (entity->type_ == zelda3::OverworldEntity::EntityType::kItem) {
|
||||
} else if (entity->entity_type_ == zelda3::GameEntity::EntityType::kItem) {
|
||||
entity_type = "Item";
|
||||
}
|
||||
const auto is_hovering =
|
||||
@@ -87,7 +90,7 @@ void HandleEntityDragging(zelda3::OverworldEntity *entity, ImVec2 canvas_p0,
|
||||
} else if (is_dragging_entity && dragged_entity == entity) {
|
||||
if (ImGui::BeginDragDropSource()) {
|
||||
ImGui::SetDragDropPayload("ENTITY_PAYLOAD", &entity,
|
||||
sizeof(zelda3::OverworldEntity));
|
||||
sizeof(zelda3::GameEntity));
|
||||
Text("Moving %s ID: %s", entity_type.c_str(),
|
||||
core::UppercaseHexByte(entity->entity_id_).c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
@@ -132,7 +135,7 @@ bool DrawOverworldEntrancePopup(
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Entrance editor", NULL,
|
||||
ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
gui::InputHex("Map ID", &entrance.map_id_);
|
||||
gui::InputHexWord("Map ID", &entrance.map_id_);
|
||||
gui::InputHexByte("Entrance ID", &entrance.entrance_id_,
|
||||
kInputFieldSize + 20);
|
||||
gui::InputHex("X", &entrance.x_);
|
||||
@@ -209,7 +212,7 @@ bool DrawExitEditorPopup(zelda3::overworld::OverworldExit &exit) {
|
||||
gui::InputHexWord("Room", &exit.room_id_);
|
||||
SameLine();
|
||||
gui::InputHex("Entity ID", &exit.entity_id_, 4);
|
||||
gui::InputHex("Map", &exit.map_id_);
|
||||
gui::InputHexWord("Map", &exit.map_id_);
|
||||
SameLine();
|
||||
Checkbox("Automatic", &exit.is_automatic_);
|
||||
|
||||
@@ -310,11 +313,11 @@ bool DrawExitEditorPopup(zelda3::overworld::OverworldExit &exit) {
|
||||
void DrawItemInsertPopup() {
|
||||
// Contents of the Context Menu
|
||||
if (ImGui::BeginPopup("Item Inserter")) {
|
||||
static int new_item_id = 0;
|
||||
static size_t new_item_id = 0;
|
||||
Text("Add Item");
|
||||
BeginChild("ScrollRegion", ImVec2(150, 150), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
for (int i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) {
|
||||
for (size_t i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) {
|
||||
if (Selectable(zelda3::overworld::kSecretItemNames[i].c_str(),
|
||||
i == new_item_id)) {
|
||||
new_item_id = i;
|
||||
@@ -348,10 +351,10 @@ bool DrawItemEditorPopup(zelda3::overworld::OverworldItem &item) {
|
||||
BeginChild("ScrollRegion", ImVec2(150, 150), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
ImGui::BeginGroup();
|
||||
for (int i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) {
|
||||
for (size_t i = 0; i < zelda3::overworld::kSecretItemNames.size(); i++) {
|
||||
if (Selectable(zelda3::overworld::kSecretItemNames[i].c_str(),
|
||||
item.id == i)) {
|
||||
item.id = i;
|
||||
item.id_ == i)) {
|
||||
item.id_ = i;
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
@@ -384,7 +387,7 @@ void DrawSpriteTable(std::function<void(int)> onSpriteSelect) {
|
||||
// Initialize items if empty
|
||||
if (items.empty()) {
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
items.push_back(SpriteItem{i, core::kSpriteDefaultNames[i].data()});
|
||||
items.push_back(SpriteItem{i, zelda3::kSpriteDefaultNames[i].data()});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include "app/editor/overworld_editor.h"
|
||||
#include "app/zelda3/common.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
@@ -11,16 +10,16 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
bool IsMouseHoveringOverEntity(const zelda3::OverworldEntity &entity,
|
||||
bool IsMouseHoveringOverEntity(const zelda3::GameEntity &entity,
|
||||
ImVec2 canvas_p0, ImVec2 scrolling);
|
||||
|
||||
void MoveEntityOnGrid(zelda3::OverworldEntity *entity, ImVec2 canvas_p0,
|
||||
void MoveEntityOnGrid(zelda3::GameEntity *entity, ImVec2 canvas_p0,
|
||||
ImVec2 scrolling, bool free_movement = false);
|
||||
|
||||
void HandleEntityDragging(zelda3::OverworldEntity *entity, ImVec2 canvas_p0,
|
||||
void HandleEntityDragging(zelda3::GameEntity *entity, ImVec2 canvas_p0,
|
||||
ImVec2 scrolling, bool &is_dragging_entity,
|
||||
zelda3::OverworldEntity *&dragged_entity,
|
||||
zelda3::OverworldEntity *¤t_entity,
|
||||
zelda3::GameEntity *&dragged_entity,
|
||||
zelda3::GameEntity *¤t_entity,
|
||||
bool free_movement = false);
|
||||
|
||||
bool DrawEntranceInserterPopup();
|
||||
@@ -85,4 +84,4 @@ bool DrawSpriteEditorPopup(zelda3::Sprite &sprite);
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_OVERWORLD_ENTITY_H
|
||||
#endif // YAZE_APP_EDITOR_OVERWORLD_ENTITY_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,6 @@
|
||||
#ifndef YAZE_APP_EDITOR_OVERWORLDEDITOR_H
|
||||
#define YAZE_APP_EDITOR_OVERWORLDEDITOR_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -10,13 +8,11 @@
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/editor/graphics/gfx_group_editor.h"
|
||||
#include "app/editor/graphics/palette_editor.h"
|
||||
#include "app/editor/graphics/tile16_editor.h"
|
||||
#include "app/editor/overworld/entity.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/utils/gfx_context.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
@@ -25,24 +21,24 @@
|
||||
#include "app/gui/zeml.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
static constexpr uint k4BPP = 4;
|
||||
static constexpr uint kByteSize = 3;
|
||||
static constexpr uint kMessageIdSize = 5;
|
||||
static constexpr uint kNumSheetsToLoad = 223;
|
||||
static constexpr uint kTile8DisplayHeight = 64;
|
||||
static constexpr float kInputFieldSize = 30.f;
|
||||
|
||||
static constexpr absl::string_view kToolsetColumnNames[] = {
|
||||
"#undoTool", "#redoTool", "#separator2", "#zoomOutTool",
|
||||
"#zoomInTool", "#separator", "#drawTool", "#history",
|
||||
"#entranceTool", "#exitTool", "#itemTool", "#spriteTool",
|
||||
"#transportTool", "#musicTool", "#separator3", "#tilemapTool",
|
||||
"propertiesTool"};
|
||||
constexpr uint k4BPP = 4;
|
||||
constexpr uint kByteSize = 3;
|
||||
constexpr uint kMessageIdSize = 5;
|
||||
constexpr uint kNumSheetsToLoad = 223;
|
||||
constexpr uint kTile8DisplayHeight = 64;
|
||||
constexpr uint kOverworldMapSize = 0x200;
|
||||
constexpr float kInputFieldSize = 30.f;
|
||||
constexpr ImVec2 kOverworldCanvasSize(kOverworldMapSize * 8,
|
||||
kOverworldMapSize * 8);
|
||||
constexpr ImVec2 kCurrentGfxCanvasSize(0x100 + 1, 0x10 * 0x40 + 1);
|
||||
constexpr ImVec2 kBlocksetCanvasSize(0x100 + 1, 0x4000 + 1);
|
||||
constexpr ImVec2 kGraphicsBinCanvasSize(0x100 + 1, kNumSheetsToLoad * 0x40 + 1);
|
||||
|
||||
constexpr ImGuiTableFlags kOWMapFlags =
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable;
|
||||
@@ -52,6 +48,14 @@ constexpr ImGuiTableFlags kOWEditFlags =
|
||||
ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter |
|
||||
ImGuiTableFlags_BordersV;
|
||||
|
||||
static constexpr absl::string_view kToolsetColumnNames[] = {
|
||||
"#undoTool", "#redoTool", "#separator2", "#zoomOutTool",
|
||||
"#zoomInTool", "#separator", "#drawTool", "#history",
|
||||
"#entranceTool", "#exitTool", "#itemTool", "#spriteTool",
|
||||
"#transportTool", "#musicTool", "#separator3", "#tilemapTool",
|
||||
"propertiesTool", "#separator4", "#experimentalTool", "#properties",
|
||||
"#separator5"};
|
||||
|
||||
constexpr absl::string_view kWorldList =
|
||||
"Light World\0Dark World\0Extra World\0";
|
||||
|
||||
@@ -61,13 +65,17 @@ constexpr absl::string_view kTileSelectorTab = "##TileSelectorTabBar";
|
||||
constexpr absl::string_view kOWEditTable = "##OWEditTable";
|
||||
constexpr absl::string_view kOWMapTable = "#MapSettingsTable";
|
||||
|
||||
constexpr int kEntranceTileTypePtrLow = 0xDB8BF;
|
||||
constexpr int kEntranceTileTypePtrHigh = 0xDB917;
|
||||
constexpr int kNumEntranceTileTypes = 0x2C;
|
||||
|
||||
class EntranceContext {
|
||||
public:
|
||||
absl::Status LoadEntranceTileTypes(Rom& rom) {
|
||||
int offset_low = 0xDB8BF;
|
||||
int offset_high = 0xDB917;
|
||||
int offset_low = kEntranceTileTypePtrLow;
|
||||
int offset_high = kEntranceTileTypePtrHigh;
|
||||
|
||||
for (int i = 0; i < 0x2C; i++) {
|
||||
for (int i = 0; i < kNumEntranceTileTypes; i++) {
|
||||
// Load entrance tile types
|
||||
ASSIGN_OR_RETURN(auto value_low, rom.ReadWord(offset_low + i));
|
||||
entrance_tile_types_low_.push_back(value_low);
|
||||
@@ -101,8 +109,8 @@ class EntranceContext {
|
||||
*/
|
||||
class OverworldEditor : public Editor,
|
||||
public SharedRom,
|
||||
public context::GfxContext,
|
||||
public EntranceContext,
|
||||
public GfxContext,
|
||||
public core::ExperimentFlags {
|
||||
public:
|
||||
OverworldEditor() { type_ = EditorType::kOverworld; }
|
||||
@@ -110,12 +118,15 @@ class OverworldEditor : public Editor,
|
||||
void InitializeZeml();
|
||||
|
||||
absl::Status Update() final;
|
||||
absl::Status Undo() { return absl::UnimplementedError("Undo"); }
|
||||
absl::Status Redo() { return absl::UnimplementedError("Redo"); }
|
||||
absl::Status Cut() { return absl::UnimplementedError("Cut"); }
|
||||
absl::Status Copy() { return absl::UnimplementedError("Copy"); }
|
||||
absl::Status Paste() { return absl::UnimplementedError("Paste"); }
|
||||
absl::Status Find() { return absl::UnimplementedError("Find Unused Tiles"); }
|
||||
absl::Status Undo() override { return absl::UnimplementedError("Undo"); }
|
||||
absl::Status Redo() override { return absl::UnimplementedError("Redo"); }
|
||||
absl::Status Cut() override { return absl::UnimplementedError("Cut"); }
|
||||
absl::Status Copy() override { return absl::UnimplementedError("Copy"); }
|
||||
absl::Status Paste() override { return absl::UnimplementedError("Paste"); }
|
||||
absl::Status Find() override {
|
||||
return absl::UnimplementedError("Find Unused Tiles");
|
||||
}
|
||||
absl::Status Save();
|
||||
|
||||
auto overworld() { return &overworld_; }
|
||||
|
||||
@@ -135,11 +146,26 @@ class OverworldEditor : public Editor,
|
||||
absl::Status LoadGraphics();
|
||||
|
||||
private:
|
||||
absl::Status UpdateFullscreenCanvas();
|
||||
/**
|
||||
* @brief Draws the canvas, tile16 selector, and toolset in fullscreen
|
||||
*/
|
||||
void DrawFullscreenCanvas();
|
||||
|
||||
absl::Status DrawToolset();
|
||||
/**
|
||||
* @brief Toolset for entrances, exits, items, sprites, and transports.
|
||||
*/
|
||||
void DrawToolset();
|
||||
|
||||
/**
|
||||
* @brief Draws the overworld map settings. Graphics, palettes, etc.
|
||||
*/
|
||||
void DrawOverworldMapSettings();
|
||||
|
||||
/**
|
||||
* @brief Draw the overworld settings for ZSCustomOverworld.
|
||||
*/
|
||||
void DrawCustomOverworldMapSettings();
|
||||
|
||||
void RefreshChildMap(int i);
|
||||
void RefreshOverworldMap();
|
||||
absl::Status RefreshMapPalette();
|
||||
@@ -155,9 +181,28 @@ class OverworldEditor : public Editor,
|
||||
void DrawOverworldMaps();
|
||||
void DrawOverworldEdits();
|
||||
void RenderUpdatedMapBitmap(const ImVec2& click_position,
|
||||
const Bytes& tile_data);
|
||||
const std::vector<uint8_t>& tile_data);
|
||||
|
||||
/**
|
||||
* @brief Check for changes to the overworld map.
|
||||
*
|
||||
* This function either draws the tile painter with the current tile16 or
|
||||
* group of tile16 data with ow_map_canvas_ and DrawOverworldEdits or it
|
||||
* checks for left mouse button click/drag to select a tile16 or group of
|
||||
* tile16 data from the overworld map canvas. Similar to ZScream selection.
|
||||
*/
|
||||
void CheckForOverworldEdits();
|
||||
|
||||
/**
|
||||
* @brief Draw and create the tile16 IDs that are currently selected.
|
||||
*/
|
||||
void CheckForSelectRectangle();
|
||||
|
||||
/**
|
||||
* @brief Check for changes to the overworld map. Calls RefreshOverworldMap
|
||||
* and RefreshTile16Blockset on the current map if it is modified and is
|
||||
* actively being edited.
|
||||
*/
|
||||
absl::Status CheckForCurrentMap();
|
||||
void CheckForMousePan();
|
||||
|
||||
@@ -175,17 +220,10 @@ class OverworldEditor : public Editor,
|
||||
|
||||
void DrawOverworldProperties();
|
||||
|
||||
absl::Status DrawExperimentalModal();
|
||||
|
||||
absl::Status UpdateUsageStats();
|
||||
void DrawUsageGrid();
|
||||
void CalculateUsageStats();
|
||||
|
||||
absl::Status LoadAnimatedMaps();
|
||||
void DrawDebugWindow();
|
||||
|
||||
auto gfx_group_editor() const { return gfx_group_editor_; }
|
||||
|
||||
enum class EditingMode {
|
||||
DRAW_TILE,
|
||||
ENTRANCES,
|
||||
@@ -200,84 +238,55 @@ class OverworldEditor : public Editor,
|
||||
EditingMode current_mode = EditingMode::DRAW_TILE;
|
||||
EditingMode previous_mode = EditingMode::DRAW_TILE;
|
||||
|
||||
enum OverworldProperty {
|
||||
LW_AREA_GFX,
|
||||
DW_AREA_GFX,
|
||||
LW_AREA_PAL,
|
||||
DW_AREA_PAL,
|
||||
LW_SPR_GFX_PART1,
|
||||
LW_SPR_GFX_PART2,
|
||||
DW_SPR_GFX_PART1,
|
||||
DW_SPR_GFX_PART2,
|
||||
LW_SPR_PAL_PART1,
|
||||
LW_SPR_PAL_PART2,
|
||||
DW_SPR_PAL_PART1,
|
||||
DW_SPR_PAL_PART2,
|
||||
};
|
||||
|
||||
int current_world_ = 0;
|
||||
int current_map_ = 0;
|
||||
int current_parent_ = 0;
|
||||
int current_entrance_id_ = 0;
|
||||
int current_exit_id_ = 0;
|
||||
int current_item_id_ = 0;
|
||||
int current_sprite_id_ = 0;
|
||||
int current_blockset_ = 0;
|
||||
int game_state_ = 1;
|
||||
int current_tile16_ = 0;
|
||||
int selected_tile_ = 0;
|
||||
|
||||
int current_blockset_ = 0;
|
||||
|
||||
int selected_entrance_ = 0;
|
||||
int selected_usage_map_ = 0xFFFF;
|
||||
|
||||
char map_gfx_[3] = "";
|
||||
char map_palette_[3] = "";
|
||||
char spr_gfx_[3] = "";
|
||||
char spr_palette_[3] = "";
|
||||
char message_id_[5] = "";
|
||||
char staticgfx[16];
|
||||
|
||||
uint32_t tilemap_file_offset_high_ = 0;
|
||||
uint32_t tilemap_file_offset_low_ = 0;
|
||||
uint32_t light_maps_to_load_ = 0x51;
|
||||
uint32_t dark_maps_to_load_ = 0x2A;
|
||||
uint32_t sp_maps_to_load_ = 0x07;
|
||||
|
||||
bool opt_enable_grid = true;
|
||||
bool all_gfx_loaded_ = false;
|
||||
bool map_blockset_loaded_ = false;
|
||||
bool selected_tile_loaded_ = false;
|
||||
bool update_selected_tile_ = true;
|
||||
bool is_dragging_entrance_ = false;
|
||||
bool show_tile16_editor_ = false;
|
||||
bool show_gfx_group_editor_ = false;
|
||||
bool overworld_canvas_fullscreen_ = false;
|
||||
bool middle_mouse_dragging_ = false;
|
||||
|
||||
bool is_dragging_entity_ = false;
|
||||
zelda3::OverworldEntity* dragged_entity_;
|
||||
zelda3::OverworldEntity* current_entity_;
|
||||
|
||||
int current_entrance_id_ = 0;
|
||||
zelda3::overworld::OverworldEntrance current_entrance_;
|
||||
int current_exit_id_ = 0;
|
||||
zelda3::overworld::OverworldExit current_exit_;
|
||||
int current_item_id_ = 0;
|
||||
zelda3::overworld::OverworldItem current_item_;
|
||||
int current_sprite_id_ = 0;
|
||||
zelda3::Sprite current_sprite_;
|
||||
|
||||
bool show_experimental = false;
|
||||
std::string ow_tilemap_filename_ = "";
|
||||
std::string tile32_configuration_filename_ = "";
|
||||
|
||||
Bytes selected_tile_data_;
|
||||
std::vector<Bytes> tile16_individual_data_;
|
||||
std::vector<uint8_t> selected_tile_data_;
|
||||
std::vector<std::vector<uint8_t>> tile16_individual_data_;
|
||||
std::vector<gfx::Bitmap> tile16_individual_;
|
||||
|
||||
std::vector<Bytes> tile8_individual_data_;
|
||||
std::vector<std::vector<uint8_t>> tile8_individual_data_;
|
||||
std::vector<gfx::Bitmap> tile8_individual_;
|
||||
|
||||
Tile16Editor tile16_editor_;
|
||||
GfxGroupEditor gfx_group_editor_;
|
||||
PaletteEditor palette_editor_;
|
||||
zelda3::overworld::Overworld overworld_;
|
||||
|
||||
gui::Canvas ow_map_canvas_{"owMapCanvas", ImVec2(0x200 * 8, 0x200 * 8),
|
||||
gui::CanvasGridSize::k64x64};
|
||||
gui::Canvas current_gfx_canvas_{"customGfxCanvas",
|
||||
ImVec2(0x100 + 1, 0x10 * 0x40 + 1),
|
||||
gui::CanvasGridSize::k32x32};
|
||||
gui::Canvas blockset_canvas_{"blocksetCanvas", ImVec2(0x100 + 1, 0x2000 + 1),
|
||||
gui::CanvasGridSize::k32x32};
|
||||
gui::Canvas graphics_bin_canvas_{
|
||||
"graphicsBinCanvas", ImVec2(0x100 + 1, kNumSheetsToLoad * 0x40 + 1),
|
||||
gui::CanvasGridSize::k16x16};
|
||||
gui::Canvas properties_canvas_;
|
||||
|
||||
gfx::SnesPalette palette_;
|
||||
|
||||
gfx::Bitmap selected_tile_bmp_;
|
||||
gfx::Bitmap tile16_blockset_bmp_;
|
||||
gfx::Bitmap current_gfx_bmp_;
|
||||
@@ -286,10 +295,28 @@ class OverworldEditor : public Editor,
|
||||
gfx::BitmapTable maps_bmp_;
|
||||
gfx::BitmapTable current_graphics_set_;
|
||||
gfx::BitmapTable sprite_previews_;
|
||||
gfx::BitmapTable animated_maps_;
|
||||
|
||||
OWBlockset refresh_blockset_;
|
||||
zelda3::overworld::Overworld overworld_;
|
||||
zelda3::OWBlockset refresh_blockset_;
|
||||
|
||||
zelda3::Sprite current_sprite_;
|
||||
|
||||
zelda3::overworld::OverworldEntrance current_entrance_;
|
||||
zelda3::overworld::OverworldExit current_exit_;
|
||||
zelda3::overworld::OverworldItem current_item_;
|
||||
|
||||
zelda3::GameEntity* current_entity_;
|
||||
zelda3::GameEntity* dragged_entity_;
|
||||
|
||||
gui::Canvas ow_map_canvas_{"OwMap", kOverworldCanvasSize,
|
||||
gui::CanvasGridSize::k64x64};
|
||||
gui::Canvas current_gfx_canvas_{"CurrentGfx", kCurrentGfxCanvasSize,
|
||||
gui::CanvasGridSize::k32x32};
|
||||
gui::Canvas blockset_canvas_{"OwBlockset", kBlocksetCanvasSize,
|
||||
gui::CanvasGridSize::k32x32};
|
||||
gui::Canvas graphics_bin_canvas_{"GraphicsBin", kGraphicsBinCanvasSize,
|
||||
gui::CanvasGridSize::k16x16};
|
||||
gui::Canvas properties_canvas_;
|
||||
gui::zeml::Node layout_node_;
|
||||
absl::Status status_;
|
||||
};
|
||||
@@ -297,4 +324,4 @@ class OverworldEditor : public Editor,
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,157 +0,0 @@
|
||||
#include "app/editor/overworld_editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
void OverworldEditor::RefreshChildMap(int map_index) {
|
||||
overworld_.mutable_overworld_map(map_index)->LoadAreaGraphics();
|
||||
status_ = overworld_.mutable_overworld_map(map_index)->BuildTileset();
|
||||
PRINT_IF_ERROR(status_);
|
||||
status_ = overworld_.mutable_overworld_map(map_index)->BuildTiles16Gfx(
|
||||
overworld_.tiles16().size());
|
||||
PRINT_IF_ERROR(status_);
|
||||
status_ = overworld_.mutable_overworld_map(map_index)->BuildBitmap(
|
||||
overworld_.GetMapTiles(current_world_));
|
||||
maps_bmp_[map_index].set_data(
|
||||
overworld_.mutable_overworld_map(map_index)->bitmap_data());
|
||||
maps_bmp_[map_index].set_modified(true);
|
||||
PRINT_IF_ERROR(status_);
|
||||
}
|
||||
|
||||
void OverworldEditor::RefreshOverworldMap() {
|
||||
std::vector<std::future<void>> futures;
|
||||
int indices[4];
|
||||
|
||||
auto refresh_map_async = [this](int map_index) {
|
||||
RefreshChildMap(map_index);
|
||||
};
|
||||
|
||||
int source_map_id = current_map_;
|
||||
bool is_large = overworld_.overworld_map(current_map_)->is_large_map();
|
||||
if (is_large) {
|
||||
source_map_id = current_parent_;
|
||||
// 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(source_map_id)->parent() + i;
|
||||
if (i >= 2) sibling_index += 6;
|
||||
futures.push_back(
|
||||
std::async(std::launch::async, refresh_map_async, sibling_index));
|
||||
indices[i] = sibling_index;
|
||||
}
|
||||
}
|
||||
indices[0] = source_map_id;
|
||||
futures.push_back(
|
||||
std::async(std::launch::async, refresh_map_async, source_map_id));
|
||||
|
||||
for (auto &each : futures) {
|
||||
each.get();
|
||||
}
|
||||
int n = is_large ? 4 : 1;
|
||||
// We do texture updating on the main thread
|
||||
for (int i = 0; i < n; ++i) {
|
||||
rom()->UpdateBitmap(&maps_bmp_[indices[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::RefreshMapPalette() {
|
||||
RETURN_IF_ERROR(
|
||||
overworld_.mutable_overworld_map(current_map_)->LoadPalette());
|
||||
const auto current_map_palette = overworld_.AreaPalette();
|
||||
|
||||
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;
|
||||
RETURN_IF_ERROR(
|
||||
overworld_.mutable_overworld_map(sibling_index)->LoadPalette());
|
||||
RETURN_IF_ERROR(
|
||||
maps_bmp_[sibling_index].ApplyPalette(current_map_palette));
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(maps_bmp_[current_map_].ApplyPalette(current_map_palette));
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void OverworldEditor::RefreshMapProperties() {
|
||||
auto ¤t_ow_map = *overworld_.mutable_overworld_map(current_map_);
|
||||
if (current_ow_map.is_large_map()) {
|
||||
// We need to copy the properties from the parent map to the children
|
||||
for (int i = 1; i < 4; i++) {
|
||||
int sibling_index = current_ow_map.parent() + i;
|
||||
if (i >= 2) {
|
||||
sibling_index += 6;
|
||||
}
|
||||
auto &map = *overworld_.mutable_overworld_map(sibling_index);
|
||||
map.set_area_graphics(current_ow_map.area_graphics());
|
||||
map.set_area_palette(current_ow_map.area_palette());
|
||||
map.set_sprite_graphics(game_state_,
|
||||
current_ow_map.sprite_graphics(game_state_));
|
||||
map.set_sprite_palette(game_state_,
|
||||
current_ow_map.sprite_palette(game_state_));
|
||||
map.set_message_id(current_ow_map.message_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status OverworldEditor::RefreshTile16Blockset() {
|
||||
if (current_blockset_ ==
|
||||
overworld_.overworld_map(current_map_)->area_graphics()) {
|
||||
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
|
||||
rom()->UpdateBitmap(&tile16_blockset_bmp_);
|
||||
RETURN_IF_ERROR(tile16_blockset_bmp_.ApplyPalette(palette_));
|
||||
|
||||
// Copy the tile16 data into individual tiles.
|
||||
auto tile16_data = overworld_.Tile16Blockset();
|
||||
|
||||
std::vector<std::future<void>> futures;
|
||||
// Loop through the tiles and copy their pixel data into separate vectors
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
futures.push_back(std::async(
|
||||
std::launch::async,
|
||||
[&](int index) {
|
||||
// Create a new vector for the pixel data of the current tile
|
||||
Bytes tile_data(16 * 16, 0x00); // More efficient initialization
|
||||
|
||||
// Copy the pixel data for the current tile into the vector
|
||||
for (int ty = 0; ty < 16; ty++) {
|
||||
for (int tx = 0; tx < 16; tx++) {
|
||||
int position = tx + (ty * 0x10);
|
||||
uint8_t value =
|
||||
tile16_data[(index % 8 * 16) + (index / 8 * 16 * 0x80) +
|
||||
(ty * 0x80) + tx];
|
||||
tile_data[position] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the vector for the current tile to the vector of tile pixel
|
||||
// data
|
||||
tile16_individual_[index].set_data(tile_data);
|
||||
},
|
||||
i));
|
||||
}
|
||||
|
||||
for (auto &future : futures) {
|
||||
future.get();
|
||||
}
|
||||
|
||||
// Render the bitmaps of each tile.
|
||||
for (int id = 0; id < 4096; id++) {
|
||||
RETURN_IF_ERROR(tile16_individual_[id].ApplyPalette(palette_));
|
||||
rom()->UpdateBitmap(&tile16_individual_[id]);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "app/editor/sprite/zsprite.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/zelda3/sprite/sprite.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -71,13 +72,13 @@ void SpriteEditor::DrawVanillaSpriteEditor() {
|
||||
for (int n = 0; n < active_sprites_.Size;) {
|
||||
bool open = true;
|
||||
|
||||
if (active_sprites_[n] > sizeof(core::kSpriteDefaultNames) / 4) {
|
||||
if (active_sprites_[n] > sizeof(zelda3::kSpriteDefaultNames) / 4) {
|
||||
active_sprites_.erase(active_sprites_.Data + n);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem(
|
||||
core::kSpriteDefaultNames[active_sprites_[n]].data(), &open,
|
||||
zelda3::kSpriteDefaultNames[active_sprites_[n]].data(), &open,
|
||||
ImGuiTabItemFlags_None)) {
|
||||
DrawSpriteCanvas();
|
||||
ImGui::EndTabItem();
|
||||
@@ -175,7 +176,7 @@ void SpriteEditor::DrawCurrentSheets() {
|
||||
graphics_sheet_canvas_.DrawTileSelector(32);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
graphics_sheet_canvas_.DrawBitmap(
|
||||
rom()->bitmap_manager()[current_sheets_[i]], 1, (i * 0x40) + 1, 2);
|
||||
rom()->gfx_sheets().at(current_sheets_[i]), 1, (i * 0x40) + 1, 2);
|
||||
}
|
||||
graphics_sheet_canvas_.DrawGrid();
|
||||
graphics_sheet_canvas_.DrawOverlay();
|
||||
@@ -188,10 +189,10 @@ void SpriteEditor::DrawSpritesList() {
|
||||
ImVec2(ImGui::GetContentRegionAvail().x, 0), true,
|
||||
ImGuiWindowFlags_NoDecoration)) {
|
||||
int i = 0;
|
||||
for (const auto each_sprite_name : core::kSpriteDefaultNames) {
|
||||
for (const auto each_sprite_name : zelda3::kSpriteDefaultNames) {
|
||||
rom()->resource_label()->SelectableLabelWithNameEdit(
|
||||
current_sprite_id_ == i, "Sprite Names", core::UppercaseHexByte(i),
|
||||
core::kSpriteDefaultNames[i].data());
|
||||
zelda3::kSpriteDefaultNames[i].data());
|
||||
if (ImGui::IsItemClicked()) {
|
||||
current_sprite_id_ = i;
|
||||
if (!active_sprites_.contains(i)) {
|
||||
@@ -243,7 +244,7 @@ void SpriteEditor::DrawCustomSpritesMetadata() {
|
||||
// ZSprite Maker format open file dialog
|
||||
if (ImGui::Button("Open ZSprite")) {
|
||||
// Open ZSprite file
|
||||
std::string file_path = FileDialogWrapper::ShowOpenFileDialog();
|
||||
std::string file_path = core::FileDialogWrapper::ShowOpenFileDialog();
|
||||
if (!file_path.empty()) {
|
||||
zsprite::ZSprite zsprite;
|
||||
status_ = zsprite.Load(file_path);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/editor/sprite/zsprite.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#ifndef YAZE_APP_EDITOR_SPRITE_ZSPRITE_H
|
||||
#define YAZE_APP_EDITOR_SPRITE_ZSPRITE_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "app/core/constants.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -46,7 +46,7 @@ struct OamTile {
|
||||
struct AnimationGroup {
|
||||
AnimationGroup() = default;
|
||||
AnimationGroup(uint8_t fs, uint8_t fe, uint8_t fsp, std::string fn)
|
||||
: frame_start(fs), frame_end(fe), frame_speed(fsp), frame_name(fn) {}
|
||||
: frame_name(fn), frame_start(fs), frame_end(fe), frame_speed(fsp) {}
|
||||
|
||||
std::string frame_name;
|
||||
uint8_t frame_start;
|
||||
|
||||
143
src/app/editor/system/command_manager.cc
Normal file
143
src/app/editor/system/command_manager.cc
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "command_manager.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
ImGuiKey MapKeyToImGuiKey(char key) {
|
||||
switch (key) {
|
||||
case 'A':
|
||||
return ImGuiKey_A;
|
||||
case 'B':
|
||||
return ImGuiKey_B;
|
||||
case 'C':
|
||||
return ImGuiKey_C;
|
||||
case 'D':
|
||||
return ImGuiKey_D;
|
||||
case 'E':
|
||||
return ImGuiKey_E;
|
||||
case 'F':
|
||||
return ImGuiKey_F;
|
||||
case 'G':
|
||||
return ImGuiKey_G;
|
||||
case 'H':
|
||||
return ImGuiKey_H;
|
||||
case 'I':
|
||||
return ImGuiKey_I;
|
||||
case 'J':
|
||||
return ImGuiKey_J;
|
||||
case 'K':
|
||||
return ImGuiKey_K;
|
||||
case 'L':
|
||||
return ImGuiKey_L;
|
||||
case 'M':
|
||||
return ImGuiKey_M;
|
||||
case 'N':
|
||||
return ImGuiKey_N;
|
||||
case 'O':
|
||||
return ImGuiKey_O;
|
||||
case 'P':
|
||||
return ImGuiKey_P;
|
||||
case 'Q':
|
||||
return ImGuiKey_Q;
|
||||
case 'R':
|
||||
return ImGuiKey_R;
|
||||
case 'S':
|
||||
return ImGuiKey_S;
|
||||
case 'T':
|
||||
return ImGuiKey_T;
|
||||
case 'U':
|
||||
return ImGuiKey_U;
|
||||
case 'V':
|
||||
return ImGuiKey_V;
|
||||
case 'W':
|
||||
return ImGuiKey_W;
|
||||
case 'X':
|
||||
return ImGuiKey_X;
|
||||
case 'Y':
|
||||
return ImGuiKey_Y;
|
||||
case 'Z':
|
||||
return ImGuiKey_Z;
|
||||
case '/':
|
||||
return ImGuiKey_Slash;
|
||||
case '-':
|
||||
return ImGuiKey_Minus;
|
||||
default:
|
||||
return ImGuiKey_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
// When the player presses Space, a popup will appear fixed to the bottom of the
|
||||
// ImGui window with a list of the available key commands which can be used.
|
||||
void CommandManager::ShowWhichKey() {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Space)) {
|
||||
ImGui::OpenPopup("WhichKey");
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - 100),
|
||||
ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, 100),
|
||||
ImGuiCond_Always);
|
||||
if (ImGui::BeginPopup("WhichKey")) {
|
||||
// ESC to close the popup
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
const ImVec4 colors[] = {
|
||||
ImVec4(0.8f, 0.2f, 0.2f, 1.0f), // Soft Red
|
||||
ImVec4(0.2f, 0.8f, 0.2f, 1.0f), // Soft Green
|
||||
ImVec4(0.2f, 0.2f, 0.8f, 1.0f), // Soft Blue
|
||||
ImVec4(0.8f, 0.8f, 0.2f, 1.0f), // Soft Yellow
|
||||
ImVec4(0.8f, 0.2f, 0.8f, 1.0f), // Soft Magenta
|
||||
ImVec4(0.2f, 0.8f, 0.8f, 1.0f) // Soft Cyan
|
||||
};
|
||||
const int numColors = sizeof(colors) / sizeof(colors[0]);
|
||||
int colorIndex = 0;
|
||||
|
||||
if (ImGui::BeginTable("CommandsTable", commands_.size(),
|
||||
ImGuiTableFlags_SizingStretchProp)) {
|
||||
for (const auto &[shortcut, info] : commands_) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(colors[colorIndex], "%c: %s",
|
||||
info.command_info.mnemonic,
|
||||
info.command_info.name.c_str());
|
||||
colorIndex = (colorIndex + 1) % numColors;
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void CommandManager::SaveKeybindings(const std::string &filepath) {
|
||||
std::ofstream out(filepath);
|
||||
if (out.is_open()) {
|
||||
for (const auto &[shortcut, info] : commands_) {
|
||||
out << shortcut << " " << info.command_info.mnemonic << " "
|
||||
<< info.command_info.name << " " << info.command_info.desc << "\n";
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
void CommandManager::LoadKeybindings(const std::string &filepath) {
|
||||
std::ifstream in(filepath);
|
||||
if (in.is_open()) {
|
||||
commands_.clear();
|
||||
std::string shortcut, name, desc;
|
||||
char mnemonic;
|
||||
while (in >> shortcut >> mnemonic >> name >> desc) {
|
||||
commands_[shortcut].command_info = {nullptr, mnemonic, name, desc};
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
83
src/app/editor/system/command_manager.h
Normal file
83
src/app/editor/system/command_manager.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_COMMAND_MANAGER_H
|
||||
#define YAZE_APP_EDITOR_SYSTEM_COMMAND_MANAGER_H
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
ImGuiKey MapKeyToImGuiKey(char key);
|
||||
|
||||
class CommandManager {
|
||||
public:
|
||||
CommandManager() = default;
|
||||
~CommandManager() = default;
|
||||
|
||||
using Command = std::function<void()>;
|
||||
|
||||
struct CommandInfo {
|
||||
Command command;
|
||||
char mnemonic;
|
||||
std::string name;
|
||||
std::string desc;
|
||||
CommandInfo(Command command, char mnemonic, const std::string &name,
|
||||
const std::string &desc)
|
||||
: command(std::move(command)), mnemonic(mnemonic), name(name),
|
||||
desc(desc) {}
|
||||
CommandInfo() = default;
|
||||
};
|
||||
|
||||
// New command info which supports subsections of commands
|
||||
struct CommandInfoOrPrefix {
|
||||
CommandInfo command_info;
|
||||
std::unordered_map<std::string, CommandInfoOrPrefix> subcommands;
|
||||
CommandInfoOrPrefix(CommandInfo command_info)
|
||||
: command_info(std::move(command_info)) {}
|
||||
CommandInfoOrPrefix() = default;
|
||||
};
|
||||
|
||||
void RegisterPrefix(const std::string &group_name, const char prefix,
|
||||
const std::string &name, const std::string &desc) {
|
||||
commands_[group_name].command_info = {nullptr, prefix, name, desc};
|
||||
}
|
||||
|
||||
void RegisterSubcommand(const std::string &group_name,
|
||||
const std::string &shortcut, const char mnemonic,
|
||||
const std::string &name, const std::string &desc,
|
||||
Command command) {
|
||||
commands_[group_name].subcommands[shortcut].command_info = {
|
||||
command, mnemonic, name, desc};
|
||||
}
|
||||
|
||||
void RegisterCommand(const std::string &shortcut, Command command,
|
||||
char mnemonic, const std::string &name,
|
||||
const std::string &desc) {
|
||||
commands_[shortcut].command_info = {std::move(command), mnemonic, name,
|
||||
desc};
|
||||
}
|
||||
|
||||
void ExecuteCommand(const std::string &shortcut) {
|
||||
if (commands_.find(shortcut) != commands_.end()) {
|
||||
commands_[shortcut].command_info.command();
|
||||
}
|
||||
}
|
||||
|
||||
void ShowWhichKey();
|
||||
|
||||
void SaveKeybindings(const std::string &filepath);
|
||||
void LoadKeybindings(const std::string &filepath);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, CommandInfoOrPrefix> commands_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_COMMAND_MANAGER_H
|
||||
77
src/app/editor/system/constant_manager.h
Normal file
77
src/app/editor/system/constant_manager.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_CONSTANT_MANAGER_H
|
||||
#define YAZE_APP_EDITOR_SYSTEM_CONSTANT_MANAGER_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "app/zelda3/overworld/overworld_map.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class ConstantManager {
|
||||
public:
|
||||
void ShowConstantManager() {
|
||||
ImGui::Begin("Constant Manager");
|
||||
|
||||
// Tab bar for the different types of constants
|
||||
// Overworld, dungeon, graphics, expanded
|
||||
ImGui::TextWrapped(
|
||||
"This is the constant manager. It allows you to view and edit "
|
||||
"constants in the ROM. You should only edit these if you know what "
|
||||
"you're doing.");
|
||||
|
||||
if (ImGui::BeginTabBar("Constant Manager Tabs")) {
|
||||
if (ImGui::BeginTabItem("Overworld")) {
|
||||
ImGui::Text("Overworld constants");
|
||||
ImGui::Separator();
|
||||
ImGui::Text("OverworldCustomASMHasBeenApplied: %d",
|
||||
zelda3::overworld::OverworldCustomASMHasBeenApplied);
|
||||
ImGui::Text("OverworldCustomAreaSpecificBGPalette: %d",
|
||||
zelda3::overworld::OverworldCustomAreaSpecificBGPalette);
|
||||
ImGui::Text("OverworldCustomAreaSpecificBGEnabled: %d",
|
||||
zelda3::overworld::OverworldCustomAreaSpecificBGEnabled);
|
||||
ImGui::Text("OverworldCustomMainPaletteArray: %d",
|
||||
zelda3::overworld::OverworldCustomMainPaletteArray);
|
||||
ImGui::Text("OverworldCustomMainPaletteEnabled: %d",
|
||||
zelda3::overworld::OverworldCustomMainPaletteEnabled);
|
||||
ImGui::Text("OverworldCustomMosaicArray: %d",
|
||||
zelda3::overworld::OverworldCustomMosaicArray);
|
||||
ImGui::Text("OverworldCustomMosaicEnabled: %d",
|
||||
zelda3::overworld::OverworldCustomMosaicEnabled);
|
||||
ImGui::Text("OverworldCustomAnimatedGFXArray: %d",
|
||||
zelda3::overworld::OverworldCustomAnimatedGFXArray);
|
||||
ImGui::Text("OverworldCustomAnimatedGFXEnabled: %d",
|
||||
zelda3::overworld::OverworldCustomAnimatedGFXEnabled);
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Dungeon")) {
|
||||
ImGui::Text("Dungeon constants");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Graphics")) {
|
||||
ImGui::Text("Graphics constants");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Expanded")) {
|
||||
ImGui::Text("Expanded constants");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_CONSTANT_MANAGER_H
|
||||
85
src/app/editor/system/extension_manager.cc
Normal file
85
src/app/editor/system/extension_manager.cc
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "extension_manager.h"
|
||||
|
||||
#if defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||
defined(__APPLE__) && defined(__MACH__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <system/extension.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
void ExtensionManager::LoadExtension(const std::string& filename,
|
||||
yaze_editor_context* context) {
|
||||
#if defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||
defined(__APPLE__) && defined(__MACH__)
|
||||
auto extension_path = filename.c_str();
|
||||
void* handle = dlopen(extension_path, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
std::cerr << "Cannot open extension: " << dlerror() << std::endl;
|
||||
return;
|
||||
}
|
||||
dlerror(); // Clear any existing error
|
||||
|
||||
// Load the symbol to retrieve the extension
|
||||
auto get_extension = reinterpret_cast<yaze_extension* (*)()>(
|
||||
dlsym(handle, "get_yaze_extension"));
|
||||
const char* dlsym_error = dlerror();
|
||||
if (dlsym_error) {
|
||||
std::cerr << "Cannot load symbol 'get_yaze_extension': " << dlsym_error
|
||||
<< std::endl;
|
||||
dlclose(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
yaze_extension* extension = get_extension();
|
||||
if (extension && extension->initialize) {
|
||||
extension->initialize(context);
|
||||
} else {
|
||||
std::cerr << "Failed to initialize the extension." << std::endl;
|
||||
dlclose(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
extensions_.push_back(extension);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExtensionManager::RegisterExtension(yaze_extension* extension) {
|
||||
extensions_.push_back(extension);
|
||||
}
|
||||
|
||||
void ExtensionManager::InitializeExtensions(yaze_editor_context* context) {
|
||||
for (auto& extension : extensions_) {
|
||||
extension->initialize(context);
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionManager::ShutdownExtensions() {
|
||||
for (auto& extension : extensions_) {
|
||||
extension->cleanup();
|
||||
}
|
||||
|
||||
// if (handle) {
|
||||
// dlclose(handle);
|
||||
// handle = nullptr;
|
||||
// extension = nullptr;
|
||||
// }
|
||||
}
|
||||
|
||||
void ExtensionManager::ExecuteExtensionUI(yaze_editor_context* context) {
|
||||
for (auto& extension : extensions_) {
|
||||
if (extension->extend_ui) {
|
||||
extension->extend_ui(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
29
src/app/editor/system/extension_manager.h
Normal file
29
src/app/editor/system/extension_manager.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_EXTENSION_MANAGER_H
|
||||
#define YAZE_APP_EDITOR_SYSTEM_EXTENSION_MANAGER_H
|
||||
|
||||
#include <system/extension.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class ExtensionManager {
|
||||
public:
|
||||
void LoadExtension(const std::string& filename, yaze_editor_context* context);
|
||||
void RegisterExtension(yaze_extension* extension);
|
||||
void InitializeExtensions(yaze_editor_context* context);
|
||||
void ShutdownExtensions();
|
||||
void ExecuteExtensionUI(yaze_editor_context* context);
|
||||
|
||||
private:
|
||||
std::vector<yaze_extension*> extensions_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_EXTENSION_MANAGER_H
|
||||
@@ -1,9 +1,8 @@
|
||||
#ifndef YAZE_APP_EDITOR_UTILS_FLAGS_H
|
||||
#define YAZE_APP_EDITOR_UTILS_FLAGS_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include "core/common.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -31,6 +30,8 @@ struct FlagsMenu : public core::ExperimentFlags {
|
||||
&mutable_flags()->overworld.kSaveOverworldItems);
|
||||
Checkbox("Save Overworld Properties",
|
||||
&mutable_flags()->overworld.kSaveOverworldProperties);
|
||||
Checkbox("Load Custom Overworld",
|
||||
&mutable_flags()->overworld.kLoadCustomOverworld);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@@ -42,21 +43,16 @@ struct FlagsMenu : public core::ExperimentFlags {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (BeginMenu("Emulator Flags")) {
|
||||
Checkbox("Load Audio Device", &mutable_flags()->kLoadAudioDevice);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
Checkbox("Use built-in file dialog",
|
||||
&mutable_flags()->kNewFileDialogWrapper);
|
||||
Checkbox("Enable Console Logging", &mutable_flags()->kLogToConsole);
|
||||
Checkbox("Enable Texture Streaming",
|
||||
&mutable_flags()->kLoadTexturesAsStreaming);
|
||||
Checkbox("Use Bitmap Manager", &mutable_flags()->kUseBitmapManager);
|
||||
Checkbox("Log Instructions to Debugger",
|
||||
&mutable_flags()->kLogInstructions);
|
||||
Checkbox("Save All Palettes", &mutable_flags()->kSaveAllPalettes);
|
||||
Checkbox("Save Gfx Groups", &mutable_flags()->kSaveGfxGroups);
|
||||
Checkbox("Save Graphics Sheets", &mutable_flags()->kSaveGraphicsSheet);
|
||||
Checkbox("Use New ImGui Input", &mutable_flags()->kUseNewImGuiInput);
|
||||
}
|
||||
};
|
||||
32
src/app/editor/system/history_manager.h
Normal file
32
src/app/editor/system/history_manager.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_HISTORY_MANAGER_H
|
||||
#define YAZE_APP_EDITOR_SYSTEM_HISTORY_MANAGER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
// System history manager, undo and redo.
|
||||
class HistoryManager {
|
||||
public:
|
||||
HistoryManager() = default;
|
||||
~HistoryManager() = default;
|
||||
|
||||
void Add(const char* data);
|
||||
void Undo();
|
||||
void Redo();
|
||||
|
||||
private:
|
||||
std::vector<const char*> history_;
|
||||
std::stack<const char*> undo_;
|
||||
std::stack<const char*> redo_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_HISTORY_MANAGER_H
|
||||
19
src/app/editor/system/popup_manager.cc
Normal file
19
src/app/editor/system/popup_manager.cc
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "popup_manager.h"
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
PopupManager::PopupManager() {
|
||||
}
|
||||
|
||||
PopupManager::~PopupManager() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
21
src/app/editor/system/popup_manager.h
Normal file
21
src/app/editor/system/popup_manager.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef YAZE_APP_EDITOR_POPUP_MANAGER_H
|
||||
#define YAZE_APP_EDITOR_POPUP_MANAGER_H
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
// ImGui popup manager.
|
||||
class PopupManager {
|
||||
public:
|
||||
PopupManager();
|
||||
~PopupManager();
|
||||
|
||||
void Show(const char* name);
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_POPUP_MANAGER_H
|
||||
30
src/app/editor/system/resource_manager.h
Normal file
30
src/app/editor/system/resource_manager.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef YAZE_APP_EDITOR_SYSTEM_RESOURCE_MANAGER_H
|
||||
#define YAZE_APP_EDITOR_SYSTEM_RESOURCE_MANAGER_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
// System resource manager.
|
||||
class ResourceManager {
|
||||
public:
|
||||
ResourceManager() : count_(0) {}
|
||||
~ResourceManager() = default;
|
||||
|
||||
void Load(const char* path);
|
||||
void Unload(const char* path);
|
||||
void UnloadAll();
|
||||
|
||||
size_t Count() const;
|
||||
|
||||
private:
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_SYSTEM_RESOURCE_MANAGER_H
|
||||
@@ -1,11 +1,9 @@
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
#include "app/editor/system/settings_editor.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/editor/utils/flags.h"
|
||||
#include "app/editor/utils/keyboard_shortcuts.h"
|
||||
#include "app/editor/settings_editor.h"
|
||||
#include "app/editor/utils/flags.h"
|
||||
#include "app/editor/system/flags.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/editor/utils/editor.h"
|
||||
#include "app/editor/editor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -1,26 +0,0 @@
|
||||
#include "app/editor/utils/gfx_context.h"
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "app/editor/graphics/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/gui/canvas.h"
|
||||
#include "app/gui/icons.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
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef YAZE_APP_EDITOR_VRAM_CONTEXT_H
|
||||
#define YAZE_APP_EDITOR_VRAM_CONTEXT_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#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/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
namespace context {
|
||||
|
||||
/**
|
||||
* @brief Shared graphical context across editors.
|
||||
*/
|
||||
class GfxContext {
|
||||
protected:
|
||||
// Palettesets for the tile16 individual tiles
|
||||
static std::unordered_map<uint8_t, gfx::Paletteset> palettesets_;
|
||||
};
|
||||
|
||||
} // namespace context
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_VRAM_CONTEXT_H
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef YAZE_APP_EDITOR_UTILS_KEYBOARD_SHORTCUTS_H
|
||||
#define YAZE_APP_EDITOR_UTILS_KEYBOARD_SHORTCUTS_H
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
struct KeyboardShortcuts {
|
||||
enum class ShortcutType {
|
||||
kCut,
|
||||
kCopy,
|
||||
kPaste,
|
||||
kUndo,
|
||||
kRedo,
|
||||
kFind,
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_UTILS_KEYBOARD_SHORTCUTS_H_
|
||||
@@ -1,64 +0,0 @@
|
||||
#ifndef YAZE_APP_EDITOR_UTILS_RECENT_FILES_H
|
||||
#define YAZE_APP_EDITOR_UTILS_RECENT_FILES_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
|
||||
class RecentFilesManager {
|
||||
public:
|
||||
RecentFilesManager(const std::string& filename) : filename_(filename) {}
|
||||
|
||||
void AddFile(const std::string& filePath) {
|
||||
// Add a file to the list, avoiding duplicates
|
||||
auto it = std::find(recentFiles_.begin(), recentFiles_.end(), filePath);
|
||||
if (it == recentFiles_.end()) {
|
||||
recentFiles_.push_back(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void Save() {
|
||||
std::ofstream file(filename_);
|
||||
if (!file.is_open()) {
|
||||
return; // Handle the error appropriately
|
||||
}
|
||||
|
||||
for (const auto& filePath : recentFiles_) {
|
||||
file << filePath << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Load() {
|
||||
std::ifstream file(filename_);
|
||||
if (!file.is_open()) {
|
||||
return; // Handle the error appropriately
|
||||
}
|
||||
|
||||
recentFiles_.clear();
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
if (!line.empty()) {
|
||||
recentFiles_.push_back(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string>& GetRecentFiles() const {
|
||||
return recentFiles_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string filename_;
|
||||
std::vector<std::string> recentFiles_;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_UTILS_RECENT_FILES_H
|
||||
Reference in New Issue
Block a user