From 3d2cd4dc799d96ad60f5befc618a9878aa98e0fa Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sat, 10 Sep 2022 18:48:47 -0500 Subject: [PATCH 01/16] start yaze_delta side project --- src/CMakeLists.txt | 40 +++++++++++ src/app/core/controller.h | 1 + src/app/delta/delta.cc | 33 +++++++++ src/app/delta/delta.proto | 40 +++++++++++ src/app/delta/viewer.cc | 146 ++++++++++++++++++++++++++++++++++++++ src/app/delta/viewer.h | 33 +++++++++ 6 files changed, 293 insertions(+) create mode 100644 src/app/delta/delta.cc create mode 100644 src/app/delta/delta.proto create mode 100644 src/app/delta/viewer.cc create mode 100644 src/app/delta/viewer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 502d057d..c8dad48f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -139,6 +139,46 @@ set_target_properties(yaze LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/yaze.res" ) +# + +add_executable( + yaze_delta + app/delta/delta.cc + app/delta/viewer.cc + app/rom.cc + ${YAZE_APP_ASM_SRC} + ${YAZE_APP_CORE_SRC} + ${YAZE_APP_EDITOR_SRC} + ${YAZE_APP_GFX_SRC} + ${YAZE_APP_ZELDA3_SRC} + ${YAZE_GUI_SRC} + ${IMGUI_SRC} + lib/asar/src/asar-dll-bindings/c/asardll.c +) + +target_include_directories( + yaze_delta PUBLIC + lib/ + app/ + ${ASAR_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/src/ + ${PNG_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIR} + ${GLEW_INCLUDE_DIRS} + lib/asar/src/asar-dll-bindings/c +) + +target_link_libraries( + yaze_delta PUBLIC + ${ABSL_TARGETS} + ${SDL_TARGETS} + ${PNG_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${CMAKE_DL_LIBS} + ImGui +) + set (source "${CMAKE_SOURCE_DIR}/assets") set (destination "${CMAKE_CURRENT_BINARY_DIR}/assets") add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD diff --git a/src/app/core/controller.h b/src/app/core/controller.h index d3bb255b..ba5af3e4 100644 --- a/src/app/core/controller.h +++ b/src/app/core/controller.h @@ -26,6 +26,7 @@ class Controller { absl::Status onEntry(); void onInput(); void onLoad(); + void onLoadDelta(); void doRender() const; void onExit() const; diff --git a/src/app/delta/delta.cc b/src/app/delta/delta.cc new file mode 100644 index 00000000..39e604d1 --- /dev/null +++ b/src/app/delta/delta.cc @@ -0,0 +1,33 @@ +#if defined(_WIN32) +#define main SDL_main +#endif + +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/symbolize.h" +#include "app/core/controller.h" +#include "app/delta/viewer.h" + +int main(int argc, char** argv) { + absl::InitializeSymbolizer(argv[0]); + + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); + + yaze::app::core::Controller controller; + yaze::app::delta::Viewer viewer; + + auto entry_status = controller.onEntry(); + if (!entry_status.ok()) { + // TODO(@scawful): log the specific error + return EXIT_FAILURE; + } + + while (controller.isActive()) { + controller.onInput(); + viewer.Update(); + controller.doRender(); + } + controller.onExit(); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/src/app/delta/delta.proto b/src/app/delta/delta.proto new file mode 100644 index 00000000..fc67285d --- /dev/null +++ b/src/app/delta/delta.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; +option cc_enable_arenas = true; + +service YazeDelta { + rpc Init(InitRequest) returns (InitResponse) {} + + rpc Push(PushRequest) returns (PushResponse) {} + rpc Pull(PullRequest) returns (PullResponse) {} + + rpc CreateBranch(CreateBranchRequest) returns (CreateBranchResponse) {} + rpc DeleteBranch(DeleteBranchRequest) returns (DeleteBranchResponse) {} + + rpc Merge(MergeRequest) returns (MergeResponse) {} + rpc UndoMerge(UndoMergeRequest) returns (UndoMergeResponse) {} +} + +message InitRequest { + string project_name = 1; + repeated uint16_t bytes = 2; +} + +message PushRequest { + string username = 1; +} +message PushResponse {} + +message PullRequest {} +message PullResponse {} + +message CreateBranchRequest {} +message CreateBranchResponse {} + +message DeleteBranchRequest {} +message DeleteBranchResponse {} + +message MergeRequest {} +message MergeResponse {} + +message UndoMergeRequest {} +message UndoMergeResponse {} \ No newline at end of file diff --git a/src/app/delta/viewer.cc b/src/app/delta/viewer.cc new file mode 100644 index 00000000..79bbad6e --- /dev/null +++ b/src/app/delta/viewer.cc @@ -0,0 +1,146 @@ +#include "viewer.h" + +#include +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "app/core/constants.h" +#include "app/gfx/snes_palette.h" +#include "app/gfx/snes_tile.h" +#include "app/rom.h" +#include "gui/canvas.h" +#include "gui/icons.h" +#include "gui/input.h" + +namespace yaze { +namespace app { +namespace delta { +namespace { + +constexpr ImGuiWindowFlags kMainEditorFlags = + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | + ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar; + +void NewMasterFrame() { + const ImGuiIO& io = ImGui::GetIO(); + ImGui::NewFrame(); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImVec2 dimensions(io.DisplaySize.x, io.DisplaySize.y); + ImGui::SetNextWindowSize(dimensions, ImGuiCond_Always); + + if (!ImGui::Begin("##YazeMain", nullptr, kMainEditorFlags)) { + ImGui::End(); + return; + } +} + +bool BeginCentered(const char* name) { + ImGuiIO const& io = ImGui::GetIO(); + ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f); + ImGui::SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + ImGuiWindowFlags flags = + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings; + return ImGui::Begin(name, nullptr, flags); +} + +void DisplayStatus(absl::Status& status) { + if (BeginCentered("StatusWindow")) { + ImGui::Text("%s", status.ToString().c_str()); + ImGui::Spacing(); + ImGui::NextColumn(); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::NewLine(); + ImGui::SameLine(270); + if (ImGui::Button("OK", ImVec2(200, 0))) { + status = absl::OkStatus(); + } + ImGui::End(); + } +} + +} // namespace + +void Viewer::Update() { + NewMasterFrame(); + DrawBranchTree(); + ImGui::End(); +} + +void Viewer::DrawBranchTree() { + static ImGuiTableFlags flags = + ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | + ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | + ImGuiTableFlags_NoBordersInBody; + + if (ImGui::BeginTable("3ways", 3, flags)) { + // The first column will use the default _WidthStretch when ScrollX is Off + // and _WidthFixed when ScrollX is On + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, + 10 * 12.0f); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, + 10 * 18.0f); + ImGui::TableHeadersRow(); + + // Simple storage to output a dummy file-system. + struct MyTreeNode { + const char* Name; + const char* Type; + int Size; + int ChildIdx; + int ChildCount; + static void DisplayNode(const MyTreeNode* node, + const MyTreeNode* all_nodes) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + const bool is_folder = (node->ChildCount > 0); + if (is_folder) { + bool open = + ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TableNextColumn(); + ImGui::TextDisabled("--"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); + if (open) { + for (int child_n = 0; child_n < node->ChildCount; child_n++) + DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes); + ImGui::TreePop(); + } + } else { + ImGui::TreeNodeEx( + node->Name, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | + ImGuiTreeNodeFlags_NoTreePushOnOpen | + ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TableNextColumn(); + ImGui::Text("%d", node->Size); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); + } + } + }; + static const MyTreeNode nodes[] = { + {"Root", "Folder", -1, 1, 3}, // 0 + {"Music", "Folder", -1, 4, 2}, // 1 + {"Textures", "Folder", -1, 6, 3}, // 2 + {"desktop.ini", "System file", 1024, -1, -1}, // 3 + {"File1_a.wav", "Audio file", 123000, -1, -1}, // 4 + {"File1_b.wav", "Audio file", 456000, -1, -1}, // 5 + {"Image001.png", "Image file", 203128, -1, -1}, // 6 + {"Copy of Image001.png", "Image file", 203256, -1, -1}, // 7 + {"Copy of Image001 (Final2).png", "Image file", 203512, -1, -1}, // 8 + }; + + MyTreeNode::DisplayNode(&nodes[0], nodes); + + ImGui::EndTable(); + } +} +} // namespace delta +} // namespace app +} // namespace yaze \ No newline at end of file diff --git a/src/app/delta/viewer.h b/src/app/delta/viewer.h new file mode 100644 index 00000000..6cd7903b --- /dev/null +++ b/src/app/delta/viewer.h @@ -0,0 +1,33 @@ +#ifndef YAZE_APP_DELTA_VIEWER_H +#define YAZE_APP_DELTA_VIEWER_H + +#include +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "app/core/constants.h" +#include "app/gfx/snes_palette.h" +#include "app/gfx/snes_tile.h" +#include "app/rom.h" +#include "gui/canvas.h" +#include "gui/icons.h" +#include "gui/input.h" + +namespace yaze { +namespace app { +namespace delta { +class Viewer { + public: + void Update(); + + private: + void DrawBranchTree(); +}; +} // namespace delta +} // namespace app +} // namespace yaze + +#endif \ No newline at end of file From e4b802c3b08b88d771317aeb4fd9924ee1911651 Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sat, 10 Sep 2022 21:48:24 -0500 Subject: [PATCH 02/16] delta client/server infrastructure --- src/CMakeLists.txt | 4 ++- src/app/delta/CMakeLists.txt | 32 ++++++++++++++++++++++ src/app/delta/client.cc | 53 ++++++++++++++++++++++++++++++++++++ src/app/delta/client.h | 44 ++++++++++++++++++++++++++++++ src/app/delta/delta.cc | 1 - src/app/delta/delta.proto | 48 +++++++++++++++++++++++++++++--- src/app/delta/service.cc | 42 ++++++++++++++++++++++++++++ src/app/delta/service.h | 37 +++++++++++++++++++++++++ 8 files changed, 255 insertions(+), 6 deletions(-) create mode 100644 src/app/delta/CMakeLists.txt create mode 100644 src/app/delta/client.cc create mode 100644 src/app/delta/client.h create mode 100644 src/app/delta/service.cc create mode 100644 src/app/delta/service.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c8dad48f..18ee10aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -139,12 +139,13 @@ set_target_properties(yaze LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/yaze.res" ) -# +add_subdirectory(app/delta) add_executable( yaze_delta app/delta/delta.cc app/delta/viewer.cc + app/delta/client.cc app/rom.cc ${YAZE_APP_ASM_SRC} ${YAZE_APP_CORE_SRC} @@ -176,6 +177,7 @@ target_link_libraries( ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS} + delta-service ImGui ) diff --git a/src/app/delta/CMakeLists.txt b/src/app/delta/CMakeLists.txt new file mode 100644 index 00000000..087dd9f7 --- /dev/null +++ b/src/app/delta/CMakeLists.txt @@ -0,0 +1,32 @@ + +add_library(delta-service delta.proto) +target_link_libraries(delta-service + PUBLIC + protobuf::libprotobuf + gRPC::grpc + gRPC::grpc++ +) + +target_include_directories(delta-service + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR} + ${PROTOBUF_INCLUDE_PATH} +) + +get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION) + +# compile the message types +protobuf_generate(TARGET delta-service LANGUAGE cpp) + +# compile the GRPC services +protobuf_generate( + TARGET + delta-service + LANGUAGE + grpc + GENERATE_EXTENSIONS + .grpc.pb.h + .grpc.pb.cc + PLUGIN + "protoc-gen-grpc=${grpc_cpp_plugin_location}" +) \ No newline at end of file diff --git a/src/app/delta/client.cc b/src/app/delta/client.cc new file mode 100644 index 00000000..b90f5e20 --- /dev/null +++ b/src/app/delta/client.cc @@ -0,0 +1,53 @@ +#include "client.h" + +#include +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "src/app/delta/delta.grpc.pb.h" +#include "src/app/delta/delta.pb.h" + +namespace yaze { +namespace app { +namespace delta { + +using grpc::Channel; +using grpc::ClientAsyncResponseReader; +using grpc::ClientContext; +using grpc::CompletionQueue; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::Status; + +void Client::CreateChannel() { + auto channel = grpc::CreateChannel("localhost:50051", + grpc::InsecureChannelCredentials()); + stub_ = ::YazeDelta::NewStub(channel); +} + +absl::Status Client::InitRepo(std::string author_name, + std::string project_name) { + Repository new_repo; + new_repo.set_author_name(author_name); + new_repo.set_project_name(project_name); + + InitRequest request; + request.set_allocated_repo(&new_repo); + + InitResponse response; + Status status = stub_->Init(&rpc_context, request, &response); + + if (!status.ok()) { + std::cerr << status.error_code() << ": " << status.error_message() + << std::endl; + return absl::InternalError(status.error_message()); + } + return absl::OkStatus(); +} + +} // namespace delta +} // namespace app +} // namespace yaze diff --git a/src/app/delta/client.h b/src/app/delta/client.h new file mode 100644 index 00000000..0c5cb0c2 --- /dev/null +++ b/src/app/delta/client.h @@ -0,0 +1,44 @@ +#ifndef YAZE_APP_DELTA_CLIENT_H +#define YAZE_APP_DELTA_CLIENT_H + +#include +#include +#include +#include +#include + +#include + +#include "absl/status/status.h" +#include "src/app/delta/delta.grpc.pb.h" +#include "src/app/delta/delta.pb.h" + + +namespace yaze { +namespace app { +namespace delta { + +using grpc::Channel; +using grpc::ClientAsyncResponseReader; +using grpc::ClientContext; +using grpc::CompletionQueue; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::Status; + +class Client { + public: + void CreateChannel(); + absl::Status InitRepo(std::string author_name, std::string project_name); + + private: + ClientContext rpc_context; + std::vector repos_; + std::unique_ptr stub_; +}; + +} // namespace delta +} // namespace app +} // namespace yaze + +#endif \ No newline at end of file diff --git a/src/app/delta/delta.cc b/src/app/delta/delta.cc index 39e604d1..4a413d67 100644 --- a/src/app/delta/delta.cc +++ b/src/app/delta/delta.cc @@ -18,7 +18,6 @@ int main(int argc, char** argv) { auto entry_status = controller.onEntry(); if (!entry_status.ok()) { - // TODO(@scawful): log the specific error return EXIT_FAILURE; } diff --git a/src/app/delta/delta.proto b/src/app/delta/delta.proto index fc67285d..4ed2fd66 100644 --- a/src/app/delta/delta.proto +++ b/src/app/delta/delta.proto @@ -4,9 +4,13 @@ option cc_enable_arenas = true; service YazeDelta { rpc Init(InitRequest) returns (InitResponse) {} + rpc Clone(CloneRequest) returns (CloneResponse) {} + rpc Push(PushRequest) returns (PushResponse) {} rpc Pull(PullRequest) returns (PullResponse) {} + rpc Sync(stream SyncRequest) returns (stream SyncResponse) {} + rpc CreateBranch(CreateBranchRequest) returns (CreateBranchResponse) {} rpc DeleteBranch(DeleteBranchRequest) returns (DeleteBranchResponse) {} @@ -14,19 +18,55 @@ service YazeDelta { rpc UndoMerge(UndoMergeRequest) returns (UndoMergeResponse) {} } -message InitRequest { - string project_name = 1; - repeated uint16_t bytes = 2; +message Commit { + int64 commit_id = 1; + int64 parent_commit_id = 2; + string author_name = 3; + string message_header = 4; + optional string message_body = 5; + bytes data = 6; + int64 signature = 7; } +message Branch { + string branch_name = 1; + optional string parent_name = 2; + repeated Commit commits = 3; +} + +message Repository { + string project_name = 1; + string author_name = 2; + int64 signature = 3; + optional bool locked = 4; + optional string password = 5; + repeated Branch tree = 6; +} + +message InitRequest { + Repository repo = 1; +} + +message InitResponse { + int32 response = 1; +} + +message CloneRequest {} + +message CloneResponse {} + message PushRequest { - string username = 1; + string author_name = 1; } message PushResponse {} message PullRequest {} message PullResponse {} +message SyncRequest {} + +message SyncResponse {} + message CreateBranchRequest {} message CreateBranchResponse {} diff --git a/src/app/delta/service.cc b/src/app/delta/service.cc new file mode 100644 index 00000000..b88d3f33 --- /dev/null +++ b/src/app/delta/service.cc @@ -0,0 +1,42 @@ +#include "service.h" + +#include +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "src/app/delta/delta.grpc.pb.h" +#include "src/app/delta/delta.pb.h" + +namespace yaze { +namespace app { +namespace delta { + +using grpc::Channel; +using grpc::ClientAsyncResponseReader; +using grpc::ClientContext; +using grpc::CompletionQueue; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::Status; + +Status DeltaService::Init(grpc::ServerContext* context, + const InitRequest* request, InitResponse* reply) { + return Status::OK; +} + +Status DeltaService::Push(grpc::ServerContext* context, + const PushRequest* request, PushResponse* reply) { + return Status::OK; +} + +Status DeltaService::Pull(grpc::ServerContext* context, + const PullRequest* request, PullResponse* reply) { + return Status::OK; +} + +} // namespace delta +} // namespace app +} // namespace yaze diff --git a/src/app/delta/service.h b/src/app/delta/service.h new file mode 100644 index 00000000..1bf1ab35 --- /dev/null +++ b/src/app/delta/service.h @@ -0,0 +1,37 @@ +#ifndef YAZE_APP_DELTA_SERVICE_H +#define YAZE_APP_DELTA_SERVICE_H + +#include +#include +#include +#include +#include + +#include + +#include "absl/status/status.h" +#include "src/app/delta/delta.grpc.pb.h" +#include "src/app/delta/delta.pb.h" + +namespace yaze { +namespace app { +namespace delta { + +class DeltaService final : public ::YazeDelta::Service { + public: + Status Init(grpc::ServerContext* context, const InitRequest* request, + InitResponse* reply) override; + + Status Push(grpc::ServerContext* context, const PushRequest* request, + PushResponse* reply) override; + + Status Pull(grpc::ServerContext* context, const PullRequest* request, + PullResponse* reply) override; + + private: + std::vector repos_; +}; + +} // namespace delta +} // namespace app +} // namespace yaze From 2c0bbd345732cc3e0389fc551185b47dc7066c68 Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sat, 10 Sep 2022 21:48:49 -0500 Subject: [PATCH 03/16] naming refactor --- src/app/editor/overworld_editor.cc | 25 +++++++++---------------- src/app/editor/overworld_editor.h | 14 +++++++------- src/app/gfx/bitmap.cc | 10 ++++++---- src/app/zelda3/overworld.h | 18 +++++++++--------- src/app/zelda3/overworld_map.cc | 3 ++- src/app/zelda3/overworld_map.h | 11 ++++------- 6 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 86083c2b..98a3077e 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -44,25 +44,21 @@ absl::Status OverworldEditor::Update() { all_gfx_loaded_ = true; RETURN_IF_ERROR(overworld_.Load(rom_)) - current_gfx_bmp_.Create(128, 512, 64, overworld_.GetCurrentGraphics()); + palette_ = overworld_.AreaPalette(); + current_gfx_bmp_.Create(128, 512, 64, overworld_.AreaGraphics()); + current_gfx_bmp_.ApplyPalette(palette_); rom_.RenderBitmap(¤t_gfx_bmp_); - auto tile16_palette = overworld_.GetCurrentPalette(); - tile16_blockset_bmp_.Create(128, 8192, 128, - overworld_.GetCurrentBlockset()); - for (int j = 0; j < tile16_palette.colors.size(); j++) { - tile16_blockset_bmp_.SetPaletteColor(j, tile16_palette.GetColor(j)); - } + tile16_blockset_bmp_.Create(128, 8192, 128, overworld_.Tile16Blockset()); + tile16_blockset_bmp_.ApplyPalette(palette_); rom_.RenderBitmap(&tile16_blockset_bmp_); map_blockset_loaded_ = true; for (int i = 0; i < core::kNumOverworldMaps; ++i) { overworld_.SetCurrentMap(i); - auto palette = overworld_.GetCurrentPalette(); - maps_bmp_[i].Create(512, 512, 512, overworld_.GetCurrentBitmapData()); - for (int j = 0; j < palette.colors.size(); j++) { - maps_bmp_[i].SetPaletteColor(j, palette.GetColor(j)); - } + auto palette = overworld_.AreaPalette(); + maps_bmp_[i].Create(512, 512, 512, overworld_.BitmapData()); + maps_bmp_[i].ApplyPalette(palette); rom_.RenderBitmap(&(maps_bmp_[i])); } } @@ -73,10 +69,7 @@ absl::Status OverworldEditor::Update() { } UpdateSelectedTile16(selected_tile_, tile16_blockset_bmp_, selected_tile_bmp_); - auto palette = overworld_.GetCurrentPalette(); - for (int j = 0; j < palette.colors.size(); j++) { - selected_tile_bmp_.SetPaletteColor(j, palette.GetColor(j)); - } + selected_tile_bmp_.ApplyPalette(palette_); rom_.RenderBitmap(&selected_tile_bmp_); update_selected_tile_ = false; } diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index 16471469..2a4a07ac 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -29,10 +29,10 @@ static constexpr uint kTile8DisplayHeight = 64; static constexpr float kInputFieldSize = 30.f; static constexpr absl::string_view kToolsetColumnNames[] = { - "#undoTool", "#redoTool", "#drawTool", "#separator2", - "#zoomOutTool", "#zoomInTool", "#separator", "#history", - "#entranceTool", "#exitTool", "#itemTool", "#spriteTool", - "#transportTool", "#musicTool" }; + "#undoTool", "#redoTool", "#drawTool", "#separator2", + "#zoomOutTool", "#zoomInTool", "#separator", "#history", + "#entranceTool", "#exitTool", "#itemTool", "#spriteTool", + "#transportTool", "#musicTool"}; static constexpr absl::string_view kOverworldSettingsColumnNames[] = { "##1stCol", "##gfxCol", "##palCol", "##sprgfxCol", @@ -90,9 +90,9 @@ class OverworldEditor { zelda3::Overworld overworld_; gfx::SNESPalette palette_; - gfx::Bitmap tile16_blockset_bmp_; // pointer size 1048576 - gfx::Bitmap current_gfx_bmp_; // pointer size 32768 - gfx::Bitmap all_gfx_bmp; // pointer size 456704 + gfx::Bitmap tile16_blockset_bmp_; + gfx::Bitmap current_gfx_bmp_; + gfx::Bitmap all_gfx_bmp; gfx::Bitmap selected_tile_bmp_; gui::Canvas overworld_map_canvas_; diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index 58844d18..1c20c956 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -103,11 +103,13 @@ void Bitmap::CreateTexture(std::shared_ptr renderer) { } // Convert SNESPalette to SDL_Palette for surface. -void Bitmap::ApplyPalette(const SNESPalette & palette) { +void Bitmap::ApplyPalette(const SNESPalette &palette) { palette_ = palette; - SDL_SetPaletteColors(surface_->format->palette, - palette_.GetSDL_Palette()->colors, - 0, 256); + for (int i = 0; i < palette.size_; ++i) { + surface_->format->palette->colors[i].r = palette.GetColor(i).rgb.x; + surface_->format->palette->colors[i].g = palette.GetColor(i).rgb.y; + surface_->format->palette->colors[i].b = palette.GetColor(i).rgb.z; + } } void Bitmap::SetPaletteColor(int id, gfx::SNESColor color) { diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index 5ea21356..c5d97f9d 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -24,18 +24,18 @@ class Overworld { auto GetTiles16() const { return tiles16; } auto GetOverworldMap(uint index) { return overworld_maps_[index]; } auto GetOverworldMaps() const { return overworld_maps_; } - auto GetCurrentBlockset() const { - return overworld_maps_[current_map_].GetCurrentBlockset(); + + auto AreaGraphics() const { + return overworld_maps_[current_map_].AreaGraphics(); } - auto GetCurrentGraphics() const { - return overworld_maps_[current_map_].GetCurrentGraphics(); + auto AreaPalette() const { + return overworld_maps_[current_map_].AreaPalette(); } - auto GetCurrentBitmapData() const { - return overworld_maps_[current_map_].GetBitmapData(); - } - auto GetCurrentPalette() const { - return overworld_maps_[current_map_].GetCurrentPalette(); + auto BitmapData() const { return overworld_maps_[current_map_].BitmapData(); } + auto Tile16Blockset() const { + return overworld_maps_[current_map_].Tile16Blockset(); } + auto isLoaded() const { return is_loaded_; } void SetCurrentMap(int i) { current_map_ = i; } diff --git a/src/app/zelda3/overworld_map.cc b/src/app/zelda3/overworld_map.cc index 85283d92..0c6388b5 100644 --- a/src/app/zelda3/overworld_map.cc +++ b/src/app/zelda3/overworld_map.cc @@ -156,6 +156,7 @@ OverworldMap::OverworldMap(int index, ROM& rom, absl::Status OverworldMap::BuildMap(int count, int game_state, int world, uchar* map_parent, OWBlockset& world_blockset) { + game_state_ = game_state; world_ = world; if (large_map_) { parent_ = map_parent[index_]; @@ -496,7 +497,7 @@ absl::Status OverworldMap::BuildTiles16Gfx(int count) { auto destination = xx + yy + offset + (mx + (my * 0x80)); current_blockset_[destination] = - current_gfx_[source] + (info.palette_ * 0x10); + (current_gfx_[source] & 0x0F) + (info.palette_ * 0x10); } } } diff --git a/src/app/zelda3/overworld_map.h b/src/app/zelda3/overworld_map.h index a2d2a955..e192f585 100644 --- a/src/app/zelda3/overworld_map.h +++ b/src/app/zelda3/overworld_map.h @@ -28,14 +28,13 @@ class OverworldMap { absl::Status BuildMap(int count, int game_state, int world, uchar* map_parent, OWBlockset& world_blockset); - auto GetCurrentBlockset() const { return current_blockset_; } - auto GetCurrentGraphics() const { return current_gfx_; } - auto GetCurrentPalette() const { return current_palette_; } - auto GetBitmapData() const { return bitmap_data_; } + auto Tile16Blockset() const { return current_blockset_; } + auto AreaGraphics() const { return current_gfx_; } + auto AreaPalette() const { return current_palette_; } + auto BitmapData() const { return bitmap_data_; } auto SetLargeMap(bool is_set) { large_map_ = is_set; } auto IsLargeMap() const { return large_map_; } auto IsInitialized() const { return initialized_; } - auto IsBuilt() const { return built_; } private: void LoadAreaInfo(); @@ -52,8 +51,6 @@ class OverworldMap { int message_id_ = 0; int area_graphics_ = 0; int area_palette_ = 0; - - // TODO SET ME int game_state_ = 0; uchar sprite_graphics_[3]; From 61b09d24dd2838088c4a64bd448bb61aeaef7b77 Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sun, 11 Sep 2022 00:29:54 -0500 Subject: [PATCH 04/16] update viewer and client --- src/app/delta/client.h | 2 +- src/app/delta/viewer.cc | 153 +++++++++++++++++++++++++++++++--------- src/app/delta/viewer.h | 12 ++++ 3 files changed, 131 insertions(+), 36 deletions(-) diff --git a/src/app/delta/client.h b/src/app/delta/client.h index 0c5cb0c2..6c3d7f74 100644 --- a/src/app/delta/client.h +++ b/src/app/delta/client.h @@ -13,7 +13,6 @@ #include "src/app/delta/delta.grpc.pb.h" #include "src/app/delta/delta.pb.h" - namespace yaze { namespace app { namespace delta { @@ -28,6 +27,7 @@ using grpc::Status; class Client { public: + Client() = default; void CreateChannel(); absl::Status InitRepo(std::string author_name, std::string project_name); diff --git a/src/app/delta/viewer.cc b/src/app/delta/viewer.cc index 79bbad6e..b1466560 100644 --- a/src/app/delta/viewer.cc +++ b/src/app/delta/viewer.cc @@ -38,40 +38,122 @@ void NewMasterFrame() { } } -bool BeginCentered(const char* name) { - ImGuiIO const& io = ImGui::GetIO(); - ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f); - ImGui::SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); - ImGuiWindowFlags flags = - ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings; - return ImGui::Begin(name, nullptr, flags); -} - -void DisplayStatus(absl::Status& status) { - if (BeginCentered("StatusWindow")) { - ImGui::Text("%s", status.ToString().c_str()); - ImGui::Spacing(); - ImGui::NextColumn(); - ImGui::Columns(1); - ImGui::Separator(); - ImGui::NewLine(); - ImGui::SameLine(270); - if (ImGui::Button("OK", ImVec2(200, 0))) { - status = absl::OkStatus(); - } - ImGui::End(); - } -} - } // namespace void Viewer::Update() { NewMasterFrame(); + DrawYazeMenu(); + DrawFileDialog(); + + ImGui::Text(ICON_MD_CHANGE_HISTORY); + ImGui::SameLine(); + ImGui::Text("%s", rom_.GetTitle()); + + ImGui::Separator(); + + ImGui::Button(ICON_MD_SYNC); + ImGui::SameLine(); + ImGui::Button(ICON_MD_ARROW_UPWARD); + ImGui::SameLine(); + ImGui::Button(ICON_MD_ARROW_DOWNWARD); + ImGui::SameLine(); + ImGui::Button(ICON_MD_MERGE); + ImGui::SameLine(); + + ImGui::Button(ICON_MD_MANAGE_HISTORY); + ImGui::SameLine(); + ImGui::Button(ICON_MD_LAN); + ImGui::SameLine(); + ImGui::Button(ICON_MD_COMMIT); + ImGui::SameLine(); + ImGui::Button(ICON_MD_DIFFERENCE); + + ImGui::Separator(); + + ImGui::SetNextItemWidth(75.f); + ImGui::Button(ICON_MD_SEND); + ImGui::SameLine(); + ImGui::InputText("Server Address", &client_address_); + + ImGui::SetNextItemWidth(75.f); + ImGui::Button(ICON_MD_DOWNLOAD); + ImGui::SameLine(); + ImGui::InputText("Repository Source", &client_address_); + + ImGui::Separator(); DrawBranchTree(); ImGui::End(); } +void Viewer::DrawFileDialog() { + if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey")) { + if (ImGuiFileDialog::Instance()->IsOk()) { + std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + rom_.LoadFromFile(filePathName); + } + ImGuiFileDialog::Instance()->Close(); + } +} + +void Viewer::DrawYazeMenu() { + MENU_BAR() + DrawFileMenu(); + DrawViewMenu(); + END_MENU_BAR() +} + +void Viewer::DrawFileMenu() const { + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("Open", "Ctrl+O")) { + ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open ROM", + ".sfc,.smc", "."); + } + + MENU_ITEM2("Save", "Ctrl+S") {} + + ImGui::EndMenu(); + } +} + +void Viewer::DrawViewMenu() { + static bool show_imgui_metrics = false; + static bool show_imgui_style_editor = false; + static bool show_memory_editor = false; + static bool show_imgui_demo = false; + + if (show_imgui_metrics) { + ImGui::ShowMetricsWindow(&show_imgui_metrics); + } + + if (show_memory_editor) { + static MemoryEditor mem_edit; + mem_edit.DrawWindow("Memory Editor", (void*)&rom_, rom_.GetSize()); + } + + if (show_imgui_demo) { + ImGui::ShowDemoWindow(); + } + + if (show_imgui_style_editor) { + ImGui::Begin("Style Editor (ImGui)", &show_imgui_style_editor); + ImGui::ShowStyleEditor(); + ImGui::End(); + } + + if (ImGui::BeginMenu("View")) { + ImGui::MenuItem("HEX Editor", nullptr, &show_memory_editor); + ImGui::MenuItem("ImGui Demo", nullptr, &show_imgui_demo); + ImGui::Separator(); + if (ImGui::BeginMenu("GUI Tools")) { + ImGui::MenuItem("Metrics (ImGui)", nullptr, &show_imgui_metrics); + ImGui::MenuItem("Style Editor (ImGui)", nullptr, + &show_imgui_style_editor); + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } +} + void Viewer::DrawBranchTree() { static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | @@ -125,15 +207,16 @@ void Viewer::DrawBranchTree() { } }; static const MyTreeNode nodes[] = { - {"Root", "Folder", -1, 1, 3}, // 0 - {"Music", "Folder", -1, 4, 2}, // 1 - {"Textures", "Folder", -1, 6, 3}, // 2 - {"desktop.ini", "System file", 1024, -1, -1}, // 3 - {"File1_a.wav", "Audio file", 123000, -1, -1}, // 4 - {"File1_b.wav", "Audio file", 456000, -1, -1}, // 5 - {"Image001.png", "Image file", 203128, -1, -1}, // 6 - {"Copy of Image001.png", "Image file", 203256, -1, -1}, // 7 - {"Copy of Image001 (Final2).png", "Image file", 203512, -1, -1}, // 8 + {"lttp-redux", "Repository", -1, 1, 3}, + {"main", "Branch", -1, 4, 2}, + {"hyrule-castle", "Branch", -1, 4, 2}, + {"lost-woods", "Branch", -1, 6, 3}, + {"Added some bushes", "Commit", 1024, -1, -1}, + {"Constructed a new house", "Commit", 123000, -1, -1}, + {"File1_b.wav", "Commit", 456000, -1, -1}, + {"Image001.png", "Commit", 203128, -1, -1}, + {"Copy of Image001.png", "Commit", 203256, -1, -1}, + {"Copy of Image001 (Final2).png", "Commit", 203512, -1, -1}, }; MyTreeNode::DisplayNode(&nodes[0], nodes); diff --git a/src/app/delta/viewer.h b/src/app/delta/viewer.h index 6cd7903b..edcc8d48 100644 --- a/src/app/delta/viewer.h +++ b/src/app/delta/viewer.h @@ -9,6 +9,7 @@ #include "absl/status/status.h" #include "app/core/constants.h" +#include "app/delta/client.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" @@ -24,7 +25,18 @@ class Viewer { void Update(); private: + void DrawFileDialog(); + + void DrawYazeMenu(); + void DrawFileMenu() const; + void DrawViewMenu(); + void DrawBranchTree(); + + std::string client_address_; + + ROM rom_; + Client client_; }; } // namespace delta } // namespace app From 1acc02738046003ec76f2646e8f40b64cca97edb Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sun, 11 Sep 2022 00:30:08 -0500 Subject: [PATCH 05/16] update CMakeLists.txt --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60a96e32..a3001a87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,10 @@ set( find_package(PNG REQUIRED) find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) +find_package(gRPC REQUIRED) +set(PROTOBUF_INCLUDE_PATH ${CMAKE_CURRENT_BINARY_DIR} + CACHE INTERNAL "Path to generated protobuf files.") +include_directories(${PROTOBUF_INCLUDE_PATH}) # Project Files add_subdirectory(src/lib/abseil-cpp) From 904166ee2535682e52f6959811d054d715a7ec38 Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sun, 11 Sep 2022 09:53:48 -0500 Subject: [PATCH 06/16] transparency fix attempt --- src/app/gfx/bitmap.cc | 11 ++++++++--- src/app/gfx/snes_palette.h | 2 ++ src/app/zelda3/overworld_map.cc | 10 ++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index 1c20c956..c8e6a21d 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -106,9 +106,14 @@ void Bitmap::CreateTexture(std::shared_ptr renderer) { void Bitmap::ApplyPalette(const SNESPalette &palette) { palette_ = palette; for (int i = 0; i < palette.size_; ++i) { - surface_->format->palette->colors[i].r = palette.GetColor(i).rgb.x; - surface_->format->palette->colors[i].g = palette.GetColor(i).rgb.y; - surface_->format->palette->colors[i].b = palette.GetColor(i).rgb.z; + if (palette.GetColor(i).transparent) { + surface_->format->palette->colors[i].a = 0; + } else { + surface_->format->palette->colors[i].r = palette.GetColor(i).rgb.x; + surface_->format->palette->colors[i].g = palette.GetColor(i).rgb.y; + surface_->format->palette->colors[i].b = palette.GetColor(i).rgb.z; + surface_->format->palette->colors[i].a = 255; + } } } diff --git a/src/app/gfx/snes_palette.h b/src/app/gfx/snes_palette.h index bee951a9..f0481184 100644 --- a/src/app/gfx/snes_palette.h +++ b/src/app/gfx/snes_palette.h @@ -45,7 +45,9 @@ struct SNESColor { void setRgb(ImVec4); void setSNES(snes_color); void setSNES(uint16_t); + void setTransparent(bool t) { transparent = t; } + bool transparent = false; uint16_t snes = 0; ImVec4 rgb; }; diff --git a/src/app/zelda3/overworld_map.cc b/src/app/zelda3/overworld_map.cc index 0c6388b5..d54ec9c3 100644 --- a/src/app/zelda3/overworld_map.cc +++ b/src/app/zelda3/overworld_map.cc @@ -134,10 +134,9 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, current.Create(new_palette); // ColorPalette pal = GFX.editort16Bitmap.Palette; - // for (int i = 0; i < 256; i++) { - // pal.Entries[i] = new_palette[i]; - // pal.Entries[(i / 16) * 16] = Color.Transparent; - // } + for (int i = 0; i < 256; i++) { + current[(i / 16) * 16].setTransparent(true); + } // GFX.mapgfx16Bitmap.Palette = pal; // GFX.mapblockset16Bitmap.Palette = pal; @@ -334,8 +333,7 @@ void OverworldMap::LoadPalette() { uchar pal0 = 0; - uchar pal1 = - rom_[core::overworldMapPaletteGroup + (area_palette_ * 4)]; // aux1 + uchar pal1 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4)]; uchar pal2 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + 1]; // aux2 uchar pal3 = rom_[core::overworldMapPaletteGroup + (area_palette_ * 4) + From cfb84481ed1943c499902d15e2e84976bdff162e Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 11 Sep 2022 14:23:39 -0500 Subject: [PATCH 07/16] palette viewer and editor --- src/app/editor/master_editor.cc | 1 + src/app/editor/overworld_editor.cc | 9 ++- src/app/editor/overworld_editor.h | 2 + src/app/editor/palette_editor.cc | 110 +++++++++++++++++++++++++++-- src/app/editor/palette_editor.h | 11 +++ src/app/gfx/bitmap.cc | 5 +- src/app/gfx/snes_palette.cc | 8 +-- src/app/gfx/snes_palette.h | 4 ++ 8 files changed, 140 insertions(+), 10 deletions(-) diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index e3987b0d..07b853de 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -103,6 +103,7 @@ void MasterEditor::DrawFileDialog() { status_ = rom_.LoadFromFile(filePathName); overworld_editor_.SetupROM(rom_); screen_editor_.SetupROM(rom_); + palette_editor_.SetupROM(rom_); } ImGuiFileDialog::Instance()->Close(); } diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 98a3077e..36448510 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -95,7 +95,7 @@ absl::Status OverworldEditor::Update() { } absl::Status OverworldEditor::DrawToolset() { - if (ImGui::BeginTable("OWToolset", 15, toolset_table_flags, ImVec2(0, 0))) { + if (ImGui::BeginTable("OWToolset", 17, toolset_table_flags, ImVec2(0, 0))) { for (const auto &name : kToolsetColumnNames) ImGui::TableSetupColumn(name.data()); @@ -134,6 +134,13 @@ absl::Status OverworldEditor::DrawToolset() { ImGui::TableNextColumn(); ImGui::Button(ICON_MD_MUSIC_NOTE); + // Separator + ImGui::TableNextColumn(); + ImGui::Text(ICON_MD_MORE_VERT); + // Music + ImGui::TableNextColumn(); + palette_editor_.DisplayPalette(palette_, overworld_.isLoaded()); + ImGui::EndTable(); } return absl::OkStatus(); diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index 2a4a07ac..7e0b83f3 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -9,6 +9,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "app/editor/palette_editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" @@ -88,6 +89,7 @@ class OverworldEditor { ROM rom_; zelda3::Overworld overworld_; + PaletteEditor palette_editor_; gfx::SNESPalette palette_; gfx::Bitmap tile16_blockset_bmp_; diff --git a/src/app/editor/palette_editor.cc b/src/app/editor/palette_editor.cc index e22f88a6..ca676fe3 100644 --- a/src/app/editor/palette_editor.cc +++ b/src/app/editor/palette_editor.cc @@ -12,10 +12,28 @@ namespace app { namespace editor { absl::Status PaletteEditor::Update() { - for (const auto &name : kPaletteCategoryNames) { - if (ImGui::TreeNode(name.data())) { - ImGui::SameLine(); - if (ImGui::SmallButton("button")) { + for (int i = 0; i < 11; ++i) { + if (ImGui::TreeNode(kPaletteCategoryNames[i].data())) { + auto size = rom_.GetPaletteGroup(kPaletteGroupNames[i].data()).size; + auto palettes = rom_.GetPaletteGroup(kPaletteGroupNames[i].data()); + for (int j = 0; j < size; j++) { + ImGui::Text("%d", j); + auto palette = palettes[j]; + for (int n = 0; n < size; n++) { + ImGui::PushID(n); + if ((n % 8) != 0) + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + ImGuiColorEditFlags palette_button_flags = + ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker; + if (ImGui::ColorButton("##palette", palette[n].RGB(), + palette_button_flags, ImVec2(20, 20))) + current_color_ = + ImVec4(palette[n].rgb.x, palette[n].rgb.y, palette[n].rgb.z, + current_color_.w); // Preserve alpha! + + ImGui::PopID(); + } } ImGui::TreePop(); } @@ -23,6 +41,90 @@ absl::Status PaletteEditor::Update() { return absl::OkStatus(); } +absl::Status 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; + static ImVec4 saved_palette[256] = {}; + if (loaded && !init) { + for (int n = 0; n < palette.size_; n++) { + saved_palette[n].x = palette.GetColor(n).rgb.x / 255; + saved_palette[n].y = palette.GetColor(n).rgb.y / 255; + saved_palette[n].z = palette.GetColor(n).rgb.z / 255; + saved_palette[n].w = 255; // Alpha + } + init = true; + } + + static ImVec4 backup_color; + bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); + ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); + open_popup |= ImGui::Button("Palette"); + if (open_popup) { + ImGui::OpenPopup("mypicker"); + backup_color = color; + } + if (ImGui::BeginPopup("mypicker")) { + ImGui::Text("Current Overworld Palette"); + ImGui::Separator(); + ImGui::ColorPicker4("##picker", (float*)&color, + misc_flags | ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoSmallPreview); + ImGui::SameLine(); + + ImGui::BeginGroup(); // Lock X position + ImGui::Text("Current ==>"); + ImGui::SameLine(); + ImGui::Text("Previous"); + + ImGui::ColorButton( + "##current", color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40)); + ImGui::SameLine(); + + if (ImGui::ColorButton( + "##previous", backup_color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40))) + color = backup_color; + ImGui::Separator(); + ImGui::Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) { + ImGui::PushID(n); + if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | + ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip; + if (ImGui::ColorButton("##palette", saved_palette[n], + palette_button_flags, ImVec2(20, 20))) + color = ImVec4(saved_palette[n].x, saved_palette[n].y, + saved_palette[n].z, color.w); // Preserve alpha! + + if (ImGui::BeginDragDropTarget()) { + if (const ImGuiPayload* payload = + ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = + ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + ImGui::EndPopup(); + } + return absl::OkStatus(); +} + } // namespace editor } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/editor/palette_editor.h b/src/app/editor/palette_editor.h index 939d2d55..d27551b8 100644 --- a/src/app/editor/palette_editor.h +++ b/src/app/editor/palette_editor.h @@ -5,6 +5,7 @@ #include "absl/status/status.h" #include "app/gfx/snes_palette.h" +#include "app/rom.h" #include "gui/canvas.h" #include "gui/icons.h" @@ -17,11 +18,21 @@ static constexpr absl::string_view kPaletteCategoryNames[] = { "Area Colors", "Enemies", "Dungeons", "World Map", "Dungeon Map", "Triforce", "Crystal"}; +static constexpr absl::string_view kPaletteGroupNames[] = { + "swords", "shields", "armors", "ow_main", + "ow_aux", "global_sprites", "dungeon_main", "ow_mini_map", + "ow_mini_map", "3d_object", "3d_object"}; + class PaletteEditor { public: absl::Status Update(); + absl::Status DisplayPalette(gfx::SNESPalette& palette, bool loaded); + + auto SetupROM(ROM& rom) { rom_ = rom; } private: + ImVec4 current_color_; + ROM rom_; }; } // namespace editor diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index c8e6a21d..0b5f7989 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -107,12 +107,15 @@ void Bitmap::ApplyPalette(const SNESPalette &palette) { palette_ = palette; for (int i = 0; i < palette.size_; ++i) { if (palette.GetColor(i).transparent) { + surface_->format->palette->colors[i].r = 0; + surface_->format->palette->colors[i].g = 0; + surface_->format->palette->colors[i].b = 0; surface_->format->palette->colors[i].a = 0; } else { surface_->format->palette->colors[i].r = palette.GetColor(i).rgb.x; surface_->format->palette->colors[i].g = palette.GetColor(i).rgb.y; surface_->format->palette->colors[i].b = palette.GetColor(i).rgb.z; - surface_->format->palette->colors[i].a = 255; + surface_->format->palette->colors[i].a = palette.GetColor(i).rgb.w; } } } diff --git a/src/app/gfx/snes_palette.cc b/src/app/gfx/snes_palette.cc index c3fad32a..5ff1c878 100644 --- a/src/app/gfx/snes_palette.cc +++ b/src/app/gfx/snes_palette.cc @@ -66,8 +66,8 @@ SNESColor::SNESColor() : rgb(ImVec4(0.f, 0.f, 0.f, 0.f)) {} SNESColor::SNESColor(snes_color val) { rgb.x = val.red; - rgb.y = val.blue; - rgb.z = val.green; + rgb.y = val.green; + rgb.z = val.blue; } SNESColor::SNESColor(ImVec4 val) : rgb(val) { @@ -88,13 +88,13 @@ void SNESColor::setRgb(ImVec4 val) { } void SNESColor::setSNES(snes_color val) { - rgb = ImVec4(val.red, val.green, val.blue, 1.f); + rgb = ImVec4(val.red, val.green, val.blue, 255.f); } void SNESColor::setSNES(uint16_t val) { snes = val; snes_color col = ConvertSNEStoRGB(val); - rgb = ImVec4(col.red, col.green, col.blue, 1.f); + rgb = ImVec4(col.red, col.green, col.blue, 0.f); } // ============================================================================ diff --git a/src/app/gfx/snes_palette.h b/src/app/gfx/snes_palette.h index f0481184..1c0e4143 100644 --- a/src/app/gfx/snes_palette.h +++ b/src/app/gfx/snes_palette.h @@ -47,6 +47,10 @@ struct SNESColor { void setSNES(uint16_t); void setTransparent(bool t) { transparent = t; } + auto RGB() { + return ImVec4(rgb.x / 255, rgb.y / 255, rgb.z / 255, rgb.w); + } + bool transparent = false; uint16_t snes = 0; ImVec4 rgb; From 0896f51c3953675f56240aa0839221956e0cb5b6 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 11 Sep 2022 14:23:46 -0500 Subject: [PATCH 08/16] remove pseudo vram --- src/app/gfx/pseudo_vram.cc | 30 ------------------------ src/app/gfx/pseudo_vram.h | 47 -------------------------------------- 2 files changed, 77 deletions(-) delete mode 100644 src/app/gfx/pseudo_vram.cc delete mode 100644 src/app/gfx/pseudo_vram.h diff --git a/src/app/gfx/pseudo_vram.cc b/src/app/gfx/pseudo_vram.cc deleted file mode 100644 index 4429783f..00000000 --- a/src/app/gfx/pseudo_vram.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "pseudo_vram.h" - -namespace yaze { -namespace app { -namespace gfx { - -void pseudo_vram::ChangeGraphicsTileset( - const std::vector& graphics_set) {} - -void pseudo_vram::ChangeGraphicsPalette(const SNESPalette& graphics_pal) {} - -void pseudo_vram::ChangeSpriteTileset(const std::vector& sprite_set) {} - -void pseudo_vram::ChangeSpritePalette(const SNESPalette& sprite_pal) {} - -std::vector CreateGraphicsSet( - int id, const std::unordered_map& all_graphics) { - std::vector graphics_set; - return graphics_set; -} - -std::vector CreateSpriteSet( - int id, const std::unordered_map& all_graphics) { - std::vector graphics_set; - return graphics_set; -} - -} // namespace gfx -} // namespace app -} // namespace yaze \ No newline at end of file diff --git a/src/app/gfx/pseudo_vram.h b/src/app/gfx/pseudo_vram.h deleted file mode 100644 index 4f07ed15..00000000 --- a/src/app/gfx/pseudo_vram.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef YAZE_APP_GFX_PSEUDO_VRAM_H -#define YAZE_APP_GFX_PSEUDO_VRAM_H - -#include - -#include -#include -#include - -#include "app/gfx/bitmap.h" -#include "app/gfx/snes_palette.h" -#include "app/gfx/snes_tile.h" - -namespace yaze { -namespace app { -namespace gfx { - -// VRAM: 64 KB of VRAM for screen maps and tile sets (backgrounds and objects) -// OAM: 512 + 32 bytes for objects (Object Attribute Memory) -// CGRAM: 512 bytes for palette data -// Palette: 256 entries; 15-Bit color (BGR555) for a total of 32,768 colors. -// Resolution: between 256x224 and 512x448. - -class pseudo_vram { - public: - void ChangeGraphicsTileset(const std::vector& graphics_set); - void ChangeGraphicsPalette(const SNESPalette& graphics_pal); - void ChangeSpriteTileset(const std::vector& sprite_set); - void ChangeSpritePalette(const SNESPalette& sprite_pal); - - auto GetTileset(int index) const { return m_vram.at(index); } - - private: - static const uint32_t REAL_VRAM_SIZE = 0x8000; - std::unordered_map m_vram; -}; - -std::vector CreateGraphicsSet( - int id, const std::unordered_map& all_graphics); -std::vector CreateSpriteSet( - int id, const std::unordered_map& all_graphics); - -} // namespace gfx -} // namespace app -} // namespace yaze - -#endif // YAZE_APP_GFX_PSEUDO_VRAM_H \ No newline at end of file From 9b4f8fd7167a044952d36a0a86cdd477fdb06442 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 11 Sep 2022 14:23:58 -0500 Subject: [PATCH 09/16] fix overworld colors drawing --- src/app/zelda3/overworld.cc | 7 +++--- src/app/zelda3/overworld.h | 1 - src/app/zelda3/overworld_map.cc | 38 ++++++++++++++++++++------------- src/app/zelda3/overworld_map.h | 2 +- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/app/zelda3/overworld.cc b/src/app/zelda3/overworld.cc index 8894bf76..442d9335 100644 --- a/src/app/zelda3/overworld.cc +++ b/src/app/zelda3/overworld.cc @@ -194,9 +194,10 @@ void Overworld::FetchLargeMaps() { overworld_maps_[136].SetLargeMap(false); bool mapChecked[64]; - for (auto &each : mapChecked) { - each = false; - } + for (int i = 0; i < 64; i++) + { + mapChecked[i] = false; + } int xx = 0; int yy = 0; while (true) { diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index c5d97f9d..46f6fb5d 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -9,7 +9,6 @@ #include "absl/status/status.h" #include "app/core/constants.h" #include "app/gfx/bitmap.h" -#include "app/gfx/pseudo_vram.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" #include "app/zelda3/overworld_map.h" diff --git a/src/app/zelda3/overworld_map.cc b/src/app/zelda3/overworld_map.cc index d54ec9c3..4bd94c8c 100644 --- a/src/app/zelda3/overworld_map.cc +++ b/src/app/zelda3/overworld_map.cc @@ -176,16 +176,7 @@ absl::Status OverworldMap::BuildMap(int count, int game_state, int world, } } - int world_index = 0x20; - if (parent_ < 0x40) { - world_index = 0x20; - } else if (parent_ >= 0x40 && parent_ < 0x80) { - world_index = 0x21; - } else if (parent_ == 0x88) { - world_index = 0x24; - } - - LoadAreaGraphics(game_state, world_index); + LoadAreaGraphics(); RETURN_IF_ERROR(BuildTileset()) RETURN_IF_ERROR(BuildTiles16Gfx(count)) LoadPalette(); @@ -273,7 +264,16 @@ void OverworldMap::LoadAreaInfo() { } } -void OverworldMap::LoadAreaGraphics(int game_state, int world_index) { +void OverworldMap::LoadAreaGraphics() { + int world_index = 0x20; + if (parent_ < 0x40) { + world_index = 0x20; + } else if (parent_ >= 0x40 && parent_ < 0x80) { + world_index = 0x21; + } else if (parent_ == 0x88) { + world_index = 0x24; + } + // Sprites Blocksets static_graphics_[8] = 0x73 + 0x00; static_graphics_[9] = 0x73 + 0x01; @@ -281,7 +281,7 @@ void OverworldMap::LoadAreaGraphics(int game_state, int world_index) { static_graphics_[11] = 0x73 + 0x07; for (int i = 0; i < 4; i++) { static_graphics_[12 + i] = (rom_[core::kSpriteBlocksetPointer + - (sprite_graphics_[game_state] * 4) + i] + + (sprite_graphics_[game_state_] * 4) + i] + 0x73); } @@ -386,7 +386,7 @@ void OverworldMap::LoadPalette() { if (parent_ < 0x40) { // Default LW Palette pal0 = 0; - + bgr = rom_.GetPaletteGroup("grass")[0].GetColor(0); if (parent_ == 0x03 || parent_ == 0x05 || parent_ == 0x07) { pal0 = 2; } @@ -456,8 +456,16 @@ absl::Status OverworldMap::BuildTileset() { for (int i = 0; i < 0x10; i++) { for (int j = 0; j < 0x1000; j++) { - current_gfx_[(i * 0x1000) + j] = - all_gfx_[j + (static_graphics_[i] * 0x1000)]; + auto byte = all_gfx_[j + (static_graphics_[i] * 0x1000)]; + switch (i) { + case 0: + case 3: + case 4: + case 5: + byte += 0x88; + break; + } + current_gfx_[(i * 0x1000) + j] = byte; } } return absl::OkStatus(); diff --git a/src/app/zelda3/overworld_map.h b/src/app/zelda3/overworld_map.h index e192f585..51d35902 100644 --- a/src/app/zelda3/overworld_map.h +++ b/src/app/zelda3/overworld_map.h @@ -38,7 +38,7 @@ class OverworldMap { private: void LoadAreaInfo(); - void LoadAreaGraphics(int game_state, int world_index); + void LoadAreaGraphics(); void LoadPalette(); absl::Status BuildTileset(); From aa1a5a36ada8a07e3e5517762086f703fcf853a3 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 11 Sep 2022 15:53:02 -0500 Subject: [PATCH 10/16] housekeeping --- src/app/editor/master_editor.cc | 4 +-- src/app/gfx/bitmap.cc | 57 --------------------------------- src/app/gfx/bitmap.h | 6 ---- src/app/zelda3/overworld_map.cc | 33 ++++++++++--------- 4 files changed, 20 insertions(+), 80 deletions(-) diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index 07b853de..59a8a363 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -119,10 +119,10 @@ void MasterEditor::DrawAboutPopup() { if (about_) ImGui::OpenPopup("About"); if (ImGui::BeginPopupModal("About", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Yet Another Zelda3 Editor - v0.01"); + ImGui::Text("Yet Another Zelda3 Editor - v0.02"); ImGui::Text("Written by: scawful"); ImGui::Spacing(); - ImGui::Text("Special Thanks: Zarby89"); + ImGui::Text("Special Thanks: Zarby89, JaredBrian"); ImGui::Separator(); if (ImGui::Button("Close", ImVec2(200, 0))) { diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index 0b5f7989..201e890b 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -120,63 +120,6 @@ void Bitmap::ApplyPalette(const SNESPalette &palette) { } } -void Bitmap::SetPaletteColor(int id, gfx::SNESColor color) { - surface_->format->palette->colors[id].r = color.rgb.x; - surface_->format->palette->colors[id].g = color.rgb.y; - surface_->format->palette->colors[id].b = color.rgb.z; -} - -// Creates a vector of bitmaps which are individual 8x8 tiles. -absl::StatusOr> Bitmap::CreateTiles() { - std::vector tiles; - for (int i = 0; i < 16; ++i) { - for (int j = 0; j < 4; ++j) { - Bitmap bmp; - bmp.Create(8, 8, 8, 32); - auto surface = bmp.GetSurface(); - SDL_Rect src_rect = {i, j, 8, 8}; - if (SDL_BlitSurface(surface_.get(), &src_rect, surface, nullptr) != 0) - return absl::InternalError( - absl::StrCat("Failed to blit surface: ", SDL_GetError())); - tiles.push_back(bmp); - } - } - return tiles; -} - -// Converts a vector of 8x8 tiles into a tilesheet. -absl::Status Bitmap::CreateFromTiles(const std::vector &tiles) { - if (tiles.empty()) - return absl::InvalidArgumentError( - "Failed to create bitmap: `tiles` is empty."); - - SDL_Rect tile_rect = {0, 0, 8, 8}; - SDL_Rect dest_rect = {0, 0, 8, 8}; - for (const auto &tile : tiles) { - auto src = tile.GetSurface(); - if (SDL_BlitSurface(src, &tile_rect, surface_.get(), &dest_rect) != 0) - return absl::InternalError( - absl::StrCat("Failed to blit surface: ", SDL_GetError())); - - dest_rect.x++; - if (dest_rect.x == 15) { - dest_rect.x = 0; - dest_rect.y++; - } - } - - return absl::OkStatus(); -} - -absl::Status Bitmap::WritePixel(int pos, uchar pixel) { - if (!surface_) { - return absl::InternalError("Surface not loaded"); - } - auto pixels = (char *)surface_->pixels; - pixels[pos] = pixel; - return absl::OkStatus(); -} - } // namespace gfx } // namespace app } // namespace yaze diff --git a/src/app/gfx/bitmap.h b/src/app/gfx/bitmap.h index 43588e65..84dfa5d0 100644 --- a/src/app/gfx/bitmap.h +++ b/src/app/gfx/bitmap.h @@ -31,12 +31,6 @@ class Bitmap { void CreateTexture(std::shared_ptr renderer); void ApplyPalette(const SNESPalette &palette); - void SetPaletteColor(int id, gfx::SNESColor color); - - absl::StatusOr> CreateTiles(); - absl::Status CreateFromTiles(const std::vector &tiles); - - absl::Status WritePixel(int pos, uchar pixel); int GetWidth() const { return width_; } int GetHeight() const { return height_; } diff --git a/src/app/zelda3/overworld_map.cc b/src/app/zelda3/overworld_map.cc index 4bd94c8c..35ce1d22 100644 --- a/src/app/zelda3/overworld_map.cc +++ b/src/app/zelda3/overworld_map.cc @@ -46,7 +46,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, int k = 0; for (int y = 2; y < 7; y++) { for (int x = 1; x < 8; x++) { - new_palette[x + (16 * y)] = main[k++]; + new_palette[x + (16 * y)] = main[k]; + k++; } } @@ -61,7 +62,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 2; y < 5; y++) { for (int x = 9; x < 16; x++) { - new_palette[x + (16 * y)] = aux1[k++]; + new_palette[x + (16 * y)] = aux1[k]; + k++; } } @@ -69,7 +71,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 5; y < 8; y++) { for (int x = 9; x < 16; x++) { - new_palette[x + (16 * y)] = aux2[k++]; + new_palette[x + (16 * y)] = aux2[k]; + k++; } } @@ -88,7 +91,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 8; y < 9; y++) { for (int x = 1; x < 8; x++) { - new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux1")[1][k++]; + new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux1")[1][k]; + k++; } } @@ -96,7 +100,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 8; y < 9; y++) { for (int x = 9; x < 16; x++) { - new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux3")[0][k++]; + new_palette[x + (16 * y)] = rom.GetPaletteGroup("sprites_aux3")[0][k]; + k++; } } @@ -104,7 +109,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 9; y < 13; y++) { for (int x = 1; x < 16; x++) { - new_palette[x + (16 * y)] = rom.GetPaletteGroup("global_sprites")[0][k++]; + new_palette[x + (16 * y)] = rom.GetPaletteGroup("global_sprites")[0][k]; + k++; } } @@ -112,7 +118,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 13; y < 14; y++) { for (int x = 1; x < 8; x++) { - new_palette[x + (16 * y)] = spr[k++]; + new_palette[x + (16 * y)] = spr[k]; + k++; } } @@ -120,7 +127,8 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 14; y < 15; y++) { for (int x = 1; x < 8; x++) { - new_palette[x + (16 * y)] = spr2[k++]; + new_palette[x + (16 * y)] = spr2[k]; + k++; } } @@ -128,20 +136,15 @@ void SetColorsPalette(ROM& rom, int index, gfx::SNESPalette& current, k = 0; for (int y = 15; y < 16; y++) { for (int x = 1; x < 16; x++) { - new_palette[x + (16 * y)] = rom.GetPaletteGroup("armors")[0][k++]; + new_palette[x + (16 * y)] = rom.GetPaletteGroup("armors")[0][k]; + k++; } } current.Create(new_palette); - // ColorPalette pal = GFX.editort16Bitmap.Palette; for (int i = 0; i < 256; i++) { current[(i / 16) * 16].setTransparent(true); } - - // GFX.mapgfx16Bitmap.Palette = pal; - // GFX.mapblockset16Bitmap.Palette = pal; - - // gfxBitmap.Palette = pal; } } // namespace From 5179af9c00d29252b218b62a6cd109df8d0fd297 Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sun, 11 Sep 2022 18:05:12 -0500 Subject: [PATCH 11/16] remove deleted source --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18ee10aa..afe40a3d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,7 +62,6 @@ set( set( YAZE_APP_GFX_SRC app/gfx/bitmap.cc - app/gfx/pseudo_vram.cc app/gfx/snes_palette.cc app/gfx/snes_tile.cc ) From 290844db54a525cfcaeffc1218a23dc4928a2e55 Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Sun, 11 Sep 2022 22:37:47 -0500 Subject: [PATCH 12/16] add entrances to ow draw --- src/app/editor/overworld_editor.cc | 10 +++++ src/app/editor/overworld_editor.h | 1 + src/app/zelda3/overworld.cc | 42 +++++++++++++++++++-- src/app/zelda3/overworld.h | 59 ++++++++++++++++++++++++++++++ src/gui/canvas.cc | 18 +++++++-- src/gui/canvas.h | 1 + 6 files changed, 123 insertions(+), 8 deletions(-) diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 36448510..0e84643e 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -8,6 +8,8 @@ #include "absl/container/flat_hash_map.h" #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "absl/strings/str_format.h" +#include "app/editor/palette_editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" #include "app/gfx/snes_tile.h" @@ -218,6 +220,14 @@ void OverworldEditor::DrawOverworldCanvas() { xx = 0; } } + for (const auto &each : overworld_.Entrances()) { + if (each.mapId_ < 64 + (current_world_ * 0x40) && + each.mapId_ >= (current_world_ * 0x40)) { + overworld_map_canvas_.DrawOutline(each.x_, each.y_, 16, 16); + std::string str = absl::StrFormat("%#x", each.entranceId_); + overworld_map_canvas_.DrawText(str, each.x_ - 2, each.y_ - 14); + } + } } overworld_map_canvas_.DrawGrid(64.f); overworld_map_canvas_.DrawOverlay(); diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index 7e0b83f3..35c500ce 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -9,6 +9,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "absl/strings/str_format.h" #include "app/editor/palette_editor.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_palette.h" diff --git a/src/app/zelda3/overworld.cc b/src/app/zelda3/overworld.cc index 442d9335..2ae05a0c 100644 --- a/src/app/zelda3/overworld.cc +++ b/src/app/zelda3/overworld.cc @@ -38,6 +38,7 @@ absl::Status Overworld::Load(ROM &rom) { overworld_maps_.emplace_back(map_index, rom_, tiles16); FetchLargeMaps(); + LoadEntrances(); auto size = tiles16.size(); for (int i = 0; i < core::kNumOverworldMaps; ++i) { @@ -194,10 +195,9 @@ void Overworld::FetchLargeMaps() { overworld_maps_[136].SetLargeMap(false); bool mapChecked[64]; - for (int i = 0; i < 64; i++) - { - mapChecked[i] = false; - } + for (int i = 0; i < 64; i++) { + mapChecked[i] = false; + } int xx = 0; int yy = 0; while (true) { @@ -238,6 +238,40 @@ void Overworld::FetchLargeMaps() { } } +void Overworld::LoadEntrances() { + for (int i = 0; i < 129; i++) { + short mapId = rom_.toint16(core::OWEntranceMap + (i * 2)); + ushort mapPos = rom_.toint16(core::OWEntrancePos + (i * 2)); + uchar entranceId = (rom_[core::OWEntranceEntranceId + i]); + int p = mapPos >> 1; + int x = (p % 64); + int y = (p >> 6); + bool deleted = false; + if (mapPos == 0xFFFF) { + deleted = true; + } + all_entrances_.emplace_back( + (x * 16) + (((mapId % 64) - (((mapId % 64) / 8) * 8)) * 512), + (y * 16) + (((mapId % 64) / 8) * 512), entranceId, mapId, mapPos, + deleted); + } + + for (int i = 0; i < 0x13; i++) { + short mapId = (short)((rom_[core::OWHoleArea + (i * 2) + 1] << 8) + + (rom_[core::OWHoleArea + (i * 2)])); + short mapPos = (short)((rom_[core::OWHolePos + (i * 2) + 1] << 8) + + (rom_[core::OWHolePos + (i * 2)])); + uchar entranceId = (rom_[core::OWHoleEntrance + i]); + int p = (mapPos + 0x400) >> 1; + int x = (p % 64); + int y = (p >> 6); + all_holes_.emplace_back(EntranceOWEditor( + (x * 16) + (((mapId % 64) - (((mapId % 64) / 8) * 8)) * 512), + (y * 16) + (((mapId % 64) / 8) * 512), entranceId, mapId, + (ushort)(mapPos + 0x400), true)); + } +} + } // namespace zelda3 } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index 46f6fb5d..5e0cf007 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -17,6 +17,60 @@ namespace yaze { namespace app { namespace zelda3 { +class EntranceOWEditor { + public: + int x_; + int y_; + ushort mapPos; + uchar entranceId_, AreaX, AreaY; + short mapId_; + bool isHole = false; + bool deleted = false; + + EntranceOWEditor(int x, int y, uchar entranceId, short mapId, ushort mapPos, + bool hole) { + x_ = x; + y_ = y; + entranceId_ = entranceId; + mapId_ = mapId; + mapPos = mapPos; + + int mapX = (mapId_ - ((mapId / 8) * 8)); + int mapY = (mapId_ / 8); + + AreaX = (uchar)((std::abs(x - (mapX * 512)) / 16)); + AreaY = (uchar)((std::abs(y - (mapY * 512)) / 16)); + + isHole = hole; + } + + auto Copy() { + return new EntranceOWEditor(x_, y_, entranceId_, mapId_, mapPos, isHole); + } + + void updateMapStuff(short mapId) { + mapId_ = mapId; + + if (mapId_ >= 64) { + mapId_ -= 64; + } + + int mapX = (mapId_ - ((mapId_ / 8) * 8)); + int mapY = (mapId_ / 8); + + AreaX = (uchar)((std::abs(x_ - (mapX * 512)) / 16)); + AreaY = (uchar)((std::abs(y_ - (mapY * 512)) / 16)); + + int mx = (mapId_ - ((mapId_ / 8) * 8)); + int my = (mapId_ / 8); + + uchar xx = (uchar)((x_ - (mx * 512)) / 16); + uchar yy = (uchar)((y_ - (my * 512)) / 16); + + mapPos = (ushort)((((AreaY) << 6) | (AreaX & 0x3F)) << 1); + } +}; + class Overworld { public: absl::Status Load(ROM &rom); @@ -27,6 +81,7 @@ class Overworld { auto AreaGraphics() const { return overworld_maps_[current_map_].AreaGraphics(); } + auto Entrances() const { return all_entrances_; } auto AreaPalette() const { return overworld_maps_[current_map_].AreaPalette(); } @@ -57,6 +112,8 @@ class Overworld { int &ttpos); absl::Status DecompressAllMapTiles(); void FetchLargeMaps(); + void LoadEntrances(); + void LoadOverworldMap(); int game_state_ = 1; @@ -70,6 +127,8 @@ class Overworld { std::vector tiles16; std::vector tiles32; std::vector overworld_maps_; + std::vector all_entrances_; + std::vector all_holes_; }; } // namespace zelda3 diff --git a/src/gui/canvas.cc b/src/gui/canvas.cc index c7be1208..23873c0b 100644 --- a/src/gui/canvas.cc +++ b/src/gui/canvas.cc @@ -39,8 +39,10 @@ void Canvas::DrawContextMenu() { // Add first and second point if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { ImVec2 draw_tile_outline_pos; - draw_tile_outline_pos.x = std::round((double)mouse_pos_in_canvas.x / 32) * 32; - draw_tile_outline_pos.y = std::round((double)mouse_pos_in_canvas.y / 32) * 32; + draw_tile_outline_pos.x = + std::round((double)mouse_pos_in_canvas.x / 32) * 32; + draw_tile_outline_pos.y = + std::round((double)mouse_pos_in_canvas.y / 32) * 32; points_.push_back(draw_tile_outline_pos); points_.push_back( @@ -86,11 +88,19 @@ void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset) { } void Canvas::DrawOutline(int x, int y, int w, int h) { - ImVec2 origin(x, y); - ImVec2 size(x + w, y + h); + ImVec2 origin(canvas_p0_.x + scrolling_.x + x, + canvas_p0_.y + scrolling_.y + y); + ImVec2 size(canvas_p0_.x + scrolling_.x + x + w, + canvas_p0_.y + scrolling_.y + y + h); draw_list_->AddRect(origin, size, IM_COL32(255, 255, 255, 255)); } +void Canvas::DrawText(std::string text, int x, int y) { + draw_list_->AddText( + ImVec2(canvas_p0_.x + scrolling_.x + x, canvas_p0_.y + scrolling_.y + y), + IM_COL32(255, 255, 255, 255), text.data()); +} + void Canvas::DrawGrid(float grid_step) { // Draw grid + all lines in the canvas draw_list_->PushClipRect(canvas_p0_, canvas_p1_, true); diff --git a/src/gui/canvas.h b/src/gui/canvas.h index 4789ec3d..a563f2bd 100644 --- a/src/gui/canvas.h +++ b/src/gui/canvas.h @@ -24,6 +24,7 @@ class Canvas { void DrawBitmap(const Bitmap& bitmap, int border_offset = 0); void DrawBitmap(const Bitmap& bitmap, int x_offset, int y_offset); void DrawOutline(int x, int y, int w, int h); + void DrawText(std::string text, int x, int y); void DrawGrid(float grid_step = 64.0f); void DrawOverlay(); // last From d6081e9add95eb3ae40167b85900de91f212c862 Mon Sep 17 00:00:00 2001 From: scawful Date: Mon, 12 Sep 2022 13:04:03 -0500 Subject: [PATCH 13/16] canvas and ow edit changes --- src/app/editor/overworld_editor.cc | 8 ++--- src/app/editor/overworld_editor.h | 1 + src/app/rom.cc | 56 +++++++++--------------------- src/gui/canvas.cc | 26 ++++++++++++++ src/gui/canvas.h | 7 ++++ 5 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 0e84643e..c4244298 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -24,15 +24,15 @@ namespace editor { namespace { void UpdateSelectedTile16(int selected, gfx::Bitmap &tile16_blockset, - gfx::Bitmap &selected_tile) { + Bytes &selected_tile) { + selected_tile.reserve(256); auto blockset = tile16_blockset.GetData(); - auto bitmap = selected_tile.GetData(); int src_pos = ((selected - ((selected / 0x08) * 0x08)) * 0x10) + ((selected / 0x08) * 2048); for (int yy = 0; yy < 0x10; yy++) { for (int xx = 0; xx < 0x10; xx++) { - bitmap[xx + (yy * 0x10)] = blockset[src_pos + xx + (yy * 0x80)]; + selected_tile[xx + (yy * 0x10)] = blockset[src_pos + xx + (yy * 0x80)]; } } } @@ -70,7 +70,7 @@ absl::Status OverworldEditor::Update() { selected_tile_bmp_.Create(16, 16, 64, 256); } UpdateSelectedTile16(selected_tile_, tile16_blockset_bmp_, - selected_tile_bmp_); + selected_tile_data_); selected_tile_bmp_.ApplyPalette(palette_); rom_.RenderBitmap(&selected_tile_bmp_); update_selected_tile_ = false; diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index 35c500ce..ccbaf9b1 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -97,6 +97,7 @@ class OverworldEditor { gfx::Bitmap current_gfx_bmp_; gfx::Bitmap all_gfx_bmp; gfx::Bitmap selected_tile_bmp_; + Bytes selected_tile_data_; gui::Canvas overworld_map_canvas_; gui::Canvas current_gfx_canvas_; diff --git a/src/app/rom.cc b/src/app/rom.cc index 8b67fa68..91f8826d 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -534,25 +534,26 @@ absl::StatusOr ROM::Decompress(int offset, int size, int mode) { if (mode == kNintendoMode1) { // Reversed byte order for overworld maps // addr = (s2 | s1); - addr = (rom_data_[offset + 1]) | ((rom_data_[offset]) << 8); + addr = (rom_data_[offset + 1] & kSnesByteMax) | + ((rom_data_[offset] & kSnesByteMax) << 8); + if (addr > offset) { + return absl::InternalError(absl::StrFormat( + "DecompressOverworld: Offset for command copy exceeds " + "current position (Offset : %#04x | Pos : %#06x)\n", + addr, offset)); + } + + if (buffer_pos + length >= size) { + size *= 2; + buffer.resize(size); + } + memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length); buffer_pos += length; offset += 2; break; } - if (addr > offset) { - return absl::InternalError(absl::StrFormat( - "DecompressOverworld: Offset for command copy exceeds " - "current position (Offset : %#04x | Pos : %#06x)\n", - addr, offset)); - } - - if (buffer_pos + length >= size) { - size *= 2; - buffer.resize(size); - } - for (int i = 0; i < length; i++) { buffer[buffer_pos] = buffer[addr + i]; buffer_pos++; @@ -687,7 +688,7 @@ void ROM::RenderBitmap(gfx::Bitmap* bitmap) const { } gfx::SNESColor ROM::ReadColor(int offset) { - short color = (short)((rom_data_[offset + 1] << 8) + rom_data_[offset]); + short color = toint16(offset); gfx::snes_color new_color; new_color.red = (color & 0x1F) * 8; new_color.green = ((color >> 5) & 0x1F) * 8; @@ -701,7 +702,7 @@ gfx::SNESPalette ROM::ReadPalette(int offset, int num_colors) { std::vector colors(num_colors); while (color_offset < num_colors) { - short color = (short)((rom_data_[offset + 1] << 8) + rom_data_[offset]); + short color = toint16(offset); gfx::snes_color new_color; new_color.red = (color & 0x1F) * 8; new_color.green = ((color >> 5) & 0x1F) * 8; @@ -783,31 +784,6 @@ void ROM::LoadAllPalettes() { palette_groups_["ow_mini_map"].AddPalette( ReadPalette(core::overworldMiniMapPalettes + (i * 256), 128)); } - - // TODO: check for the paletts in the empty bank space that kan will allocate - // and read them in here - // TODO magic colors - // LW - // int j = 0; - // while (j < 64) { - // zelda3::overworld_BackgroundPalette[j++] = - // Color.FromArgb(0xFF, 0x48, 0x98, 0x48); - // } - - // // DW - // while (j < 128) { - // zelda3::overworld_BackgroundPalette[j++] = - // Color.FromArgb(0xFF, 0x90, 0x88, 0x50); - // } - - // // SP - // while (j < core::kNumOverworldMaps) { - // zelda3::overworld_BackgroundPalette[j++] = - // Color.FromArgb(0xFF, 0x48, 0x98, 0x48); - // } - - // zelda3::overworld_BackgroundPalette = - // ReadPalette(core::customAreaSpecificBGPalette, 160); } } // namespace app diff --git a/src/gui/canvas.cc b/src/gui/canvas.cc index 23873c0b..eaf7f7c5 100644 --- a/src/gui/canvas.cc +++ b/src/gui/canvas.cc @@ -6,6 +6,7 @@ #include #include "app/gfx/bitmap.h" +#include "app/rom.h" namespace yaze { namespace gui { @@ -63,6 +64,10 @@ void Canvas::DrawContextMenu() { ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); if (ImGui::BeginPopup("context")) { + if (ImGui::MenuItem("Reset Position", nullptr, false)) { + scrolling_.x = 0; + scrolling_.y = 0; + } if (ImGui::MenuItem("Remove all", nullptr, false, points_.Size > 0)) { points_.clear(); } @@ -70,6 +75,27 @@ void Canvas::DrawContextMenu() { } } +void Canvas::DrawTilesFromUser(app::ROM &rom, Bytes &tile, + app::gfx::SNESPalette &pal) { + ImVec2 draw_tile_outline_pos; + + // Add rectangle + if (is_hovered_ && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { + draw_tile_outline_pos.x = + std::round((double)mouse_pos_in_canvas_.x / 16) * 16; + draw_tile_outline_pos.y = + std::round((double)mouse_pos_in_canvas_.y / 16) * 16; + + points_.push_back(draw_tile_outline_pos); + points_.push_back( + ImVec2(draw_tile_outline_pos.x + 16, draw_tile_outline_pos.y + 16)); + + changed_tiles_.emplace_back(app::gfx::Bitmap(16, 16, 64, tile.data())); + changed_tiles_.back().ApplyPalette(pal); + rom.RenderBitmap(&(changed_tiles_.back())); + } +} + void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset) { draw_list_->AddImage( (void *)bitmap.GetTexture(), diff --git a/src/gui/canvas.h b/src/gui/canvas.h index a563f2bd..341cab0f 100644 --- a/src/gui/canvas.h +++ b/src/gui/canvas.h @@ -7,6 +7,7 @@ #include #include "app/gfx/bitmap.h" +#include "app/rom.h" namespace yaze { namespace gui { @@ -21,6 +22,8 @@ class Canvas { void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0)); void DrawContextMenu(); + void DrawTilesFromUser(app::ROM& rom, Bytes& tile, + app::gfx::SNESPalette& pal); void DrawBitmap(const Bitmap& bitmap, int border_offset = 0); void DrawBitmap(const Bitmap& bitmap, int x_offset, int y_offset); void DrawOutline(int x, int y, int w, int h); @@ -39,6 +42,7 @@ class Canvas { bool enable_grid_ = true; bool enable_context_menu_ = true; bool custom_canvas_size_ = false; + bool is_hovered_ = false; ImDrawList* draw_list_; ImVector points_; @@ -46,6 +50,9 @@ class Canvas { ImVec2 canvas_sz_; ImVec2 canvas_p0_; ImVec2 canvas_p1_; + ImVec2 mouse_pos_in_canvas_; + + std::vector changed_tiles_; std::string title_; }; From 56ef3150287ee944a99a2b1ee520c4af6d3f15d8 Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Mon, 12 Sep 2022 21:17:41 -0500 Subject: [PATCH 14/16] bitmap optimization, sprites, inventory, tiles --- src/CMakeLists.txt | 4 +- src/app/core/constants.h | 296 ++++++ src/app/editor/overworld_editor.cc | 76 +- src/app/editor/overworld_editor.h | 5 +- src/app/editor/palette_editor.cc | 4 +- src/app/editor/palette_editor.h | 2 +- src/app/editor/screen_editor.cc | 93 +- src/app/editor/screen_editor.h | 15 +- src/app/gfx/bitmap.cc | 7 +- src/app/gfx/bitmap.h | 1 + src/app/rom.cc | 40 +- src/app/zelda3/inventory.cc | 84 ++ src/app/zelda3/inventory.h | 45 + src/app/zelda3/overworld.cc | 113 ++- src/app/zelda3/overworld.h | 21 +- src/app/zelda3/sprite.cc | 921 ++++++++++++++++++ src/app/zelda3/sprite.h | 68 ++ src/app/zelda3/{screen.cc => title_screen.cc} | 19 +- src/app/zelda3/{screen.h => title_screen.h} | 6 +- src/gui/canvas.cc | 23 +- src/gui/canvas.h | 4 +- 21 files changed, 1692 insertions(+), 155 deletions(-) create mode 100644 src/app/zelda3/inventory.cc create mode 100644 src/app/zelda3/inventory.h create mode 100644 src/app/zelda3/sprite.cc create mode 100644 src/app/zelda3/sprite.h rename src/app/zelda3/{screen.cc => title_screen.cc} (85%) rename src/app/zelda3/{screen.h => title_screen.h} (94%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afe40a3d..9d47e203 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,9 +68,11 @@ set( set( YAZE_APP_ZELDA3_SRC + app/zelda3/inventory.cc app/zelda3/overworld_map.cc app/zelda3/overworld.cc - app/zelda3/screen.cc + app/zelda3/title_screen.cc + app/zelda3/sprite.cc ) set( diff --git a/src/app/core/constants.h b/src/app/core/constants.h index 5a55c95d..aeff07c7 100644 --- a/src/app/core/constants.h +++ b/src/app/core/constants.h @@ -25,6 +25,14 @@ #define MENU_ITEM(w) if (ImGui::MenuItem(w)) #define MENU_ITEM2(w, v) if (ImGui::MenuItem(w, v)) +#define BUTTON_COLUMN(w) \ + ImGui::TableNextColumn(); \ + ImGui::Button(w); + +#define TEXT_COLUMN(w) \ + ImGui::TableNextColumn(); \ + ImGui::Text(w); + #define PRINT_IF_ERROR(expression) \ { \ auto error = expression; \ @@ -1301,6 +1309,294 @@ static const absl::string_view TileTypeNames[] = { "$FE Door X top? (unused?)", "$FF Door X top? (unused?)"}; +static const absl::string_view kSpriteDefaultNames[]{ + "00 Raven", + "01 Vulture", + "02 Flying Stalfos Head", + "03 No Pointer (Empty", + "04 Pull Switch (good", + "05 Pull Switch (unused", + "06 Pull Switch (bad", + "07 Pull Switch (unused", + "08 Octorock (one way", + "09 Moldorm (Boss", + "0A Octorock (four way", + "0B Chicken", + "0C Octorock (?", + "0D Buzzblock", + "0E Snapdragon", + "0F Octoballoon", + "10 Octoballon Hatchlings", + "11 Hinox", + "12 Moblin", + "13 Mini Helmasaure", + "14 Gargoyle's Domain Gate", + "15 Antifairy", + "16 Sahasrahla / Aginah", + "17 Bush Hoarder", + "18 Mini Moldorm", + "19 Poe", + "1A Dwarves", + "1B Arrow in wall", + "1C Statue", + "1D Weathervane", + "1E Crystal Switch", + "1F Bug-Catching Kid", + "20 Sluggula", + "21 Push Switch", + "22 Ropa", + "23 Red Bari", + "24 Blue Bari", + "25 Talking Tree", + "26 Hardhat Beetle", + "27 Deadrock", + "28 Storytellers", + "29 Blind Hideout attendant", + "2A Sweeping Lady", + "2B Storytellers", + "2C Lumberjacks", + "2D Telepathic Stones", + "2E Multipurpose Sprite", + "2F Race Npc", + "30 Person?", + "31 Fortune Teller", + "32 Angry Brothers", + "33 Pull for items", + "34 Scared Girl", + "35 Innkeeper", + "36 Witch", + "37 Waterfall", + "38 Arrow Target", + "39 Average Middle", + "3A Half Magic Bat", + "3B Dash Item", + "3C Village Kid", + "3D Signs? Chicken lady also showed up / Scared ladies outside houses.", + "3E Rock Hoarder", + "3F Tutorial Soldier", + "40 Lightning Lock", + "41 Blue Sword Soldier / Used by guards to detect player", + "42 Green Sword Soldier", + "43 Red Spear Soldier", + "44 Assault Sword Soldier", + "45 Green Spear Soldier", + "46 Blue Archer", + "47 Green Archer", + "48 Red Javelin Soldier", + "49 Red Javelin Soldier 2", + "4A Red Bomb Soldiers", + "4B Green Soldier Recruits", + "4C Geldman", + "4D Rabbit", + "4E Popo", + "4F Popo 2", + "50 Cannon Balls", + "51 Armos", + "52 Giant Zora", + "53 Armos Knights (Boss", + "54 Lanmolas (Boss", + "55 Fireball Zora", + "56 Walking Zora", + "57 Desert Palace Barriers", + "58 Crab", + "59 Bird", + "5A Squirrel", + "5B Spark (Left to Right", + "5C Spark (Right to Left", + "5D Roller (vertical moving", + "5E Roller (vertical moving", + "5F Roller", + "60 Roller (horizontal moving", + "61 Beamos", + "62 Master Sword", + "63 Devalant (Non", + "64 Devalant (Shooter", + "65 Shooting Gallery Proprietor", + "66 Moving Cannon Ball Shooters (Right", + "67 Moving Cannon Ball Shooters (Left", + "68 Moving Cannon Ball Shooters (Down", + "69 Moving Cannon Ball Shooters (Up", + "6A Ball N' Chain Trooper", + "6B Cannon Soldier", + "6C Mirror Portal", + "6D Rat", + "6E Rope", + "6F Keese", + "70 Helmasaur King Fireball", + "71 Leever", + "72 Activator for the ponds (where you throw in items", + "73 Uncle / Priest", + "74 Running Man", + "75 Bottle Salesman", + "76 Princess Zelda", + "77 Antifairy (Alternate", + "78 Village Elder", + "79 Bee", + "7A Agahnim", + "7B Agahnim Energy Ball", + "7C Hyu", + "7D Big Spike Trap", + "7E Guruguru Bar (Clockwise", + "7F Guruguru Bar (Counter Clockwise", + "80 Winder", + "81 Water Tektite", + "82 Antifairy Circle", + "83 Green Eyegore", + "84 Red Eyegore", + "85 Yellow Stalfos", + "86 Kodongos", + "87 Flames", + "88 Mothula (Boss", + "89 Mothula's Beam", + "8A Spike Trap", + "8B Gibdo", + "8C Arrghus (Boss", + "8D Arrghus spawn", + "8E Terrorpin", + "8F Slime", + "90 Wallmaster", + "91 Stalfos Knight", + "92 Helmasaur King", + "93 Bumper", + "94 Swimmers", + "95 Eye Laser (Right", + "96 Eye Laser (Left", + "97 Eye Laser (Down", + "98 Eye Laser (Up", + "99 Pengator", + "9A Kyameron", + "9B Wizzrobe", + "9C Tadpoles", + "9D Tadpoles", + "9E Ostrich (Haunted Grove", + "9F Flute", + "A0 Birds (Haunted Grove", + "A1 Freezor", + "A2 Kholdstare (Boss", + "A3 Kholdstare's Shell", + "A4 Falling Ice", + "A5 Zazak Fireball", + "A6 Red Zazak", + "A7 Stalfos", + "A8 Bomber Flying Creatures from Darkworld", + "A9 Bomber Flying Creatures from Darkworld", + "AA Pikit", + "AB Maiden", + "AC Apple", + "AD Lost Old Man", + "AE Down Pipe", + "AF Up Pipe", + "B0 Right Pip", + "B1 Left Pipe", + "B2 Good bee again?", + "B3 Hylian Inscription", + "B4 Thief?s chest (not the one that follows you", + "B5 Bomb Salesman", + "B6 Kiki", + "B7 Maiden following you in Blind Dungeon", + "B8 Monologue Testing Sprite", + "B9 Feuding Friends on Death Mountain", + "BA Whirlpool", + "BB Salesman / chestgame guy / 300 rupee giver guy / Chest game thief", + "BC Drunk in the inn", + "BD Vitreous (Large Eyeball", + "BE Vitreous (Small Eyeball", + "BF Vitreous' Lightning", + "C0 Monster in Lake of Ill Omen / Quake Medallion", + "C1 Agahnim teleporting Zelda to dark world", + "C2 Boulders", + "C3 Gibo", + "C4 Thief", + "C5 Medusa", + "C6 Four Way Fireball Spitters (spit when you use your sword", + "C7 Hokku", + "C8 Big Fairy who heals you", + "C9 Tektite", + "CA Chain Chomp", + "CB Trinexx", + "CC Another part of trinexx", + "CD Yet another part of trinexx", + "CE Blind The Thief (Boss)", + "CF Swamola", + "D0 Lynel", + "D1 Bunny Beam", + "D2 Flopping fish", + "D3 Stal", + "D4 Landmine", + "D5 Digging Game Proprietor", + "D6 Ganon", + "D7 Copy of Ganon", + "D8 Heart", + "D9 Green Rupee", + "DA Blue Rupee", + "DB Red Rupee", + "DC Bomb Refill (1)", + "DD Bomb Refill (4)", + "DE Bomb Refill (8)", + "DF Small Magic Refill", + "E0 Full Magic Refill", + "E1 Arrow Refill (5)", + "E2 Arrow Refill (10)", + "E3 Fairy", + "E4 Key", + "E5 Big Key", + "E6 Shield", + "E7 Mushroom", + "E8 Fake Master Sword", + "E9 Magic Shop dude / His items", + "EA Heart Container", + "EB Heart Piece", + "EC Bushes", + "ED Cane Of Somaria Platform", + "EE Mantle", + "EF Cane of Somaria Platform (Unused)", + "F0 Cane of Somaria Platform (Unused)", + "F1 Cane of Somaria Platform (Unused)", + "F2 Medallion Tablet", + "F3", + "F4 Falling Rocks", + "F5", + "F6", + "F7", + "F8", + "F9", + "FA", + "FB", + "FC", + "FD", + "FE", + "FF", +}; + +static const absl::string_view overlordnames[] = { + "Overlord_SpritePositionTarget", + "Overlord_AllDirectionMetalBallFactory", + "Overlord_CascadeMetalBallFactory", + "Overlord_StalfosFactory", + "Overlord_StalfosTrap", + "Overlord_SnakeTrap", + "Overlord_MovingFloor", + "Overlord_ZolFactory", + "Overlord_WallMasterFactory", + "Overlord_CrumbleTilePath 1", + "Overlord_CrumbleTilePath 2", + "Overlord_CrumbleTilePath 3", + "Overlord_CrumbleTilePath 4", + "Overlord_CrumbleTilePath 5", + "Overlord_CrumbleTilePath 6", + "Overlord_PirogusuFactory 1", + "Overlord_PirogusuFactory 2", + "Overlord_PirogusuFactory 3", + "Overlord_PirogusuFactory 4", + "Overlord_FlyingTileFactory", + "Overlord_WizzrobeFactory", + "Overlord_ZoroFactory", + "Overlord_StalfosTrapTriggerWindow", + "Overlord_RedStalfosTrap", + "Overlord_ArmosCoordinator", + "Overlord_BombTrap", +}; + } // namespace core } // namespace app } // namespace yaze diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index c4244298..1477176e 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -101,46 +101,21 @@ absl::Status OverworldEditor::DrawToolset() { for (const auto &name : kToolsetColumnNames) ImGui::TableSetupColumn(name.data()); - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_UNDO); - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_REDO); - ImGui::TableNextColumn(); - ImGui::Text(ICON_MD_MORE_VERT); - - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_ZOOM_OUT); - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_ZOOM_IN); - ImGui::TableNextColumn(); - ImGui::Text(ICON_MD_MORE_VERT); - - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_DRAW); - // Entrances - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_DOOR_FRONT); - // Exits - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_DOOR_BACK); - // Items - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_GRASS); - // Sprites - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_PEST_CONTROL_RODENT); - // Transports - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_ADD_LOCATION); - // Music - ImGui::TableNextColumn(); - ImGui::Button(ICON_MD_MUSIC_NOTE); - - // Separator - ImGui::TableNextColumn(); - ImGui::Text(ICON_MD_MORE_VERT); - // Music - ImGui::TableNextColumn(); + BUTTON_COLUMN(ICON_MD_UNDO) // Undo + BUTTON_COLUMN(ICON_MD_REDO) // Redo + TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator + BUTTON_COLUMN(ICON_MD_ZOOM_OUT) // Zoom Out + BUTTON_COLUMN(ICON_MD_ZOOM_IN) // Zoom In + TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator + BUTTON_COLUMN(ICON_MD_DRAW); // Draw Tile + BUTTON_COLUMN(ICON_MD_DOOR_FRONT) // Entrances + BUTTON_COLUMN(ICON_MD_DOOR_BACK) // Exits + BUTTON_COLUMN(ICON_MD_GRASS) // Items + BUTTON_COLUMN(ICON_MD_PEST_CONTROL_RODENT) // Sprites + BUTTON_COLUMN(ICON_MD_ADD_LOCATION) // Transports + BUTTON_COLUMN(ICON_MD_MUSIC_NOTE) // Music + TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator + ImGui::TableNextColumn(); // Palette palette_editor_.DisplayPalette(palette_, overworld_.isLoaded()); ImGui::EndTable(); @@ -223,9 +198,10 @@ void OverworldEditor::DrawOverworldCanvas() { for (const auto &each : overworld_.Entrances()) { if (each.mapId_ < 64 + (current_world_ * 0x40) && each.mapId_ >= (current_world_ * 0x40)) { - overworld_map_canvas_.DrawOutline(each.x_, each.y_, 16, 16); + overworld_map_canvas_.DrawRect(each.x_, each.y_, 16, 16, + ImVec4(210, 24, 210, 150)); std::string str = absl::StrFormat("%#x", each.entranceId_); - overworld_map_canvas_.DrawText(str, each.x_ - 2, each.y_ - 14); + overworld_map_canvas_.DrawText(str, each.x_ - 4, each.y_ - 2); } } } @@ -271,9 +247,7 @@ void OverworldEditor::DrawTileSelector() { void OverworldEditor::DrawTile16Selector() { blockset_canvas_.DrawBackground(ImVec2(0x100 + 1, (8192 * 2) + 1)); blockset_canvas_.DrawContextMenu(); - if (map_blockset_loaded_) { - blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 2); - } + blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 2, map_blockset_loaded_); blockset_canvas_.DrawGrid(32.0f); blockset_canvas_.DrawOverlay(); } @@ -301,13 +275,11 @@ void OverworldEditor::DrawTile8Selector() { } void OverworldEditor::DrawAreaGraphics() { - if (overworld_.isLoaded()) { - current_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 16 * 64 + 1)); - current_gfx_canvas_.DrawContextMenu(); - current_gfx_canvas_.DrawBitmap(current_gfx_bmp_); - current_gfx_canvas_.DrawGrid(32.0f); - current_gfx_canvas_.DrawOverlay(); - } + current_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 16 * 64 + 1)); + current_gfx_canvas_.DrawContextMenu(); + current_gfx_canvas_.DrawBitmap(current_gfx_bmp_, 2, overworld_.isLoaded()); + current_gfx_canvas_.DrawGrid(32.0f); + current_gfx_canvas_.DrawOverlay(); } void OverworldEditor::LoadGraphics() { diff --git a/src/app/editor/overworld_editor.h b/src/app/editor/overworld_editor.h index ccbaf9b1..2b1cb868 100644 --- a/src/app/editor/overworld_editor.h +++ b/src/app/editor/overworld_editor.h @@ -84,20 +84,21 @@ class OverworldEditor { ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingStretchSame; + Bytes selected_tile_data_; std::unordered_map graphics_bin_; std::unordered_map current_graphics_set_; std::unordered_map maps_bmp_; + std::unordered_map sprite_previews_; ROM rom_; - zelda3::Overworld overworld_; PaletteEditor palette_editor_; + zelda3::Overworld overworld_; gfx::SNESPalette palette_; gfx::Bitmap tile16_blockset_bmp_; gfx::Bitmap current_gfx_bmp_; gfx::Bitmap all_gfx_bmp; gfx::Bitmap selected_tile_bmp_; - Bytes selected_tile_data_; gui::Canvas overworld_map_canvas_; gui::Canvas current_gfx_canvas_; diff --git a/src/app/editor/palette_editor.cc b/src/app/editor/palette_editor.cc index ca676fe3..00e6c381 100644 --- a/src/app/editor/palette_editor.cc +++ b/src/app/editor/palette_editor.cc @@ -41,8 +41,7 @@ absl::Status PaletteEditor::Update() { return absl::OkStatus(); } -absl::Status PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, - bool loaded) { +void PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, bool loaded) { static ImVec4 color = ImVec4(0, 0, 0, 255.f); ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_NoDragDrop | @@ -122,7 +121,6 @@ absl::Status PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, ImGui::EndGroup(); ImGui::EndPopup(); } - return absl::OkStatus(); } } // namespace editor diff --git a/src/app/editor/palette_editor.h b/src/app/editor/palette_editor.h index d27551b8..80ab485f 100644 --- a/src/app/editor/palette_editor.h +++ b/src/app/editor/palette_editor.h @@ -26,7 +26,7 @@ static constexpr absl::string_view kPaletteGroupNames[] = { class PaletteEditor { public: absl::Status Update(); - absl::Status DisplayPalette(gfx::SNESPalette& palette, bool loaded); + void DisplayPalette(gfx::SNESPalette& palette, bool loaded); auto SetupROM(ROM& rom) { rom_ = rom; } diff --git a/src/app/editor/screen_editor.cc b/src/app/editor/screen_editor.cc index 0ad889f2..793d660c 100644 --- a/src/app/editor/screen_editor.cc +++ b/src/app/editor/screen_editor.cc @@ -27,13 +27,12 @@ ScreenEditor::ScreenEditor() { screen_canvas_.SetCanvasSize(ImVec2(512, 512)); } void ScreenEditor::Update() { TAB_BAR("##TabBar") - DrawMosaicEditor(); + DrawInventoryMenuEditor(); DrawTitleScreenEditor(); DrawNamingScreenEditor(); DrawOverworldMapEditor(); DrawDungeonMapsEditor(); - DrawGameMenuEditor(); - DrawHUDEditor(); + DrawMosaicEditor(); END_TAB_BAR() } @@ -60,6 +59,61 @@ void ScreenEditor::DrawWorldGrid(int world, int h, int w) { } } +void ScreenEditor::DrawInventoryMenuEditor() { + TAB_ITEM("Inventory Menu") + + static bool create = false; + if (!create) { + PRINT_IF_ERROR(rom_.LoadAllGraphicsData()) + all_gfx_ = rom_.GetGraphicsBuffer(); + inventory_.Create(all_gfx_); + create = true; + } + + if (ImGui::BeginTable("InventoryScreen", 2, ImGuiTableFlags_Resizable)) { + ImGui::TableSetupColumn("Canvas"); + ImGui::TableSetupColumn("Tiles"); + ImGui::TableHeadersRow(); + + ImGui::TableNextColumn(); + screen_canvas_.DrawBackground(); + screen_canvas_.DrawContextMenu(); + screen_canvas_.DrawBitmap(inventory_.Bitmap(), 2, create); + screen_canvas_.DrawGrid(); + screen_canvas_.DrawOverlay(); + + ImGui::TableNextColumn(); + tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, 192 * 2 + 2)); + tilesheet_canvas_.DrawContextMenu(); + tilesheet_canvas_.DrawBitmap(inventory_.Tilesheet(), 2, create); + tilesheet_canvas_.DrawGrid(); + tilesheet_canvas_.DrawOverlay(); + + ImGui::EndTable(); + } + + ImGui::SameLine(); + + END_TAB_ITEM() +} + +void ScreenEditor::DrawTitleScreenEditor() { + TAB_ITEM("Title Screen") + END_TAB_ITEM() +} +void ScreenEditor::DrawNamingScreenEditor() { + TAB_ITEM("Naming Screen") + END_TAB_ITEM() +} +void ScreenEditor::DrawOverworldMapEditor() { + TAB_ITEM("Overworld Map") + END_TAB_ITEM() +} +void ScreenEditor::DrawDungeonMapsEditor() { + TAB_ITEM("Dungeon Maps") + END_TAB_ITEM() +} + void ScreenEditor::DrawMosaicEditor() { TAB_ITEM("Mosaic Transitions") @@ -94,39 +148,6 @@ void ScreenEditor::DrawMosaicEditor() { END_TAB_ITEM() } -void ScreenEditor::DrawTitleScreenEditor() { - TAB_ITEM("Title Screen") - END_TAB_ITEM() -} -void ScreenEditor::DrawNamingScreenEditor() { - TAB_ITEM("Naming Screen") - END_TAB_ITEM() -} -void ScreenEditor::DrawOverworldMapEditor() { - TAB_ITEM("Overworld Map") - END_TAB_ITEM() -} -void ScreenEditor::DrawDungeonMapsEditor() { - TAB_ITEM("Dungeon Maps") - END_TAB_ITEM() -} -void ScreenEditor::DrawGameMenuEditor() { - TAB_ITEM("Game Menu") - END_TAB_ITEM() -} -void ScreenEditor::DrawHUDEditor() { - TAB_ITEM("Heads-up Display") - END_TAB_ITEM() -} - -void ScreenEditor::DrawCanvas() { - screen_canvas_.DrawBackground(); - screen_canvas_.DrawContextMenu(); - - screen_canvas_.DrawGrid(); - screen_canvas_.DrawOverlay(); -} - void ScreenEditor::DrawToolset() { static bool show_bg1 = true; static bool show_bg2 = true; diff --git a/src/app/editor/screen_editor.h b/src/app/editor/screen_editor.h index a6a363e1..46b0fbfa 100644 --- a/src/app/editor/screen_editor.h +++ b/src/app/editor/screen_editor.h @@ -10,7 +10,7 @@ #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "app/rom.h" -#include "app/zelda3/screen.h" +#include "app/zelda3/inventory.h" #include "gui/canvas.h" namespace yaze { @@ -24,7 +24,10 @@ static int overworldCustomMosaicArray = 0x1301F0; class ScreenEditor { public: ScreenEditor(); - void SetupROM(ROM &rom) { rom_ = rom; } + void SetupROM(ROM &rom) { + rom_ = rom; + inventory_.SetupROM(rom_); + } void Update(); private: @@ -33,19 +36,19 @@ class ScreenEditor { void DrawNamingScreenEditor(); void DrawOverworldMapEditor(); void DrawDungeonMapsEditor(); - void DrawGameMenuEditor(); - void DrawHUDEditor(); + void DrawInventoryMenuEditor(); - void DrawCanvas(); void DrawToolset(); void DrawWorldGrid(int world, int h = 8, int w = 8); char mosaic_tiles_[core::kNumOverworldMaps]; ROM rom_; + Bytes all_gfx_; + zelda3::Inventory inventory_; snes_asm::Script mosaic_script_; - zelda3::Screen current_screen_; gui::Canvas screen_canvas_; + gui::Canvas tilesheet_canvas_; }; } // namespace editor diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index 201e890b..6d27ee93 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -47,8 +47,8 @@ void Bitmap::Create(int width, int height, int depth, uchar *data) { SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_, SDL_PIXELFORMAT_INDEX8), SDL_Surface_Deleter()); - GrayscalePalette(surface_->format->palette); surface_->pixels = pixel_data_; + GrayscalePalette(surface_->format->palette); } // Reserves data to later draw to surface via pointer @@ -57,13 +57,14 @@ void Bitmap::Create(int width, int height, int depth, int size) { height_ = height; depth_ = depth; data_size_ = size; + data_.reserve(size); + pixel_data_ = data_.data(); surface_ = std::unique_ptr( SDL_CreateRGBSurfaceWithFormat(0, width, height, depth, SDL_PIXELFORMAT_INDEX8), SDL_Surface_Deleter()); - GrayscalePalette(surface_->format->palette); - pixel_data_ = (uchar *)SDL_malloc(size); surface_->pixels = pixel_data_; + GrayscalePalette(surface_->format->palette); } // Pass raw pixel data directly to the surface diff --git a/src/app/gfx/bitmap.h b/src/app/gfx/bitmap.h index 84dfa5d0..ea03af47 100644 --- a/src/app/gfx/bitmap.h +++ b/src/app/gfx/bitmap.h @@ -53,6 +53,7 @@ class Bitmap { struct SDL_Surface_Deleter { void operator()(SDL_Surface *p) const { if (p != nullptr) { + p->pixels = nullptr; SDL_FreeSurface(p); p = nullptr; } diff --git a/src/app/rom.cc b/src/app/rom.cc index 91f8826d..cf8561b4 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -35,22 +35,28 @@ int GetGraphicsAddress(const uchar* data, uint8_t offset) { return core::SnesToPc(snes_addr); } -Bytes SNES3bppTo8bppSheet(Bytes sheet) { +Bytes SNES3bppTo8bppSheet(Bytes sheet, int bpp) { Bytes sheet_buffer_out(0x1000); int xx = 0; // positions where we are at on the sheet int yy = 0; int pos = 0; int ypos = 0; + if (bpp == 2) { + bpp = 16; + } else if (bpp == 3) { + bpp = 24; + } + // for each tiles, 16 per line for (int i = 0; i < 64; i++) { // for each line for (int y = 0; y < 8; y++) { //[0] + [1] + [16] for (int x = 0; x < 8; x++) { - auto b1 = ((sheet[(y * 2) + (24 * pos)] & (kGraphicsBitmap[x]))); - auto b2 = (sheet[((y * 2) + (24 * pos)) + 1] & (kGraphicsBitmap[x])); - auto b3 = (sheet[(16 + y) + (24 * pos)] & (kGraphicsBitmap[x])); + auto b1 = ((sheet[(y * 2) + (bpp * pos)] & (kGraphicsBitmap[x]))); + auto b2 = (sheet[((y * 2) + (bpp * pos)) + 1] & (kGraphicsBitmap[x])); + auto b3 = (sheet[(16 + y) + (bpp * pos)] & (kGraphicsBitmap[x])); unsigned char b = 0; if (b1 != 0) { b |= 1; @@ -58,7 +64,7 @@ Bytes SNES3bppTo8bppSheet(Bytes sheet) { if (b2 != 0) { b |= 2; } - if (b3 != 0) { + if (b3 != 0 && bpp != 16) { b |= 4; } sheet_buffer_out[x + (xx) + (y * 128) + (yy * 1024)] = b; @@ -590,7 +596,7 @@ absl::StatusOr ROM::DecompressOverworld(int pos, int size) { // 218-222 -> compressed 2bpp -> (decompressed each) 0x800 chars absl::Status ROM::LoadAllGraphicsData() { Bytes sheet; - bool convert = false; + bool bpp3 = false; for (int i = 0; i < core::NumberOfSheets; i++) { if (i >= 115 && i <= 126) { // uncompressed sheets @@ -599,17 +605,19 @@ absl::Status ROM::LoadAllGraphicsData() { for (int j = 0; j < core::Uncompressed3BPPSize; j++) { sheet[j] = rom_data_[j + offset]; } - convert = true; + bpp3 = true; } else if (i == 113 || i == 114 || i >= 218) { - convert = false; + auto offset = GetGraphicsAddress(rom_data_.data(), i); + ASSIGN_OR_RETURN(sheet, Decompress(offset, 0x800)) + bpp3 = false; } else { auto offset = GetGraphicsAddress(rom_data_.data(), i); ASSIGN_OR_RETURN(sheet, Decompress(offset)) - convert = true; + bpp3 = true; } - if (convert) { - auto converted_sheet = SNES3bppTo8bppSheet(sheet); + if (bpp3) { + auto converted_sheet = SNES3bppTo8bppSheet(sheet, 3); graphics_bin_[i] = gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, core::kTilesheetDepth, converted_sheet.data(), 0x1000); @@ -619,8 +627,14 @@ absl::Status ROM::LoadAllGraphicsData() { graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } else { - for (int j = 0; j < 0x1000; ++j) { - graphics_buffer_.push_back(0xFF); + auto converted_sheet = SNES3bppTo8bppSheet(sheet, 2); + graphics_bin_[i] = + gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, + core::kTilesheetDepth, converted_sheet.data(), 0x1000); + graphics_bin_.at(i).CreateTexture(renderer_); + + for (int j = 0; j < graphics_bin_.at(i).GetSize(); ++j) { + graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } } diff --git a/src/app/zelda3/inventory.cc b/src/app/zelda3/inventory.cc new file mode 100644 index 00000000..923054a1 --- /dev/null +++ b/src/app/zelda3/inventory.cc @@ -0,0 +1,84 @@ +#include "inventory.h" + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_tile.h" +#include "app/rom.h" +#include "gui/canvas.h" + +namespace yaze { +namespace app { +namespace zelda3 { +void Inventory::Create(Bytes& all_gfx) { + data_.reserve(256 * 256); + for (int i = 0; i < 256 * 256; i++) { + data_.push_back(0xFF); + } + BuildTileset(all_gfx); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos))); + const int offsets[] = {0x00, 0x08, 0x200, 0x208}; + auto xx = 0; + auto yy = 0; + + int i = 0; + for (const auto& tile : tiles_) { + int offset = offsets[i]; + for (auto y = 0; y < 0x08; ++y) { + for (auto x = 0; x < 0x08; ++x) { + int mx = x; + int my = y; + + if (tile.horizontal_mirror_ != 0) { + mx = 0x07 - x; + } + + if (tile.vertical_mirror_ != 0) { + my = 0x07 - y; + } + + int xpos = ((tile.id_ % 0x10) * 0x08); + int ypos = (((tile.id_ / 0x10)) * 0x200); + int source = ypos + xpos + (x + (y * 0x80)); + + auto destination = xx + yy + offset + (mx + (my * 0x100)); + data_[destination] = (tilesheets_[source] & 0x0F); + } + } + + xx += 0x10; + if (xx >= 0x80) { + yy += 0x800; + xx = 0; + } + + if (i == 4) { + i = 0; + } + i++; + } + bitmap_.Create(256, 256, 128, data_); + // bitmap_.ApplyPalette(rom_.GetPaletteGroup("hud")[0]); + rom_.RenderBitmap(&bitmap_); +} + +void Inventory::BuildTileset(Bytes& all_gfx) { + //const int offsets[] = {0xDC000, 0x6D900, 0x6EF00, 0x6F000, 0xD8000, 0xD9000}; + const int offsets[] = {0xDC000, 0x6D900, 0x6EF00, 0x6F000, 0xD8000, 0xD9000}; + tilesheets_.reserve(6 * 0x1000); + for (int i = 0; i < 6 * 0x1000; i++) { + tilesheets_.push_back(0xFF); + } + + for (int y = 0; y < 6; y++) { + int offset = offsets[y]; + for (int x = 0; x < 0x1000; x++) { + tilesheets_[x + (y * 0x1000)] = all_gfx[offset + x + (y * 0x1000)]; + } + } + + tilesheets_bmp_.Create(128, 192, 64, tilesheets_); + rom_.RenderBitmap(&tilesheets_bmp_); +} + +} // namespace zelda3 +} // namespace app +} // namespace yaze \ No newline at end of file diff --git a/src/app/zelda3/inventory.h b/src/app/zelda3/inventory.h new file mode 100644 index 00000000..3af04d26 --- /dev/null +++ b/src/app/zelda3/inventory.h @@ -0,0 +1,45 @@ +#ifndef YAZE_APP_ZELDA3_INVENTORY_H +#define YAZE_APP_ZELDA3_INVENTORY_H + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_tile.h" +#include "app/rom.h" +#include "gui/canvas.h" + +namespace yaze { +namespace app { +namespace zelda3 { + +constexpr int kMenuGfxStart = 0xE000; +constexpr int kLampItemPos = 0x6F6F0; +constexpr int kBowItemPos = 0x6F631; + +class Inventory { + public: + void SetupROM(ROM& rom) { rom_ = rom; } + auto Bitmap() const { return bitmap_; } + auto Tilesheet() const { return tilesheets_bmp_; } + + void Create(Bytes& all_gfx); + + private: + void BuildTileset(Bytes& all_gfx); + + + ROM rom_; + + Bytes data_; + gfx::Bitmap bitmap_; + + Bytes tilesheets_; + gfx::Bitmap tilesheets_bmp_; + + gui::Canvas canvas_; + std::vector tiles_; +}; + +} // namespace zelda3 +} // namespace app +} // namespace yaze + +#endif \ No newline at end of file diff --git a/src/app/zelda3/overworld.cc b/src/app/zelda3/overworld.cc index 2ae05a0c..e807be2f 100644 --- a/src/app/zelda3/overworld.cc +++ b/src/app/zelda3/overworld.cc @@ -39,6 +39,7 @@ absl::Status Overworld::Load(ROM &rom) { FetchLargeMaps(); LoadEntrances(); + LoadSprites(); auto size = tiles16.size(); for (int i = 0; i < core::kNumOverworldMaps; ++i) { @@ -265,10 +266,118 @@ void Overworld::LoadEntrances() { int p = (mapPos + 0x400) >> 1; int x = (p % 64); int y = (p >> 6); - all_holes_.emplace_back(EntranceOWEditor( + all_holes_.emplace_back( (x * 16) + (((mapId % 64) - (((mapId % 64) / 8) * 8)) * 512), (y * 16) + (((mapId % 64) / 8) * 512), entranceId, mapId, - (ushort)(mapPos + 0x400), true)); + (ushort)(mapPos + 0x400), true); + } +} + +void Overworld::LoadSprites() { + // LW[0] = RainState 0 to 63 there's no data for DW + // LW[1] = ZeldaState 0 to 128 ; Contains LW and DW <128 or 144 wtf + // LW[2] = AgahState 0 to ?? ;Contains data for LW and DW + + for (int i = 0; i < 3; i++) { + all_sprites_.emplace_back(std::vector()); + } + + // Console.WriteLine(((core::overworldSpritesBegining & 0xFFFF) + (09 << + // 16)).ToString("X6")); + for (int i = 0; i < 64; i++) { + if (map_parent_[i] == i) { + // Beginning Sprites + int ptrPos = core::overworldSpritesBegining + (i * 2); + int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos)); + while (true) { + uchar b1 = rom_[spriteAddress]; + uchar b2 = rom_[spriteAddress + 1]; + uchar b3 = rom_[spriteAddress + 2]; + if (b1 == 0xFF) { + break; + } + + int mapY = (i / 8); + int mapX = (i % 8); + + int realX = ((b2 & 0x3F) * 16) + mapX * 512; + int realY = ((b1 & 0x3F) * 16) + mapY * 512; + + all_sprites_[0].emplace_back(overworld_maps_[i].AreaGraphics(), + (uchar)i, b3, (uchar)(b2 & 0x3F), + (uchar)(b1 & 0x3F), realX, realY); + + spriteAddress += 3; + } + } + } + + for (int i = 0; i < 144; i++) { + if (map_parent_[i] == i) { + // Zelda Saved Sprites + int ptrPos = core::overworldSpritesZelda + (i * 2); + int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos)); + while (true) { + uchar b1 = rom_[spriteAddress]; + uchar b2 = rom_[spriteAddress + 1]; + uchar b3 = rom_[spriteAddress + 2]; + if (b1 == 0xFF) { + break; + } + + int editorMapIndex = i; + if (editorMapIndex >= 128) { + editorMapIndex = i - 128; + } else if (editorMapIndex >= 64) { + editorMapIndex = i - 64; + } + + int mapY = (editorMapIndex / 8); + int mapX = (editorMapIndex % 8); + + int realX = ((b2 & 0x3F) * 16) + mapX * 512; + int realY = ((b1 & 0x3F) * 16) + mapY * 512; + + all_sprites_[1].emplace_back(overworld_maps_[i].AreaGraphics(), + (uchar)i, b3, (uchar)(b2 & 0x3F), + (uchar)(b1 & 0x3F), realX, realY); + + spriteAddress += 3; + } + } + + // Agahnim Dead Sprites + if (map_parent_[i] == i) { + int ptrPos = core::overworldSpritesAgahnim + (i * 2); + int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos)); + while (true) { + uchar b1 = rom_[spriteAddress]; + uchar b2 = rom_[spriteAddress + 1]; + uchar b3 = rom_[spriteAddress + 2]; + if (b1 == 0xFF) { + break; + } + + int editorMapIndex = i; + if (editorMapIndex >= 128) { + editorMapIndex = i - 128; + } else if (editorMapIndex >= 64) { + editorMapIndex = i - 64; + } + + int mapY = (editorMapIndex / 8); + int mapX = (editorMapIndex % 8); + + int realX = ((b2 & 0x3F) * 16) + mapX * 512; + int realY = ((b1 & 0x3F) * 16) + mapY * 512; + + all_sprites_[2].emplace_back(overworld_maps_[i].AreaGraphics(), + (uchar)i, b3, (uchar)(b2 & 0x3F), + (uchar)(b1 & 0x3F), realX, realY); + + spriteAddress += 3; + } + } } } diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index 5e0cf007..ca2212d9 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -12,12 +12,13 @@ #include "app/gfx/snes_tile.h" #include "app/rom.h" #include "app/zelda3/overworld_map.h" +#include "app/zelda3/sprite.h" namespace yaze { namespace app { namespace zelda3 { -class EntranceOWEditor { +class OverworldEntrance { public: int x_; int y_; @@ -27,8 +28,8 @@ class EntranceOWEditor { bool isHole = false; bool deleted = false; - EntranceOWEditor(int x, int y, uchar entranceId, short mapId, ushort mapPos, - bool hole) { + OverworldEntrance(int x, int y, uchar entranceId, short mapId, ushort mapPos, + bool hole) { x_ = x; y_ = y; entranceId_ = entranceId; @@ -45,7 +46,7 @@ class EntranceOWEditor { } auto Copy() { - return new EntranceOWEditor(x_, y_, entranceId_, mapId_, mapPos, isHole); + return new OverworldEntrance(x_, y_, entranceId_, mapId_, mapPos, isHole); } void updateMapStuff(short mapId) { @@ -77,7 +78,7 @@ class Overworld { auto GetTiles16() const { return tiles16; } auto GetOverworldMap(uint index) { return overworld_maps_[index]; } auto GetOverworldMaps() const { return overworld_maps_; } - + auto Sprites() const { return all_sprites_[game_state_]; } auto AreaGraphics() const { return overworld_maps_[current_map_].AreaGraphics(); } @@ -89,7 +90,7 @@ class Overworld { auto Tile16Blockset() const { return overworld_maps_[current_map_].Tile16Blockset(); } - + auto GameState() const { return game_state_; } auto isLoaded() const { return is_loaded_; } void SetCurrentMap(int i) { current_map_ = i; } @@ -113,10 +114,11 @@ class Overworld { absl::Status DecompressAllMapTiles(); void FetchLargeMaps(); void LoadEntrances(); + void LoadSprites(); void LoadOverworldMap(); - int game_state_ = 1; + int game_state_ = 0; int current_map_ = 0; uchar map_parent_[160]; bool is_loaded_ = false; @@ -127,8 +129,9 @@ class Overworld { std::vector tiles16; std::vector tiles32; std::vector overworld_maps_; - std::vector all_entrances_; - std::vector all_holes_; + std::vector all_entrances_; + std::vector all_holes_; + std::vector> all_sprites_; }; } // namespace zelda3 diff --git a/src/app/zelda3/sprite.cc b/src/app/zelda3/sprite.cc new file mode 100644 index 00000000..52774d58 --- /dev/null +++ b/src/app/zelda3/sprite.cc @@ -0,0 +1,921 @@ +#include "sprite.h" + +namespace yaze { +namespace app { +namespace zelda3 { + +Sprite::Sprite(Bytes src, uchar mapid, uchar id, uchar x, uchar y, int map_x, + int map_y) { + current_gfx_ = src; + overworld_ = true; + map_id_ = mapid; + id_ = id; + x_ = x; + y_ = y; + nx_ = x; + ny_ = y; + name_ = core::kSpriteDefaultNames[id]; + map_x_ = map_x; + map_y_ = map_y; + preview_gfx_.reserve(64 * 64); + for (int i = 0; i < 64 * 64; i++) { + preview_gfx_.push_back(0xFF); + } +} + +void Sprite::updateBBox() { + lowerX_ = 1; + lowerY_ = 1; + higherX_ = 15; + higherY_ = 15; +} + +void Sprite::Draw(bool picker) { + uchar x = nx_; + uchar y = ny_; + picker_ = picker; + + if (overlord_ == 0x07) { + if (id_ == 0x1A) { + DrawSpriteTile((x * 16), (y * 16), 14, 6, 11); // bomb + } else if (id_ == 0x05) { + DrawSpriteTile((x * 16), (y * 16) - 12, 12, 16, 12, false, true); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 12, false, true); + } else if (id_ == 0x06) { + DrawSpriteTile((x * 16), (y * 16), 10, 26, 14, true, true, 2, + 2); // snek + } else if (id_ == 0x09) { + DrawSpriteTile((x * 16), (y * 16), 6, 26, 14); + DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 8, 26, 14); + DrawSpriteTile((x * 16), (y * 16) + 16, 10, 27, 14, false, false, 1, 1); + } else if (id_ == 0x14) { + DrawSpriteTile((x * 16), (y * 16) + 8, 12, 06, 12, false, false, 2, + 1); // shadow tile + DrawSpriteTile((x * 16), (y * 16) - 8, 3, 29, 8, false, false, 1, + 1); // tile + DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 3, 29, 8, true, false, 1, + 1); // tile + DrawSpriteTile((x * 16), (y * 16), 3, 29, 8, false, true, 1, + 1); // tile + DrawSpriteTile((x * 16) + 8, (y * 16), 3, 29, 8, true, true, 1, + 1); // tile + } else { + DrawSpriteTile((x * 16), (y * 16), 4, 4, 5); + } + + if (nx_ != x || ny_ != y) { + bounding_box_.x = (lowerX_ + (nx_ * 16)); + bounding_box_.y = (lowerY_ + (ny_ * 16)); + bounding_box_.w = width_; + bounding_box_.h = height_; + } else { + bounding_box_.x = (lowerX_ + (x * 16)); + bounding_box_.y = (lowerY_ + (y * 16)); + bounding_box_.w = width_; + bounding_box_.h = height_; + } + + return; + } + + if (id_ == 0x00) { + DrawSpriteTile((x * 16), (y * 16), 4, 28, 10); + } else if (id_ == 0x01) { + DrawSpriteTile((x * 16) - 8, (y * 16), 6, 24, 12, false, false, 2, 2); + DrawSpriteTile((x * 16) + 8, (y * 16), 6, 24, 12, true, false, 2, 2); + } else if (id_ == 0x02) { + DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); + } else if (id_ == 0x04) { + uchar p = 3; + + DrawSpriteTile((x * 16), (y * 16), 14, 28, p); + DrawSpriteTile((x * 16), (y * 16), 14, 30, p); + } else if (id_ == 0x05) { + uchar p = 3; + + DrawSpriteTile((x * 16), (y * 16), 14, 28, p); + DrawSpriteTile((x * 16), (y * 16), 14, 30, p); + } else if (id_ == 0x06) { + uchar p = 3; + + DrawSpriteTile((x * 16), (y * 16), 14, 28, p); + DrawSpriteTile((x * 16), (y * 16), 14, 30, p); + } else if (id_ == 0x07) { + uchar p = 3; + + DrawSpriteTile((x * 16), (y * 16), 14, 28, p); + DrawSpriteTile((x * 16), (y * 16), 14, 30, p); + } else if (id_ == 0x08) { + DrawSpriteTile((x * 16), (y * 16), 0, 24, 6); + DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 6, false, false, 1, 1); + } else if (id_ == 0x09) { + DrawSpriteTile((x * 16) - 22, (y * 16) - 24, 12, 24, 12, false, false, 2, + 2); // Moldorm tail + DrawSpriteTile((x * 16) - 16, (y * 16) - 20, 8, 24, 12, false, false, 2, + 2); // Moldorm b2 + DrawSpriteTile((x * 16) - 12, (y * 16) - 16, 4, 24, 12, false, false, 4, + 4); // Moldorm b + DrawSpriteTile((x * 16), (y * 16), 0, 24, 12, false, false, 4, + 4); // Moldorm head + + DrawSpriteTile((x * 16) + 20, (y * 16) + 12, 8, 26, 14, false, false, 2, + 2); // Moldorm eye + DrawSpriteTile((x * 16) + 12, (y * 16) + 20, 8, 26, 14, false, false, 2, + 2); // Moldorm eye + } else if (id_ == 0x0A) { + DrawSpriteTile((x * 16), (y * 16), 0, 24, 8); + DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 8, false, false, 1, 1); + } else if (id_ == 0x0B) { + DrawSpriteTile((x * 16), (y * 16), 10, 30, 10); + } else if (id_ == 0x0C) { + DrawSpriteTile((x * 16), (y * 16), 0, 24, 8); + DrawSpriteTile((x * 16) + 4, (y * 16) + 6, 0, 24, 8, false, false, 1, 1); + } else if (id_ == 0x0D) { + DrawSpriteTile((x * 16), (y * 16), 14, 28, 12); + } else if (id_ == 0x0E) { + DrawSpriteTile((x * 16), (y * 16), 8, 18, 10, false, false, 3, 2); + } else if (id_ == 0x0F) { + DrawSpriteTile((x * 16), (y * 16), 14, 24, 8, false, false, 2, 3); + DrawSpriteTile((x * 16) + 16, (y * 16), 30, 8, 8, true, false, 1, 3); + } else if (id_ == 0x10) { + DrawSpriteTile((x * 16), (y * 16), 12, 31, 8, false, false, 1, 1); + } else if (id_ == 0x11) { + DrawSpriteTile((x * 16), (y * 16) + 16, 6, 16, 8, false, false, 2, + 2); // Feet + DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 4, 18, 8, false, false, 2, + 2); // Body1 + DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 4, 18, 8, true, false, 2, + 2); // Body2 + DrawSpriteTile((x * 16), (y * 16), 0, 16, 8, false, false, 2, + 2); // Head + } else if (id_ == 0x12) { + DrawSpriteTile((x * 16), (y * 16) + 8, 8, 26, 8); + DrawSpriteTile((x * 16), (y * 16), 6, 24, 8); + } else if (id_ == 0x13) { + DrawSpriteTile((x * 16), (y * 16), 4, 22, 2); + } else if (id_ == 0x15) { + // Antifairy + DrawSpriteTile((x * 16) + 2, (y * 16) + 8, 3, 30, 5, false, false, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16) + 2, 3, 30, 5, false, false, 1, 1); + DrawSpriteTile((x * 16) + 14, (y * 16) + 8, 3, 30, 5, false, false, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16) + 14, 3, 30, 5, false, false, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 1, 30, 5, false, false, 1, + 1); // Middle + } else if (id_ == 0x16) { + DrawSpriteTile((x * 16), (y * 16) + 8, 2, 26, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 26, 2); + } else if (id_ == 0x17) // Bush hoarder + { + DrawSpriteTile((x * 16), (y * 16), 8, 30, 10); + } else if (id_ == 0x18) // Mini moldorm + { + DrawSpriteTile((x * 16) + 13, (y * 16) + 17, 13, 21, 8, false, false, 1, + 1); // Tail + DrawSpriteTile((x * 16) + 5, (y * 16) + 8, 2, 22, 8); // Body + DrawSpriteTile((x * 16), (y * 16), 0, 22, 8); // Head + DrawSpriteTile((x * 16), (y * 16) - 4, 13, 20, 8, false, false, 1, + 1); // Eyes + DrawSpriteTile((x * 16) - 4, (y * 16), 13, 20, 8, false, false, 1, + 1); // Eyes + } else if (id_ == 0x19) // Poe - ghost + { + DrawSpriteTile((x * 16), (y * 16), 6, 31, 2); // + } else if (id_ == 0x1A) // Smith + { + // DrawSpriteTile((x*16), (y *16), 2, 4, 10,true); // Smitty + // DrawSpriteTile((x*16)+12, (y *16) - 7, 0, 6, 10); // Hammer + DrawSpriteTile((x * 16), (y * 16), 4, 22, 10); + } else if (id_ == 0x1C) // Statue + { + DrawSpriteTile((x * 16), (y * 16) + 8, 0, 28, 15); + DrawSpriteTile((x * 16), (y * 16), 2, 28, 15, false, false, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16), 2, 28, 15, true, false, 1, 1); + } else if (id_ == 0x1E) // Crystal switch + { + DrawSpriteTile((x * 16), (y * 16), 4, 30, 5); + } else if (id_ == 0x1F) // Sick kid + { + DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 10, 16, 14); + DrawSpriteTile((x * 16) + 16 - 8, (y * 16) + 8, 10, 16, 14, true); + DrawSpriteTile((x * 16) - 8, (y * 16) + 16, 10, 16, 14, false, true, 2, 2); + DrawSpriteTile((x * 16) + 16 - 8, (y * 16) + 16, 10, 16, 14, true, true, 2, + 2); + DrawSpriteTile((x * 16), (y * 16) - 4, 14, 16, 10); + } else if (id_ == 0x20) { + DrawSpriteTile((x * 16), (y * 16), 2, 24, 7); + } else if (id_ == 0x21) // Push switch + { + DrawSpriteTile((x * 16) + 4, (y * 16) + 20, 13, 29, 3, false, false, 1, 1); + DrawSpriteTile((x * 16) + 4, (y * 16) + 28, 12, 29, 3, false, false, 1, 1); + DrawSpriteTile((x * 16), (y * 16) + 8, 10, 28, 3); + } else if (id_ == 0x22) // Rope + { + DrawSpriteTile((x * 16), (y * 16), 8, 26, 5); + } else if (id_ == 0x23) // Red bari + { + DrawSpriteTile((x * 16), (y * 16), 2, 18, 4, false, false, 1, 2); + DrawSpriteTile((x * 16) + 8, (y * 16), 2, 18, 4, true, false, 1, 2); + } else if (id_ == 0x24) // Blue bari + { + DrawSpriteTile((x * 16), (y * 16), 2, 18, 6, false, false, 1, 2); + DrawSpriteTile((x * 16) + 8, (y * 16), 2, 18, 6, true, false, 1, 2); + } else if (id_ == 0x25) // Talking tree? + { + // TODO: Add something here? + } else if (id_ == 0x26) // Hardhat beetle + { + if ((x & 0x01) == 0x00) { + DrawSpriteTile((x * 16), (y * 16), 4, 20, 8); + DrawSpriteTile((x * 16), (y * 16) - 6, 0, 20, 8); + } else { + DrawSpriteTile((x * 16), (y * 16), 4, 20, 10); + DrawSpriteTile((x * 16), (y * 16) - 6, 0, 20, 10); + } + } else if (id_ == 0x27) // Deadrock + { + DrawSpriteTile((x * 16), (y * 16), 2, 30, 10); + } else if (id_ == 0x28) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x29) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x2A) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x2B) // ??? + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x2C) // Lumberjack + { + DrawSpriteTile((x * 16) - 24, (y * 16) + 12, 6, 26, 12, true); // Body + DrawSpriteTile((x * 16) - 24, (y * 16), 8, 26, 12, true); // Head + + DrawSpriteTile((x * 16) - 14, (y * 16) + 12, 14, 27, 10, false, false, 1, + 1); // Saw left edge + DrawSpriteTile((x * 16) - 6, (y * 16) + 12, 15, 27, 10, false, false, 1, + 1); // Saw left edge + DrawSpriteTile((x * 16) + 2, (y * 16) + 12, 15, 27, 10, false, false, 1, + 1); // Saw left edge + DrawSpriteTile((x * 16) + 10, (y * 16) + 12, 15, 27, 10, false, false, 1, + 1); // Saw left edge + DrawSpriteTile((x * 16) + 18, (y * 16) + 12, 15, 27, 10, false, false, 1, + 1); // Saw left edge + DrawSpriteTile((x * 16) + 26, (y * 16) + 12, 15, 27, 10, false, false, 1, + 1); // Saw left edge + DrawSpriteTile((x * 16) + 34, (y * 16) + 12, 14, 27, 10, true, false, 1, + 1); // Saw left edge + + DrawSpriteTile((x * 16) + 40, (y * 16) + 12, 4, 26, 12); // Body + DrawSpriteTile((x * 16) + 40, (y * 16), 8, 26, 12); // Head + } else if (id_ == 0x2D) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x2E) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x2F) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x30) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x31) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x32) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } + /* +else if (id_== 0x33) // Pull for rupees +{ + +} +*/ + else if (id_ == 0x34) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x35) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x36) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } + /* +else if (id_== 0x37) // Waterfall +{ +DrawSpriteTile((x*16), (y *16), 14, 6, 10); +} +*/ + else if (id_ == 0x38) // Arrowtarget + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x39) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x3A) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x3B) // Dash item + { + } else if (id_ == 0x3C) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x3D) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x3E) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x3F) // Npcs + { + DrawSpriteTile((x * 16), (y * 16), 14, 22, 10); + } else if (id_ == 0x40) // Lightning lock (agah tower) + { + DrawSpriteTile((x * 16) - 24, (y * 16), 10, 28, 2, false, false, 1, 2); + DrawSpriteTile((x * 16) - 16, (y * 16), 6, 30, 2); + DrawSpriteTile((x * 16), (y * 16), 8, 30, 2); + DrawSpriteTile((x * 16) + 16, (y * 16), 6, 30, 2); + DrawSpriteTile((x * 16) + 24, (y * 16), 10, 28, 2, false, false, 1, 2); + } else if (id_ == 0x41) // Blue soldier + { + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 10, true, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 20, 10); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 10, false, false, 1, + 2); // Shield + DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 14, 22, 10, false, true, 1, + 2); // Sword + } else if (id_ == 0x42) // Green soldier + { + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 12); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 12, true, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 20, 12); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 12, false, false, 1, + 2); // Shield + DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 14, 22, 12, false, true, 1, + 2); // Sword + } else if (id_ == 0x43) // Red spear soldier + { + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 8, true, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 20, 8); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 8, false, false, 1, + 2); // Shield + DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 11, 22, 8, false, true, 1, + 2); // Spear + } else if (id_ == 0x44) // Sword blue holding up + { + DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 10); + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); // Head + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 14, 22, 10, false, true, 1, + 2); // Sword + } else if (id_ == 0x45) // Green spear soldier + { + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 12); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 12, true, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 20, 12); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 13, 22, 12, false, false, 1, + 2); // Shield + DrawSpriteTile((x * 16) - 4, (y * 16) + 16, 11, 22, 12, false, true, 1, + 2); // Spear + } else if (id_ == 0x46) // Blue archer + { + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 10); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 6, 20, 10, true, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 20, 10); // Head + DrawSpriteTile((x * 16), (y * 16) + 16, 10, 16, 10, false, false, 1, + 1); // Bow1 + DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 10, 16, 10, true, false, 1, + 1); // Bow2 + } else if (id_ == 0x47) // Green archer + { + DrawSpriteTile((x * 16), (y * 16) + 8, 14, 16, 12); + DrawSpriteTile((x * 16), (y * 16), 0, 20, 12); + DrawSpriteTile((x * 16), (y * 16) + 16, 10, 16, 12, false, false, 1, + 1); // Bow1 + DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 10, 16, 12, true, false, 1, + 1); // Bow2 + } else if (id_ == 0x48) // Javelin soldier red + { + DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8); + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 8); // Head + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 11, 22, 8, false, true, 1, + 2); // Sword + } else if (id_ == 0x49) // Javelin soldier red from bush + { + DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8); + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 18, 8); // Head + DrawSpriteTile((x * 16), (y * 16) + 24, 0, 20, 2); + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 11, 22, 8, false, true, 1, + 2); // Sword + } else if (id_ == 0x4A) // Red bomb soldier + { + DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 8); + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 8, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 8); // Head + DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 14, 22, 11); // Bomb + } else if (id_ == 0x4B) // Green soldier recruit + { + // 0,4 + DrawSpriteTile((x * 16), (y * 16), 6, 24, 12); + DrawSpriteTile((x * 16), (y * 16) - 10, 0, 20, 12); + } else if (id_ == 0x4C) // Jazzhand + { + DrawSpriteTile((x * 16), (y * 16), 0, 26, 14, false, false, 6, 2); + } else if (id_ == 0x4D) // Rabit?? + { + DrawSpriteTile((x * 16), (y * 16), 0, 26, 12, false, false, 6, 2); + } else if (id_ == 0x4E) // Popo1 + { + DrawSpriteTile((x * 16), (y * 16), 0, 20, 10); + } else if (id_ == 0x4F) // Popo2 + { + DrawSpriteTile((x * 16), (y * 16), 2, 20, 10); + } else if (id_ == 0x50) // Canon ball + { + DrawSpriteTile((x * 16), (y * 16), 0, 24, 10); + } else if (id_ == 0x51) // Armos + { + DrawSpriteTile((x * 16), (y * 16), 0, 28, 11, false, false, 2, 4); + } else if (id_ == 0x53) // Armos Knight + { + DrawSpriteTile((x * 16), (y * 16), 0, 28, 10, false, false, 4, 4); + } else if (id_ == 0x54) { + DrawSpriteTile((x * 16), (y * 16), 2, 28, 12); + DrawSpriteTile((x * 16) + 8, (y * 16) + 10, 6, 28, 12); + DrawSpriteTile((x * 16) + 16, (y * 16) + 18, 10, 28, 12); + } else if (id_ == 0x55) // Fireball Zora + { + DrawSpriteTile((x * 16), (y * 16), 4, 26, 11); + } else if (id_ == 0x56) // Zora + { + DrawSpriteTile((x * 16), (y * 16), 10, 20, 2); + DrawSpriteTile((x * 16), (y * 16) + 8, 8, 30, 2); + } else if (id_ == 0x57) // Desert Rocks + { + DrawSpriteTile((x * 16), (y * 16), 14, 24, 2, false, false, 2, 4); + DrawSpriteTile((x * 16) + 16, (y * 16), 14, 24, 2, true, false, 2, 4); + } else if (id_ == 0x58) // Crab + { + DrawSpriteTile((x * 16), (y * 16), 14, 24, 12); + DrawSpriteTile((x * 16) + 16, (y * 16), 14, 24, 12, true); + } else if (id_ == 0x5B) // Spark + { + DrawSpriteTile((x * 16), (y * 16), 8, 18, 4); + } else if (id_ == 0x5C) // Spark + { + DrawSpriteTile((x * 16), (y * 16), 8, 18, 4, true); + } else if (id_ == 0x5D) // Roller vertical1 + { + // Subset3 + if (((y * 16) & 0x10) == 0x10) { + DrawSpriteTile((x * 16), (y * 16), 8, 24, 11); + + for (int i = 0; i < 7; i++) { + DrawSpriteTile((x * 16) + 8 + (i * 16), (y * 16), 9, 24, 11); + } + + DrawSpriteTile((x * 16) + (16 * 7), (y * 16), 8, 24, 11, true); + } else { + DrawSpriteTile((x * 16), (y * 16), 8, 24, 11); + DrawSpriteTile((x * 16) + 16, (y * 16), 9, 24, 11); + DrawSpriteTile((x * 16) + 32, (y * 16), 9, 24, 11); + DrawSpriteTile((x * 16) + 48, (y * 16), 8, 24, 11, true); + } + + } else if (id_ == 0x5E) // Roller vertical2 + { + // Subset3 + if (((y * 16) & 0x10) == 0x10) { + DrawSpriteTile((x * 16), (y * 16), 8, 24, 11); + + for (int i = 0; i < 7; i++) { + DrawSpriteTile((x * 16) + 8 + (i * 16), (y * 16), 9, 24, 11); + } + + DrawSpriteTile((x * 16) + (16 * 7), (y * 16), 8, 24, 11, true); + } else { + DrawSpriteTile((x * 16), (y * 16), 8, 24, 11); + DrawSpriteTile((x * 16) + 16, (y * 16), 9, 24, 11); + DrawSpriteTile((x * 16) + 32, (y * 16), 9, 24, 11); + DrawSpriteTile((x * 16) + 48, (y * 16), 8, 24, 11, true); + } + } else if (id_ == 0x5F) // Roller horizontal + { + if (((x * 16) & 0x10) == 0x10) { + DrawSpriteTile((x * 16), (y * 16), 14, 24, 11); + DrawSpriteTile((x * 16), (y * 16) + 16, 14, 25, 11); + DrawSpriteTile((x * 16), (y * 16) + 32, 14, 25, 11); + DrawSpriteTile((x * 16), (y * 16) + 48, 14, 24, 11, false, true); + } else { + for (int i = 0; i < 7; i++) { + DrawSpriteTile((x * 16), (y * 16) + i * 16, 14, 25, 11); + } + + DrawSpriteTile((x * 16), (y * 16), 14, 24, 11); + DrawSpriteTile((x * 16), (y * 16) + (7 * 16), 14, 24, 11, false, true); + } + } else if (id_ == 0x60) // Roller horizontal2 (right to left) + { + // Subset3 + if (((x * 16) & 0x10) == 0x10) { + DrawSpriteTile((x * 16), (y * 16), 14, 24, 11); + DrawSpriteTile((x * 16), (y * 16) + 16, 14, 25, 11); + DrawSpriteTile((x * 16), (y * 16) + 32, 14, 25, 11); + DrawSpriteTile((x * 16), (y * 16) + 48, 14, 24, 11, false, true); + } else { + for (int i = 0; i < 7; i++) { + DrawSpriteTile((x * 16), (y * 16) + i * 16, 14, 25, 11); + } + + DrawSpriteTile((x * 16), (y * 16), 14, 24, 11); + DrawSpriteTile((x * 16), (y * 16) + (7 * 16), 14, 24, 11, false, true); + } + + } else if (id_ == 0x61) // Beamos + { + DrawSpriteTile((x * 16), (y * 16) - 16, 8, 20, 14, false, false, 2, 4); + DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 10, 20, 14, false, false, 1, 1); + } else if (id_ == 0x63) // Devalant non-shooter + { + DrawSpriteTile((x * 16) - 8, (y * 16) - 8, 2, 16, 2); + DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 2, 16, 2, true); + DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 2, 16, 2, false, true); + DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 2, 16, 2, true, true); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); + } else if (id_ == 0x64) // Devalant non-shooter + { + DrawSpriteTile((x * 16) - 8, (y * 16) - 8, 2, 16, 2); + DrawSpriteTile((x * 16) + 8, (y * 16) - 8, 2, 16, 2, true); + DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 2, 16, 2, false, true); + DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 2, 16, 2, true, true); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 8); + } else if (id_ == 0x66) // Moving wall canon right + { + DrawSpriteTile((x * 16), (y * 16), 14, 16, 14, true); + } else if (id_ == 0x67) // Moving wall canon right + { + DrawSpriteTile((x * 16), (y * 16), 14, 16, 14); + } else if (id_ == 0x68) // Moving wall canon right + { + DrawSpriteTile((x * 16), (y * 16), 12, 16, 14); + } else if (id_ == 0x69) // Moving wall canon right + { + DrawSpriteTile((x * 16), (y * 16), 12, 16, 14, false, true); + } else if (id_ == 0x6A) // Chainball soldier + { + DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 14); + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 14, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 14); // Head + DrawSpriteTile((x * 16) + 12, (y * 16) - 16, 10, 18, 14); // Ball + } else if (id_ == 0x6B) // Cannon soldier + { + DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 6, 16, 14); + DrawSpriteTile((x * 16) - 4, (y * 16) + 8, 6, 20, 14, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 14); // Head + DrawSpriteTile((x * 16) + 12, (y * 16) + 8, 4, 18, 14); // Cannon + } else if (id_ == 0x6C) // Mirror portal + { + // Useless + } else if (id_ == 0x6D) // Rat + { + DrawSpriteTile((x * 16), (y * 16), 14, 24, 5); + } else if (id_ == 0x6E) // Rope + { + DrawSpriteTile((x * 16), (y * 16), 10, 26, 5); + } else if (id_ == 0x6F) { + DrawSpriteTile((x * 16), (y * 16), 4, 24, 10); + } else if (id_ == 0x70) // Helma fireball + { + DrawSpriteTile((x * 16), (y * 16), 10, 28, 4); + } else if (id_ == 0x71) // Leever + { + DrawSpriteTile((x * 16), (y * 16), 6, 16, 4); + } else if (id_ == 0x73) // Uncle priest + { + } else if (id_ == 0x79) // Bee + { + DrawSpriteTile((x * 16), (y * 16), 4, 14, 11, false, false, 1, 1); + } else if (id_ == 0x7A) { + DrawSpriteTile((x * 16), (y * 16) - 16, 2, 24, 12, false, false, 2, 4); + DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 2, 24, 12, true, false, 2, 4); + } else if (id_ == 0x7C) // Skull head + { + DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); + } else if (id_ == 0x7D) // Big spike + { + DrawSpriteTile((x * 16), (y * 16), 4, 28, 11); + DrawSpriteTile((x * 16) + 16, (y * 16), 4, 28, 11, true); + DrawSpriteTile((x * 16), (y * 16) + 16, 4, 28, 11, false, true); + DrawSpriteTile((x * 16) + 16, (y * 16) + 16, 4, 28, 11, true, true); + } else if (id_ == 0x7E) // Guruguru clockwise + { + DrawSpriteTile((x * 16), (y * 16) - 14, 8, 18, 4); + DrawSpriteTile((x * 16), (y * 16) - 28, 8, 18, 4); + DrawSpriteTile((x * 16), (y * 16) - 42, 8, 18, 4); + DrawSpriteTile((x * 16), (y * 16) - 56, 8, 18, 4); + } else if (id_ == 0x7F) // Guruguru Counterclockwise + { + DrawSpriteTile((x * 16), (y * 16) - 14, 8, 18, 4); + DrawSpriteTile((x * 16), (y * 16) - 28, 8, 18, 4); + DrawSpriteTile((x * 16), (y * 16) - 42, 8, 18, 4); + DrawSpriteTile((x * 16), (y * 16) - 56, 8, 18, 4); + } else if (id_ == 0x80) // Winder (moving firebar) + { + DrawSpriteTile((x * 16), (y * 16), 8, 18, 4); + DrawSpriteTile((x * 16) - 14, (y * 16), 8, 18, 4); + DrawSpriteTile((x * 16) - 28, (y * 16), 8, 18, 4); + DrawSpriteTile((x * 16) - 42, (y * 16), 8, 18, 4); + DrawSpriteTile((x * 16) - 56, (y * 16), 8, 18, 4); + } else if (id_ == 0x81) // Water tektite + { + DrawSpriteTile((x * 16), (y * 16), 0, 24, 11); + } else if (id_ == 0x82) // circle antifairy + { + // Antifairy top + DrawSpriteTile((x * 16 + 2) - 4, (y * 16 + 8) - 16, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 2) - 16, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 14) - 4, (y * 16 + 8) - 16, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 14) - 16, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 8) - 16, 1, 30, 5, false, false, + 1, 1); // Middle + // Left + DrawSpriteTile((x * 16 + 2) - 16, (y * 16 + 8) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 2) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 14) - 16, (y * 16 + 8) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 14) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 16, (y * 16 + 8) - 4, 1, 30, 5, false, false, + 1, 1); // Middle + + DrawSpriteTile((x * 16 + 2) - 4, (y * 16 + 8) + 8, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 2) + 8, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 14) - 4, (y * 16 + 8) + 8, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 14) + 8, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) - 4, (y * 16 + 8) + 8, 1, 30, 5, false, false, + 1, 1); // Middle + // Left + DrawSpriteTile((x * 16 + 2) + 8, (y * 16 + 8) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 2) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 14) + 8, (y * 16 + 8) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 14) - 4, 3, 30, 5, false, false, + 1, 1); + DrawSpriteTile((x * 16 + 8) + 8, (y * 16 + 8) - 4, 1, 30, 5, false, false, + 1, 1); // Middle + } else if (id_ == 0x83) // Green eyegore + { + DrawSpriteTile((x * 16), (y * 16), 12, 24, 14, false, false, 2, 3); + DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 14, true, false, 1, 3); + } else if (id_ == 0x84) // Red eyegore + { + DrawSpriteTile((x * 16), (y * 16), 12, 24, 8, false, false, 2, 3); + DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 8, true, false, 1, 3); + } else if (id_ == 0x85) // Yellow stalfos + { + DrawSpriteTile((x * 16), (y * 16), 10, 16, 11); + DrawSpriteTile((x * 16), (y * 16) - 12, 0, 16, 11); // Head + } else if (id_ == 0x86) // Kodongo + { + DrawSpriteTile((x * 16), (y * 16), 4, 26, 14); + } else if (id_ == 0x88) // Mothula + { + DrawSpriteTile((x * 16), (y * 16), 8, 24, 14, false, false, 2, 4); + DrawSpriteTile((x * 16) + 16, (y * 16), 8, 24, 14, true, false, 2, 4); + } else if (id_ == 0x8A) // Spike + { + DrawSpriteTile((x * 16), (y * 16), 6, 30, 15); + } else if (id_ == 0x8B) // Gibdo + { + DrawSpriteTile((x * 16), (y * 16), 10, 24, 14); + DrawSpriteTile((x * 16), (y * 16) - 8, 0, 24, 14); + } else if (id_ == 0x8C) // Arrghus + { + DrawSpriteTile((x * 16), (y * 16), 0, 24, 14, false, false, 2, 4); + DrawSpriteTile((x * 16) + 16, (y * 16), 0, 24, 14, true, false, 2, 4); + } else if (id_ == 0x8D) // Arrghus spawn + { + DrawSpriteTile((x * 16), (y * 16), 6, 24, 14); + } else if (id_ == 0x8E) // Terrorpin + { + DrawSpriteTile((x * 16), (y * 16), 14, 24, 12); + } else if (id_ == 0x8F) // Slime + { + DrawSpriteTile((x * 16), (y * 16), 0, 20, 12); + } else if (id_ == 0x90) // Wall master + { + DrawSpriteTile((x * 16), (y * 16), 6, 26, 12); + DrawSpriteTile((x * 16) + 16, (y * 16), 15, 26, 12, false, false, 1, 1); + DrawSpriteTile((x * 16) + 16, (y * 16) + 8, 9, 26, 12, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16) + 16, 10, 27, 12, false, false, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16) + 16, 8, 27, 12, false, false, 1, 1); + } else if (id_ == 0x91) // Stalfos knight + { + DrawSpriteTile((x * 16) - 2, (y * 16) + 12, 4, 22, 12, false, false, 1, 2); + DrawSpriteTile((x * 16) + 10, (y * 16) + 12, 4, 22, 12, true, false, 1, 2); + DrawSpriteTile((x * 16) - 4, (y * 16) + 4, 1, 22, 12); + DrawSpriteTile((x * 16) + 12, (y * 16) + 4, 3, 22, 12, false, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16) - 8, 6, 20, 12); + } else if (id_ == 0x92) // Helmaking + { + DrawSpriteTile((x * 16), (y * 16) + 32, 14, 26, 14); + DrawSpriteTile((x * 16) + 16, (y * 16) + 32, 0, 28, 14); + DrawSpriteTile((x * 16) + 32, (y * 16) + 32, 14, 26, 14, true); + + DrawSpriteTile((x * 16), (y * 16) + 16 + 32, 2, 28, 14); + DrawSpriteTile((x * 16) + 16, (y * 16) + 16 + 32, 4, 28, 14); + DrawSpriteTile((x * 16) + 32, (y * 16) + 16 + 32, 2, 28, 14, true); + + DrawSpriteTile((x * 16) + 8, (y * 16) + 32 + 32, 6, 28, 14); + DrawSpriteTile((x * 16) + 24, (y * 16) + 32 + 32, 6, 28, 14, true); + } else if (id_ == 0x93) // Bumper + { + DrawSpriteTile((x * 16), (y * 16), 12, 30, 7); + DrawSpriteTile((x * 16) + 16, (y * 16), 12, 30, 7, true); + DrawSpriteTile((x * 16) + 16, (y * 16) + 16, 12, 30, 7, true, true); + DrawSpriteTile((x * 16), (y * 16) + 16, 12, 30, 7, false, true); + } else if (id_ == 0x95) // Right laser eye + { + DrawSpriteTile((x * 16), (y * 16), 9, 28, 3, true, false, 1, 2); + DrawSpriteTile((x * 16), (y * 16) + 16, 9, 28, 3, true, true, 1, 1); + } else if (id_ == 0x96) // Left laser eye + { + DrawSpriteTile((x * 16) + 8, (y * 16) - 4, 9, 28, 3, false, false, 1, 2); + DrawSpriteTile((x * 16) + 8, (y * 16) + 12, 9, 28, 3, false, true, 1, 1); + } else if (id_ == 0x97) // Right laser eye + { + DrawSpriteTile((x * 16), (y * 16), 6, 28, 3, false, false, 2, 1); + DrawSpriteTile((x * 16) + 16, (y * 16), 6, 28, 3, true, false, 1, 1); + } else if (id_ == 0x98) // Right laser eye + { + DrawSpriteTile((x * 16), (y * 16), 6, 28, 3, false, true, 2, 1); + DrawSpriteTile((x * 16) + 16, (y * 16), 6, 28, 3, true, true, 1, 1); + } else if (id_ == 0x99) { + DrawSpriteTile((x * 16), (y * 16), 6, 24, 12); + DrawSpriteTile((x * 16), (y * 16) - 8, 0, 24, 12); + } else if (id_ == 0x9A) // Water bubble kyameron + { + DrawSpriteTile((x * 16), (y * 16), 10, 24, 6); + } else if (id_ == 0x9B) // Water bubble kyameron + { + DrawSpriteTile((x * 16), (y * 16), 6, 24, 11); + DrawSpriteTile((x * 16), (y * 16) - 8, 2, 27, 11, false, false, 2, 1); + } else if (id_ == 0x9C) // Water bubble kyameron + { + DrawSpriteTile((x * 16), (y * 16), 12, 22, 11); + DrawSpriteTile((x * 16) + 16, (y * 16), 13, 22, 11, false, false, 1, 2); + } else if (id_ == 0x9D) // Water bubble kyameron + { + DrawSpriteTile((x * 16), (y * 16), 14, 21, 11); + DrawSpriteTile((x * 16), (y * 16) - 16, 14, 20, 11, false, false, 2, 1); + } else if (id_ == 0xA1) { + DrawSpriteTile((x * 16) - 8, (y * 16) + 8, 6, 26, 14); + DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 6, 26, 14, true); + } else if (id_ == 0xA2) { + DrawSpriteTile((x * 16), (y * 16) + 8, 0, 24, 14, false, false, 4, 4); + } else if (id_ == 0xA5) { + DrawSpriteTile((x * 16), (y * 16), 0, 26, 10, false, false, 3, 2); + DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 0, 24, 10); + } else if (id_ == 0xA6) { + DrawSpriteTile((x * 16), (y * 16), 0, 26, 8, false, false, 3, 2); + DrawSpriteTile((x * 16) + 4, (y * 16) - 8, 0, 24, 8); + } else if (id_ == 0xA7) { + DrawSpriteTile((x * 16), (y * 16) + 12, 12, 16, 10); + DrawSpriteTile((x * 16), (y * 16), 0, 16, 10); + } else if (id_ == 0xAC) { + DrawSpriteTile((x * 16), (y * 16), 5, 14, 4); + } else if (id_ == 0xAD) { + DrawSpriteTile((x * 16), (y * 16) + 8, 14, 10, 10); + DrawSpriteTile((x * 16), (y * 16), 12, 10, 10); + } else if (id_ == 0xBA) { + DrawSpriteTile((x * 16), (y * 16), 14, 14, 6); + } else if (id_ == 0xC1) { + DrawSpriteTile((x * 16), (y * 16) - 16, 2, 24, 12, false, false, 2, 4); + DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 2, 24, 12, true, false, 2, 4); + } else if (id_ == 0xC3) { + DrawSpriteTile((x * 16), (y * 16), 10, 14, 12); + } else if (id_ == 0xC4) { + DrawSpriteTile((x * 16), (y * 16), 0, 18, 14); + DrawSpriteTile((x * 16), (y * 16) - 8, 0, 16, 14); + } else if (id_ == 0xC5) { + } else if (id_ == 0xC6) { + DrawSpriteTile((x * 16) + 4, (y * 16) + 14, 3, 30, 14, false, false, 1, 1); + DrawSpriteTile((x * 16) + 14, (y * 16) + 4, 3, 30, 14, false, false, 1, 1); + DrawSpriteTile((x * 16) + 4, (y * 16) + 2, 1, 31, 14, false, false, 1, 1); + DrawSpriteTile((x * 16) - 6, (y * 16) + 4, 3, 30, 14, false, false, 1, 1); + DrawSpriteTile((x * 16) + 4, (y * 16) - 6, 3, 30, 14, false, false, 1, 1); + } else if (id_ == 0xC7) { + DrawSpriteTile((x * 16), (y * 16), 0, 26, 4); + DrawSpriteTile((x * 16), (y * 16) - 10, 0, 26, 4); + DrawSpriteTile((x * 16), (y * 16) - 20, 0, 26, 4); + DrawSpriteTile((x * 16), (y * 16) - 30, 2, 26, 4); + } else if (id_ == 0xC8) { + DrawSpriteTile((x * 16), (y * 16), 12, 24, 12, false, false, 2, 3); + DrawSpriteTile((x * 16) + 16, (y * 16), 12, 24, 12, true, false, 1, 3); + } else if (id_ == 0xC9) { + DrawSpriteTile((x * 16), (y * 16), 8, 28, 8, false); + DrawSpriteTile((x * 16) + 16, (y * 16), 8, 28, 8, true); + } else if (id_ == 0xCA) { + DrawSpriteTile((x * 16), (y * 16), 8, 10, 10); + } else if (id_ == 0xD0) { + DrawSpriteTile((x * 16), (y * 16), 7, 14, 11, false, false, 3, 2); + DrawSpriteTile((x * 16), (y * 16) - 10, 8, 12, 11); + } else if (id_ == 0xD1) { + DrawSpriteTile((x * 16) + 2, (y * 16) + 8, 7, 13, 11, true, true, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16) + 2, 7, 13, 11, true, false, 1, 1); + DrawSpriteTile((x * 16) + 14, (y * 16) + 8, 7, 13, 11, true, true, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16) + 14, 7, 13, 11, false, true, 1, 1); + DrawSpriteTile((x * 16) + 8, (y * 16) + 8, 7, 13, 11, false, false, 1, + 1); // Middle + // 6,7 / 13 + } else if (id_ == 0xD4) { + DrawSpriteTile((x * 16) - 4, (y * 16), 0, 7, 7, false, false, 1, 1); + DrawSpriteTile((x * 16) + 4, (y * 16), 0, 7, 7, true, false, 1, 1); + } else if (id_ == 0xE3) // Fairy + { + DrawSpriteTile((x * 16), (y * 16), 10, 14, 10); + } else if (id_ == 0xE4) // Key + { + DrawSpriteTile((x * 16), (y * 16), 11, 06, 11, false, false, 1, 2); + } else if (id_ == 0xE7) // Mushroom + { + DrawSpriteTile((x * 16), (y * 16), 14, 30, 16); + } else if (id_ == 0xE8) // Fake ms + { + DrawSpriteTile((x * 16) + 4, (y * 16), 4, 31, 10, false, false, 1, 1); + DrawSpriteTile((x * 16) + 4, (y * 16) + 8, 5, 31, 10, false, false, 1, 1); + } else if (id_ == 0xEB) { + DrawSpriteTile((x * 16), (y * 16), 0, 14, 5); + } else if (id_ == 0xF2) { + DrawSpriteTile((x * 16), (y * 16) - 16, 12, 24, 2, false, false, 2, 4); + DrawSpriteTile((x * 16) + 16, (y * 16) - 16, 12, 24, 2, true, false, 2, 4); + } else if (id_ == 0xF4) { + DrawSpriteTile((x * 16), (y * 16), 12, 28, 5, false, false, 4, 4); + } else { + // stringtodraw.Add(new SpriteName(x, (y *16), sprites_name.name[id])); + DrawSpriteTile((x * 16), (y * 16), 4, 4, 5); + } + + bounding_box_.x = (lowerX_ + (x * 16)); + bounding_box_.y = (lowerY_ + (y * 16)); + bounding_box_.w = width_; + bounding_box_.h = height_; +} + +void Sprite::DrawSpriteTile(int x, int y, int srcx, int srcy, int pal, + bool mirror_x, bool mirror_y, int sizex, int sizey, + bool iskey) { + x += 16; + y += 16; + int drawid_ = (srcx + (srcy * 16)) + 512; + for (auto yl = 0; yl < sizey * 8; yl++) { + for (auto xl = 0; xl < (sizex * 8) / 2; xl++) { + int mx = xl; + int my = yl; + + if (mirror_x) { + mx = (((sizex * 8) / 2) - 1) - xl; + } + if (mirror_y) { + my = (((sizey * 8)) - 1) - yl; + } + + // Formula information to get tile index position in the array + //((ID / nbrofXtiles) * (imgwidth/2) + (ID - ((ID/16)*16) )) + + int tx = ((drawid_ / 0x10) * 0x400) + + ((drawid_ - ((drawid_ / 0x10) * 0x10)) * 8); + auto pixel = current_gfx_[tx + (yl * 0x80) + xl]; + // nx,ny = object position, xx,yy = tile position, xl,yl = pixel + // position + int index = (x) + (y * 64) + (mx + (my * 0x80)); + + if (index >= 0 && index <= 4096) { + preview_gfx_[index] = (uchar)((pixel & 0x0F) + 112 + (pal * 8)); + } + } + } +} + +} // namespace zelda3 +} // namespace app +} // namespace yaze diff --git a/src/app/zelda3/sprite.h b/src/app/zelda3/sprite.h new file mode 100644 index 00000000..aeb3308e --- /dev/null +++ b/src/app/zelda3/sprite.h @@ -0,0 +1,68 @@ +#ifndef YAZE_APP_ZELDA3_SPRITE_H +#define YAZE_APP_ZELDA3_SPRITE_H + +#include + +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "app/core/constants.h" +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_tile.h" +#include "app/rom.h" + +namespace yaze { +namespace app { +namespace zelda3 { + +class Sprite { + public: + uchar x_, y_, id_; + uchar nx_, ny_; + uchar layer_ = 0; + uchar subtype_ = 0; + uchar overlord_ = 0; + std::string name_; + uchar keyDrop_ = 0; + int sizeMap_ = 512; + bool overworld_ = false; + bool preview_ = false; + uchar map_id_ = 0; + int map_x_ = 0; + int map_y_ = 0; + short room_id_ = 0; + bool picker_ = false; + bool selected_ = false; + SDL_Rect bounding_box_; + + Bytes current_gfx_; + Bytes preview_gfx_; + + int lowerX_ = 32; + int lowerY_ = 32; + int higherX_ = 0; + int higherY_ = 0; + int width_ = 16; + int height_ = 16; + + Sprite(Bytes src, uchar mapid, uchar id, uchar x, uchar y, int map_x, + int map_y); + void updateBBox(); + + void Draw(bool picker = false); + + void DrawSpriteTile(int x, int y, int srcx, int srcy, int pal, + bool mirror_x = false, bool mirror_y = false, + int sizex = 2, int sizey = 2, bool iskey = false); + + auto PreviewGraphics() { return preview_gfx_; } +}; + +} // namespace zelda3 +} // namespace app +} // namespace yaze + +#endif \ No newline at end of file diff --git a/src/app/zelda3/screen.cc b/src/app/zelda3/title_screen.cc similarity index 85% rename from src/app/zelda3/screen.cc rename to src/app/zelda3/title_screen.cc index 2f408835..7553ca77 100644 --- a/src/app/zelda3/screen.cc +++ b/src/app/zelda3/title_screen.cc @@ -1,4 +1,4 @@ -#include "screen.h" +#include "title_screen.h" #include @@ -11,7 +11,7 @@ namespace yaze { namespace app { namespace zelda3 { -void Screen::Create() { +void TitleScreen::Create() { tiles8Bitmap.Create(128, 512, 8, 0x20000); tilesBG1Bitmap.Create(256, 256, 8, 0x80000); tilesBG2Bitmap.Create(256, 256, 8, 0x80000); @@ -20,12 +20,9 @@ void Screen::Create() { BuildTileset(); LoadTitleScreen(); - LoadOverworldMap(); - LoadDungeonMaps(); - LoadAllMapIcons(); } -void Screen::BuildTileset() { +void TitleScreen::BuildTileset() { uchar staticgfx[16]; // Main Blocksets @@ -66,7 +63,7 @@ void Screen::BuildTileset() { } } -void Screen::LoadTitleScreen() { +void TitleScreen::LoadTitleScreen() { int pos = (rom_[0x138C + 3] << 16) + (rom_[0x1383 + 3] << 8) + rom_[0x137A + 3]; @@ -127,14 +124,6 @@ void Screen::LoadTitleScreen() { pal_selected_ = 2; } -void Screen::LoadNamingScreen() {} - -void Screen::LoadOverworldMap() {} - -void Screen::LoadDungeonMaps() {} - -void Screen::LoadAllMapIcons() {} - } // namespace zelda3 } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/zelda3/screen.h b/src/app/zelda3/title_screen.h similarity index 94% rename from src/app/zelda3/screen.h rename to src/app/zelda3/title_screen.h index a8d92a0d..4cade272 100644 --- a/src/app/zelda3/screen.h +++ b/src/app/zelda3/title_screen.h @@ -12,17 +12,13 @@ namespace yaze { namespace app { namespace zelda3 { -class Screen { +class TitleScreen { public: void Create(); private: void BuildTileset(); void LoadTitleScreen(); - void LoadNamingScreen(); - void LoadOverworldMap(); - void LoadDungeonMaps(); - void LoadAllMapIcons(); int sword_x_ = 0; int mx_click_ = 0; diff --git a/src/gui/canvas.cc b/src/gui/canvas.cc index eaf7f7c5..e97f2a25 100644 --- a/src/gui/canvas.cc +++ b/src/gui/canvas.cc @@ -96,12 +96,14 @@ void Canvas::DrawTilesFromUser(app::ROM &rom, Bytes &tile, } } -void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset) { - draw_list_->AddImage( - (void *)bitmap.GetTexture(), - ImVec2(canvas_p0_.x + border_offset, canvas_p0_.y + border_offset), - ImVec2(canvas_p0_.x + (bitmap.GetWidth() * 2), - canvas_p0_.y + (bitmap.GetHeight() * 2))); +void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, bool ready) { + if (ready) { + draw_list_->AddImage( + (void *)bitmap.GetTexture(), + ImVec2(canvas_p0_.x + border_offset, canvas_p0_.y + border_offset), + ImVec2(canvas_p0_.x + (bitmap.GetWidth() * 2), + canvas_p0_.y + (bitmap.GetHeight() * 2))); + } } void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset) { @@ -121,6 +123,15 @@ void Canvas::DrawOutline(int x, int y, int w, int h) { draw_list_->AddRect(origin, size, IM_COL32(255, 255, 255, 255)); } +void Canvas::DrawRect(int x, int y, int w, int h, ImVec4 color) { + ImVec2 origin(canvas_p0_.x + scrolling_.x + x, + canvas_p0_.y + scrolling_.y + y); + ImVec2 size(canvas_p0_.x + scrolling_.x + x + w, + canvas_p0_.y + scrolling_.y + y + h); + draw_list_->AddRectFilled(origin, size, + IM_COL32(color.x, color.y, color.z, color.w)); +} + void Canvas::DrawText(std::string text, int x, int y) { draw_list_->AddText( ImVec2(canvas_p0_.x + scrolling_.x + x, canvas_p0_.y + scrolling_.y + y), diff --git a/src/gui/canvas.h b/src/gui/canvas.h index 341cab0f..d7be46b6 100644 --- a/src/gui/canvas.h +++ b/src/gui/canvas.h @@ -24,9 +24,11 @@ class Canvas { void DrawContextMenu(); void DrawTilesFromUser(app::ROM& rom, Bytes& tile, app::gfx::SNESPalette& pal); - void DrawBitmap(const Bitmap& bitmap, int border_offset = 0); + void DrawBitmap(const Bitmap& bitmap, int border_offset = 0, + bool ready = true); void DrawBitmap(const Bitmap& bitmap, int x_offset, int y_offset); void DrawOutline(int x, int y, int w, int h); + void DrawRect(int x, int y, int w, int h, ImVec4 color); void DrawText(std::string text, int x, int y); void DrawGrid(float grid_step = 64.0f); void DrawOverlay(); // last From 67a5f6bf68de0e232c9fbc8c33495dfb36de073a Mon Sep 17 00:00:00 2001 From: Justin Scofield <47263509+scawful@users.noreply.github.com> Date: Tue, 13 Sep 2022 00:24:24 -0500 Subject: [PATCH 15/16] housekeeping and inventory --- src/app/editor/screen_editor.cc | 2 +- src/app/rom.cc | 201 ++++++++++++++++++-------------- src/app/rom.h | 4 + src/app/zelda3/inventory.cc | 51 ++++---- src/app/zelda3/inventory.h | 7 +- 5 files changed, 144 insertions(+), 121 deletions(-) diff --git a/src/app/editor/screen_editor.cc b/src/app/editor/screen_editor.cc index 793d660c..34505b2c 100644 --- a/src/app/editor/screen_editor.cc +++ b/src/app/editor/screen_editor.cc @@ -86,7 +86,7 @@ void ScreenEditor::DrawInventoryMenuEditor() { tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, 192 * 2 + 2)); tilesheet_canvas_.DrawContextMenu(); tilesheet_canvas_.DrawBitmap(inventory_.Tilesheet(), 2, create); - tilesheet_canvas_.DrawGrid(); + tilesheet_canvas_.DrawGrid(16.0f); tilesheet_canvas_.DrawOverlay(); ImGui::EndTable(); diff --git a/src/app/rom.cc b/src/app/rom.cc index cf8561b4..067add26 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -20,67 +20,10 @@ #include "app/core/constants.h" #include "app/gfx/bitmap.h" -#define COMPRESSION_STRING_MOD 7 << 5 - namespace yaze { namespace app { -namespace { - -int GetGraphicsAddress(const uchar* data, uint8_t offset) { - auto part_one = data[kOverworldGraphicsPos1 + offset] << 16; - auto part_two = data[kOverworldGraphicsPos2 + offset] << 8; - auto part_three = data[kOverworldGraphicsPos3 + offset]; - auto snes_addr = (part_one | part_two | part_three); - return core::SnesToPc(snes_addr); -} - -Bytes SNES3bppTo8bppSheet(Bytes sheet, int bpp) { - Bytes sheet_buffer_out(0x1000); - int xx = 0; // positions where we are at on the sheet - int yy = 0; - int pos = 0; - int ypos = 0; - - if (bpp == 2) { - bpp = 16; - } else if (bpp == 3) { - bpp = 24; - } - - // for each tiles, 16 per line - for (int i = 0; i < 64; i++) { - // for each line - for (int y = 0; y < 8; y++) { - //[0] + [1] + [16] - for (int x = 0; x < 8; x++) { - auto b1 = ((sheet[(y * 2) + (bpp * pos)] & (kGraphicsBitmap[x]))); - auto b2 = (sheet[((y * 2) + (bpp * pos)) + 1] & (kGraphicsBitmap[x])); - auto b3 = (sheet[(16 + y) + (bpp * pos)] & (kGraphicsBitmap[x])); - unsigned char b = 0; - if (b1 != 0) { - b |= 1; - } - if (b2 != 0) { - b |= 2; - } - if (b3 != 0 && bpp != 16) { - b |= 4; - } - sheet_buffer_out[x + (xx) + (y * 128) + (yy * 1024)] = b; - } - } - pos++; - ypos++; - xx += 8; - if (ypos >= 16) { - yy++; - xx = 0; - ypos = 0; - } - } - return sheet_buffer_out; -} +namespace lc_lz2 { void PrintCompressionPiece(const std::shared_ptr& piece) { printf("Command: %d\n", piece->command); @@ -304,8 +247,7 @@ Bytes CreateCompressionString(std::shared_ptr& start, pos++; } else { if (piece->length <= kMaxLengthCompression) { - output.push_back((COMPRESSION_STRING_MOD) | - ((uchar)piece->command << 2) | + output.push_back(kCompressionStringMod | ((uchar)piece->command << 2) | (((piece->length - 1) & 0xFF00) >> 8)); pos++; printf("Building extended header : cmd: %d, length: %d - %02X\n", @@ -398,6 +340,68 @@ std::shared_ptr MergeCopy( return start; } +} // namespace lc_lz2 + +namespace { + +int GetGraphicsAddress(const uchar* data, uint8_t offset) { + auto part_one = data[kOverworldGraphicsPos1 + offset] << 16; + auto part_two = data[kOverworldGraphicsPos2 + offset] << 8; + auto part_three = data[kOverworldGraphicsPos3 + offset]; + auto snes_addr = (part_one | part_two | part_three); + return core::SnesToPc(snes_addr); +} + +Bytes SNES3bppTo8bppSheet(Bytes sheet, int bpp) { + int xx = 0; // positions where we are at on the sheet + int yy = 0; + int pos = 0; + int ypos = 0; + int num_tiles = 64; + int buffer_size = 0x1000; + if (bpp == 2) { + bpp = 16; + num_tiles = 128; + buffer_size = 0x2000; + } else if (bpp == 3) { + bpp = 24; + } + Bytes sheet_buffer_out(buffer_size); + + // for each tiles, 16 per line + for (int i = 0; i < num_tiles; i++) { + // for each line + for (int y = 0; y < 8; y++) { + //[0] + [1] + [16] + for (int x = 0; x < 8; x++) { + auto b1 = ((sheet[(y * 2) + (bpp * pos)] & (kGraphicsBitmap[x]))); + auto b2 = (sheet[((y * 2) + (bpp * pos)) + 1] & (kGraphicsBitmap[x])); + auto b3 = (sheet[(16 + y) + (bpp * pos)] & (kGraphicsBitmap[x])); + unsigned char b = 0; + if (b1 != 0) { + b |= 1; + } + if (b2 != 0) { + b |= 2; + } + if (b3 != 0 && bpp != 16) { + b |= 4; + } + sheet_buffer_out[x + (xx) + (y * 128) + (yy * 1024)] = b; + } + } + pos++; + ypos++; + xx += 8; + if (ypos >= 16) { + yy++; + xx = 0; + ypos = 0; + } + } + return sheet_buffer_out; +} + } // namespace // TODO TEST compressed data border for each cmd @@ -419,18 +423,19 @@ absl::StatusOr ROM::Compress(const int start, const int length, int mode, data_size_taken.fill({}); cmd_args.fill({{}}); - CheckByteRepeat(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, - last_pos); - CheckWordRepeat(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, - last_pos); - CheckIncByte(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, - last_pos); - CheckIntraCopy(rom_data_.data(), data_size_taken, cmd_args, src_data_pos, - last_pos, start); + lc_lz2::CheckByteRepeat(rom_data_.data(), data_size_taken, cmd_args, + src_data_pos, last_pos); + lc_lz2::CheckWordRepeat(rom_data_.data(), data_size_taken, cmd_args, + src_data_pos, last_pos); + lc_lz2::CheckIncByte(rom_data_.data(), data_size_taken, cmd_args, + src_data_pos, last_pos); + lc_lz2::CheckIntraCopy(rom_data_.data(), data_size_taken, cmd_args, + src_data_pos, last_pos, start); uint max_win = 2; uint cmd_with_max = kCommandDirectCopy; - ValidateForByteGain(data_size_taken, cmd_size, max_win, cmd_with_max); + lc_lz2::ValidateForByteGain(data_size_taken, cmd_size, max_win, + cmd_with_max); if (cmd_with_max == kCommandDirectCopy) { // This is the worst case scenario @@ -453,9 +458,9 @@ absl::StatusOr ROM::Compress(const int start, const int length, int mode, } } else { // Anything is better than directly copying bytes... - CompressionCommandAlternative(rom_data_.data(), compressed_chain, - cmd_size, cmd_args, src_data_pos, - comp_accumulator, cmd_with_max, max_win); + lc_lz2::CompressionCommandAlternative( + rom_data_.data(), compressed_chain, cmd_size, cmd_args, src_data_pos, + comp_accumulator, cmd_with_max, max_win); } if (src_data_pos > last_pos) { @@ -464,14 +469,15 @@ absl::StatusOr ROM::Compress(const int start, const int length, int mode, } if (check) { - RETURN_IF_ERROR(ValidateCompressionResult(compressed_chain_start, mode, - start, src_data_pos)) + RETURN_IF_ERROR(lc_lz2::ValidateCompressionResult( + compressed_chain_start, mode, start, src_data_pos)) } } - MergeCopy(compressed_chain_start->next); // Skipping compression chain header - PrintCompressionChain(compressed_chain_start); - return CreateCompressionString(compressed_chain_start->next, mode); + lc_lz2::MergeCopy( + compressed_chain_start->next); // Skipping compression chain header + lc_lz2::PrintCompressionChain(compressed_chain_start); + return lc_lz2::CreateCompressionString(compressed_chain_start->next, mode); } absl::StatusOr ROM::CompressGraphics(const int pos, const int length) { @@ -544,8 +550,8 @@ absl::StatusOr ROM::Decompress(int offset, int size, int mode) { ((rom_data_[offset] & kSnesByteMax) << 8); if (addr > offset) { return absl::InternalError(absl::StrFormat( - "DecompressOverworld: Offset for command copy exceeds " - "current position (Offset : %#04x | Pos : %#06x)\n", + "Decompress: Offset for command copy exceeds current position " + "(Offset : %#04x | Pos : %#06x)\n", addr, offset)); } @@ -569,8 +575,7 @@ absl::StatusOr ROM::Decompress(int offset, int size, int mode) { } break; default: { std::cout << absl::StrFormat( - "DecompressGraphics: Invalid command in header (Offset : %#06x, " - "Command: %#04x)\n", + "Decompress: Invalid header (Offset : %#06x, Command: %#04x)\n", offset, command); } break; } @@ -589,6 +594,21 @@ absl::StatusOr ROM::DecompressOverworld(int pos, int size) { return Decompress(pos, size, kNintendoMode1); } +absl::StatusOr ROM::Load2bppGraphics() { + Bytes sheet; + const uint8_t sheets[] = {113, 114, 218, 219, 220, 221}; + + for (int i = 0; i < 6; i++) { + auto offset = GetGraphicsAddress(rom_data_.data(), sheets[i]); + ASSIGN_OR_RETURN(auto decomp_sheet, Decompress(offset)) + auto converted_sheet = SNES3bppTo8bppSheet(decomp_sheet, 2); + for (int j = 0; j < converted_sheet.size(); ++j) { + sheet.push_back(converted_sheet.at(j)); + } + } + return sheet; +} + // 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 chars // 113-114 -> compressed 2bpp -> (decompressed each) 0x800 chars // 115-126 -> uncompressed 3bpp sprites -> (each) 0x600 chars @@ -607,8 +627,8 @@ absl::Status ROM::LoadAllGraphicsData() { } bpp3 = true; } else if (i == 113 || i == 114 || i >= 218) { - auto offset = GetGraphicsAddress(rom_data_.data(), i); - ASSIGN_OR_RETURN(sheet, Decompress(offset, 0x800)) + // auto offset = GetGraphicsAddress(rom_data_.data(), i); + // ASSIGN_OR_RETURN(sheet, Decompress(offset)) bpp3 = false; } else { auto offset = GetGraphicsAddress(rom_data_.data(), i); @@ -627,14 +647,15 @@ absl::Status ROM::LoadAllGraphicsData() { graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } else { - auto converted_sheet = SNES3bppTo8bppSheet(sheet, 2); - graphics_bin_[i] = - gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, converted_sheet.data(), 0x1000); - graphics_bin_.at(i).CreateTexture(renderer_); + // auto converted_sheet = SNES3bppTo8bppSheet(sheet, 2); + // graphics_bin_[i] = + // gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, + // core::kTilesheetDepth, converted_sheet.data(), 0x1000); + // graphics_bin_.at(i).CreateTexture(renderer_); - for (int j = 0; j < graphics_bin_.at(i).GetSize(); ++j) { - graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); + for (int j = 0; j < graphics_bin_.at(0).GetSize(); ++j) { + graphics_buffer_.push_back(0xFF); + // graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } } diff --git a/src/app/rom.h b/src/app/rom.h index 5f2b79ba..a8beaec6 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -17,6 +17,7 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.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/gfx/bitmap.h" @@ -47,6 +48,7 @@ constexpr int kCommandMod = 0x07; constexpr int kExpandedMod = 0xE0; constexpr int kExpandedLengthMod = 0x3FF; constexpr int kNormalLengthMod = 0x1F; +constexpr int kCompressionStringMod = 7 << 5; constexpr uchar kGraphicsBitmap[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; @@ -76,6 +78,8 @@ class ROM { absl::StatusOr DecompressGraphics(int pos, int size); absl::StatusOr DecompressOverworld(int pos, int size); + absl::StatusOr Load2bppGraphics(); + absl::Status LoadAllGraphicsData(); absl::Status LoadFromFile(const absl::string_view& filename); absl::Status LoadFromPointer(uchar* data, size_t length); diff --git a/src/app/zelda3/inventory.cc b/src/app/zelda3/inventory.cc index 923054a1..96093bdc 100644 --- a/src/app/zelda3/inventory.cc +++ b/src/app/zelda3/inventory.cc @@ -13,9 +13,18 @@ void Inventory::Create(Bytes& all_gfx) { for (int i = 0; i < 256 * 256; i++) { data_.push_back(0xFF); } - BuildTileset(all_gfx); + PRINT_IF_ERROR(BuildTileset(all_gfx)) + //tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kInventoryStart))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos))); - const int offsets[] = {0x00, 0x08, 0x200, 0x208}; + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x02))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x04))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x08))); + // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos))); + // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x02))); + // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x04))); + // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x08))); + const int offsets[] = {0x00, 0x08, 0x800, 0x808}; auto xx = 0; auto yy = 0; @@ -36,7 +45,7 @@ void Inventory::Create(Bytes& all_gfx) { } int xpos = ((tile.id_ % 0x10) * 0x08); - int ypos = (((tile.id_ / 0x10)) * 0x200); + int ypos = (((tile.id_ / 0x10)) * 0x400); int source = ypos + xpos + (x + (y * 0x80)); auto destination = xx + yy + offset + (mx + (my * 0x100)); @@ -44,39 +53,29 @@ void Inventory::Create(Bytes& all_gfx) { } } - xx += 0x10; - if (xx >= 0x80) { - yy += 0x800; - xx = 0; - } - if (i == 4) { i = 0; + xx += 0x10; + if (xx >= 0x80) { + yy += 0x800; + xx = 0; + } + } else { + i++; } - i++; } bitmap_.Create(256, 256, 128, data_); // bitmap_.ApplyPalette(rom_.GetPaletteGroup("hud")[0]); rom_.RenderBitmap(&bitmap_); } -void Inventory::BuildTileset(Bytes& all_gfx) { - //const int offsets[] = {0xDC000, 0x6D900, 0x6EF00, 0x6F000, 0xD8000, 0xD9000}; - const int offsets[] = {0xDC000, 0x6D900, 0x6EF00, 0x6F000, 0xD8000, 0xD9000}; - tilesheets_.reserve(6 * 0x1000); - for (int i = 0; i < 6 * 0x1000; i++) { - tilesheets_.push_back(0xFF); - } - - for (int y = 0; y < 6; y++) { - int offset = offsets[y]; - for (int x = 0; x < 0x1000; x++) { - tilesheets_[x + (y * 0x1000)] = all_gfx[offset + x + (y * 0x1000)]; - } - } - - tilesheets_bmp_.Create(128, 192, 64, tilesheets_); +absl::Status Inventory::BuildTileset(Bytes& all_gfx) { + tilesheets_.reserve(6 * 0x2000); + for (int i = 0; i < 6 * 0x2000; i++) tilesheets_.push_back(0xFF); + ASSIGN_OR_RETURN(tilesheets_, rom_.Load2bppGraphics()) + tilesheets_bmp_.Create(128, 192 + 96 + 48 - 16, 64, tilesheets_); rom_.RenderBitmap(&tilesheets_bmp_); + return absl::OkStatus(); } } // namespace zelda3 diff --git a/src/app/zelda3/inventory.h b/src/app/zelda3/inventory.h index 3af04d26..ed3fa7d3 100644 --- a/src/app/zelda3/inventory.h +++ b/src/app/zelda3/inventory.h @@ -10,8 +10,8 @@ namespace yaze { namespace app { namespace zelda3 { -constexpr int kMenuGfxStart = 0xE000; -constexpr int kLampItemPos = 0x6F6F0; +constexpr int kInventoryStart = 0x6564A; +constexpr int kLampItemPos = 0x6F6F9; constexpr int kBowItemPos = 0x6F631; class Inventory { @@ -23,8 +23,7 @@ class Inventory { void Create(Bytes& all_gfx); private: - void BuildTileset(Bytes& all_gfx); - + absl::Status BuildTileset(Bytes& all_gfx); ROM rom_; From a20b3fd2402291040a3373b7d43b3be4231ded4d Mon Sep 17 00:00:00 2001 From: scawful Date: Sat, 17 Sep 2022 10:34:44 -0500 Subject: [PATCH 16/16] housekeeping and inventory menu --- src/CMakeLists.txt | 41 ++++++++++++--- src/app/asm/script.cc | 66 +++++------------------ src/app/asm/script.h | 8 ++- src/app/core/constants.h | 2 +- src/app/delta/viewer.cc | 2 +- src/app/editor/master_editor.cc | 4 +- src/app/editor/overworld_editor.cc | 2 +- src/app/editor/screen_editor.cc | 50 ++++++++++++++---- src/app/editor/screen_editor.h | 6 ++- src/app/rom.cc | 81 ++++++++++------------------ src/app/rom.h | 2 +- src/app/zelda3/inventory.cc | 41 ++++++++------- src/app/zelda3/inventory.h | 9 ++-- src/gui/canvas.cc | 1 + src/gui/color.cc | 84 ++++++++++++++++++++++++++++++ src/gui/color.h | 20 +++++++ test/asm_test.cc | 12 ++--- 17 files changed, 266 insertions(+), 165 deletions(-) create mode 100644 src/gui/color.cc create mode 100644 src/gui/color.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d47e203..c660273d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,12 +36,35 @@ set( # Asar Assembly --------------------------------------------------------------- add_subdirectory(lib/asar/src) -set(ASAR_GEN_EXE OFF) -set(ASAR_GEN_DLL ON) -set(ASAR_GEN_LIB OFF) +get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES) +target_include_directories(asar-static PRIVATE ${ASAR_INCLUDE_DIR}) +set(ASAR_GEN_EXE OFF) +set(ASAR_GEN_DLL ON) +set(ASAR_GEN_LIB ON) set(ASAR_GEN_EXE_TEST OFF) set(ASAR_GEN_DLL_TEST OFF) +set(ASAR_STATIC_SRC + "lib/asar/src/asar/interface-lib.cpp" + "lib/asar/src/asar/addr2line.cpp" + "lib/asar/src/asar/arch-65816.cpp" + "lib/asar/src/asar/arch-spc700.cpp" + "lib/asar/src/asar/arch-superfx.cpp" + "lib/asar/src/asar/assembleblock.cpp" + "lib/asar/src/asar/crc32.cpp" + "lib/asar/src/asar/libcon.cpp" + "lib/asar/src/asar/libsmw.cpp" + "lib/asar/src/asar/libstr.cpp" + "lib/asar/src/asar/macro.cpp" + "lib/asar/src/asar/main.cpp" + "lib/asar/src/asar/asar_math.cpp" + "lib/asar/src/asar/virtualfile.cpp" + "lib/asar/src/asar/warnings.cpp" + "lib/asar/src/asar/errors.cpp" + "lib/asar/src/asar/platform/file-helpers.cpp" + "lib/asar/src/asar/platform/linux/file-helpers-linux.cpp" +) + # yaze source files ----------------------------------------------------------- set( YAZE_APP_CORE_SRC @@ -86,6 +109,7 @@ set( gui/input.cc gui/style.cc gui/widgets.cc + gui/color.cc ) add_executable( @@ -99,7 +123,7 @@ add_executable( ${YAZE_APP_ZELDA3_SRC} ${YAZE_GUI_SRC} ${IMGUI_SRC} - lib/asar/src/asar-dll-bindings/c/asardll.c + ${ASAR_STATIC_SRC} ) target_include_directories( @@ -111,7 +135,7 @@ target_include_directories( ${PNG_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${GLEW_INCLUDE_DIRS} - lib/asar/src/asar-dll-bindings/c + lib/asar/src/ ) set(SDL_TARGETS SDL2::SDL2) @@ -130,7 +154,10 @@ target_link_libraries( ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS} ImGui + asar-static ) +target_compile_definitions(yaze PRIVATE "linux") +target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp") set_target_properties(yaze PROPERTIES @@ -155,7 +182,6 @@ add_executable( ${YAZE_APP_ZELDA3_SRC} ${YAZE_GUI_SRC} ${IMGUI_SRC} - lib/asar/src/asar-dll-bindings/c/asardll.c ) target_include_directories( @@ -167,7 +193,7 @@ target_include_directories( ${PNG_INCLUDE_DIRS} ${SDL2_INCLUDE_DIR} ${GLEW_INCLUDE_DIRS} - lib/asar/src/asar-dll-bindings/c + ${ASAR_STATIC_SRC} ) target_link_libraries( @@ -179,6 +205,7 @@ target_link_libraries( ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS} delta-service + asar-static ImGui ) diff --git a/src/app/asm/script.cc b/src/app/asm/script.cc index 1972e958..ff0cf404 100644 --- a/src/app/asm/script.cc +++ b/src/app/asm/script.cc @@ -1,6 +1,6 @@ #include "script.h" -#include +#include #include #include @@ -20,49 +20,13 @@ namespace yaze { namespace app { namespace snes_asm { -std::string GenerateBytePool(char mosaic_tiles[core::kNumOverworldMaps]) { - std::string to_return = ""; - int column = 0; - for (int i = 0; i < core::kNumOverworldMaps; ++i) { - std::string to_add = ""; - - // if start of line, define byte - if (i == 0 || i % 8 == 0) { - to_add += " db "; - } - - // set byte - to_add += "$00"; - if (mosaic_tiles[i] > 0) { - if (i == 0 || i % 8 == 0) { - to_add = " db $01"; - } else { - to_add = "$01"; - } - } - - // newline or comma separated - if (column == 7) { - column = 0; - to_add += " \n"; - } else { - column++; - to_add += ", "; - } - - to_return += to_add; - } - return to_return; -} - absl::Status Script::ApplyPatchToROM(ROM &rom) { if (patch_contents_.empty() || patch_filename_.empty()) { return absl::InvalidArgumentError("No patch loaded!"); } - - char *data = (char *)rom.data(); - int size = rom.GetSize(); int count = 0; + auto data = (char *)rom.data(); + int size = rom.size(); if (!asar_patch(patch_filename_.c_str(), data, patch_size_, &size)) { auto asar_error = asar_geterrors(&count); auto full_error = asar_error->fullerrdata; @@ -71,43 +35,37 @@ absl::Status Script::ApplyPatchToROM(ROM &rom) { return absl::OkStatus(); } -absl::Status Script::GenerateMosaicChangeAssembly( +absl::Status Script::PatchOverworldMosaic( ROM &rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, int hook_offset) { + for (int i = 0; i < core::kNumOverworldMaps; i++) { + if (mosaic_tiles[i]) { + rom[core::overworldCustomMosaicArray + i] = 0x01; + } else { + rom[core::overworldCustomMosaicArray + i] = 0x00; + } + } std::fstream file("assets/asm/mosaic_change.asm", std::ios::out | std::ios::in); if (!file.is_open()) { return absl::InvalidArgumentError( - "Couldn't open mosaic change template file"); + "Unable to open mosaic change assembly source"); } - std::stringstream assembly; assembly << file.rdbuf(); file.close(); - auto assembly_string = assembly.str(); - if (!core::StringReplace(assembly_string, "", kMosaicChangeOffset)) { return absl::InternalError( "Mosaic template did not have proper `` to replace."); } - if (!core::StringReplace( assembly_string, "", absl::StrFormat("$%x", routine_offset + kSNESToPCOffset))) { return absl::InternalError( "Mosaic template did not have proper `` to replace."); } - - assembly_string += GenerateBytePool(mosaic_tiles); patch_contents_ = assembly_string; - patch_filename_ = "assets/asm/mosaic_change_generated.asm"; - std::ofstream new_file(patch_filename_, std::ios::out); - if (new_file.is_open()) { - new_file.write(assembly_string.c_str(), assembly_string.size()); - new_file.close(); - } - return ApplyPatchToROM(rom); } diff --git a/src/app/asm/script.h b/src/app/asm/script.h index ede1ba36..15a2b5cf 100644 --- a/src/app/asm/script.h +++ b/src/app/asm/script.h @@ -1,7 +1,7 @@ #ifndef YAZE_APP_ASM_SCRIPT_H #define YAZE_APP_ASM_SCRIPT_H -#include +#include #include #include @@ -27,17 +27,15 @@ class ScriptTemplate { public: virtual ~ScriptTemplate() = default; virtual absl::Status ApplyPatchToROM(ROM& rom) = 0; - virtual absl::Status GenerateMosaicChangeAssembly( + virtual absl::Status PatchOverworldMosaic( ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, int hook_offset = 0) = 0; }; class Script : public ScriptTemplate { public: - Script() { asar_init_with_dll_path("assets/libasar.dll"); } - absl::Status ApplyPatchToROM(ROM& rom) override; - absl::Status GenerateMosaicChangeAssembly( + absl::Status PatchOverworldMosaic( ROM& rom, char mosaic_tiles[core::kNumOverworldMaps], int routine_offset, int hook_offset = 0) override; diff --git a/src/app/core/constants.h b/src/app/core/constants.h index aeff07c7..94f957ba 100644 --- a/src/app/core/constants.h +++ b/src/app/core/constants.h @@ -482,7 +482,7 @@ constexpr int customAreaSpecificBGPalette = constexpr int customAreaSpecificBGASM = 0x140150; constexpr int customAreaSpecificBGEnabled = 0x140140; // 1 byte, not 0 if enabled - +constexpr int overworldCustomMosaicArray = 0x1301F0; // ============================================================================ // Dungeon Map Related Variables // ============================================================================ diff --git a/src/app/delta/viewer.cc b/src/app/delta/viewer.cc index b1466560..c3848ebe 100644 --- a/src/app/delta/viewer.cc +++ b/src/app/delta/viewer.cc @@ -127,7 +127,7 @@ void Viewer::DrawViewMenu() { if (show_memory_editor) { static MemoryEditor mem_edit; - mem_edit.DrawWindow("Memory Editor", (void*)&rom_, rom_.GetSize()); + mem_edit.DrawWindow("Memory Editor", (void*)&rom_, rom_.size()); } if (show_imgui_demo) { diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index 59a8a363..14dbcb4f 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -138,7 +138,7 @@ void MasterEditor::DrawInfoPopup() { if (ImGui::BeginPopupModal("ROM Information", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("Title: %s", rom_.GetTitle()); - ImGui::Text("ROM Size: %ld", rom_.GetSize()); + ImGui::Text("ROM Size: %ld", rom_.size()); if (ImGui::Button("Close", ImVec2(200, 0))) { rom_info_ = false; @@ -216,7 +216,7 @@ void MasterEditor::DrawViewMenu() { if (show_memory_editor) { static MemoryEditor mem_edit; - mem_edit.DrawWindow("Memory Editor", (void *)&rom_, rom_.GetSize()); + mem_edit.DrawWindow("Memory Editor", (void *)&rom_, rom_.size()); } if (show_imgui_demo) { diff --git a/src/app/editor/overworld_editor.cc b/src/app/editor/overworld_editor.cc index 1477176e..3e606b76 100644 --- a/src/app/editor/overworld_editor.cc +++ b/src/app/editor/overworld_editor.cc @@ -107,7 +107,7 @@ absl::Status OverworldEditor::DrawToolset() { BUTTON_COLUMN(ICON_MD_ZOOM_OUT) // Zoom Out BUTTON_COLUMN(ICON_MD_ZOOM_IN) // Zoom In TEXT_COLUMN(ICON_MD_MORE_VERT) // Separator - BUTTON_COLUMN(ICON_MD_DRAW); // Draw Tile + BUTTON_COLUMN(ICON_MD_DRAW) // Draw Tile BUTTON_COLUMN(ICON_MD_DOOR_FRONT) // Entrances BUTTON_COLUMN(ICON_MD_DOOR_BACK) // Exits BUTTON_COLUMN(ICON_MD_GRASS) // Items diff --git a/src/app/editor/screen_editor.cc b/src/app/editor/screen_editor.cc index 34505b2c..d81b6262 100644 --- a/src/app/editor/screen_editor.cc +++ b/src/app/editor/screen_editor.cc @@ -17,6 +17,7 @@ #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" #include "gui/canvas.h" +#include "gui/icons.h" #include "gui/input.h" namespace yaze { @@ -63,37 +64,40 @@ void ScreenEditor::DrawInventoryMenuEditor() { TAB_ITEM("Inventory Menu") static bool create = false; - if (!create) { - PRINT_IF_ERROR(rom_.LoadAllGraphicsData()) - all_gfx_ = rom_.GetGraphicsBuffer(); - inventory_.Create(all_gfx_); + if (!create && rom_.isLoaded()) { + inventory_.Create(); + palette_ =inventory_.Palette(); create = true; } - if (ImGui::BeginTable("InventoryScreen", 2, ImGuiTableFlags_Resizable)) { + DrawInventoryToolset(); + + if (ImGui::BeginTable("InventoryScreen", 3, ImGuiTableFlags_Resizable)) { ImGui::TableSetupColumn("Canvas"); ImGui::TableSetupColumn("Tiles"); + ImGui::TableSetupColumn("Palette"); ImGui::TableHeadersRow(); ImGui::TableNextColumn(); screen_canvas_.DrawBackground(); screen_canvas_.DrawContextMenu(); screen_canvas_.DrawBitmap(inventory_.Bitmap(), 2, create); - screen_canvas_.DrawGrid(); + screen_canvas_.DrawGrid(32.0f); screen_canvas_.DrawOverlay(); ImGui::TableNextColumn(); - tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, 192 * 2 + 2)); + tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4)); tilesheet_canvas_.DrawContextMenu(); tilesheet_canvas_.DrawBitmap(inventory_.Tilesheet(), 2, create); tilesheet_canvas_.DrawGrid(16.0f); tilesheet_canvas_.DrawOverlay(); + ImGui::TableNextColumn(); + gui::DisplayPalette(palette_, create); + ImGui::EndTable(); } - - ImGui::SameLine(); - + ImGui::Separator(); END_TAB_ITEM() } @@ -138,7 +142,7 @@ void ScreenEditor::DrawMosaicEditor() { gui::InputHex("Routine Location", &overworldCustomMosaicASM); if (ImGui::Button("Generate Mosaic Assembly")) { - auto mosaic = mosaic_script_.GenerateMosaicChangeAssembly( + auto mosaic = mosaic_script_.PatchOverworldMosaic( rom_, mosaic_tiles_, overworldCustomMosaicASM); if (!mosaic.ok()) { std::cout << mosaic; @@ -168,6 +172,30 @@ void ScreenEditor::DrawToolset() { ImGui::Checkbox("Draw BG3", &drawing_bg3); } +void ScreenEditor::DrawInventoryToolset() { + if (ImGui::BeginTable("InventoryToolset", 8, ImGuiTableFlags_SizingFixedFit, ImVec2(0, 0))) { + ImGui::TableSetupColumn("#drawTool"); + ImGui::TableSetupColumn("#sep1"); + ImGui::TableSetupColumn("#zoomOut"); + ImGui::TableSetupColumn("#zoomIN"); + ImGui::TableSetupColumn("#sep2"); + ImGui::TableSetupColumn("#bg2Tool"); + ImGui::TableSetupColumn("#bg3Tool"); + ImGui::TableSetupColumn("#itemTool"); + + BUTTON_COLUMN(ICON_MD_UNDO) + BUTTON_COLUMN(ICON_MD_REDO) + TEXT_COLUMN(ICON_MD_MORE_VERT) + BUTTON_COLUMN(ICON_MD_ZOOM_OUT) + BUTTON_COLUMN(ICON_MD_ZOOM_IN) + TEXT_COLUMN(ICON_MD_MORE_VERT) + BUTTON_COLUMN(ICON_MD_DRAW) + BUTTON_COLUMN(ICON_MD_BUILD) + + ImGui::EndTable(); + } +} + } // namespace editor } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/editor/screen_editor.h b/src/app/editor/screen_editor.h index 46b0fbfa..c6635dec 100644 --- a/src/app/editor/screen_editor.h +++ b/src/app/editor/screen_editor.h @@ -9,9 +9,12 @@ #include "app/core/constants.h" #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" +#include "app/gfx/snes_palette.h" #include "app/rom.h" #include "app/zelda3/inventory.h" #include "gui/canvas.h" +#include "gui/icons.h" +#include "gui/color.h" namespace yaze { namespace app { @@ -19,7 +22,6 @@ namespace editor { using MosaicArray = std::array; static int overworldCustomMosaicASM = 0x1301D0; -static int overworldCustomMosaicArray = 0x1301F0; class ScreenEditor { public: @@ -39,6 +41,7 @@ class ScreenEditor { void DrawInventoryMenuEditor(); void DrawToolset(); + void DrawInventoryToolset(); void DrawWorldGrid(int world, int h = 8, int w = 8); char mosaic_tiles_[core::kNumOverworldMaps]; @@ -46,6 +49,7 @@ class ScreenEditor { ROM rom_; Bytes all_gfx_; zelda3::Inventory inventory_; + gfx::SNESPalette palette_; snes_asm::Script mosaic_script_; gui::Canvas screen_canvas_; gui::Canvas tilesheet_canvas_; diff --git a/src/app/rom.cc b/src/app/rom.cc index 067add26..139f37ab 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -302,7 +302,7 @@ absl::Status ValidateCompressionResult( RETURN_IF_ERROR(temp_rom.LoadFromBytes( CreateCompressionString(compressed_chain_start->next, mode))) ASSIGN_OR_RETURN(auto decomp_data, - temp_rom.Decompress(0, temp_rom.GetSize())) + temp_rom.Decompress(0, temp_rom.size())) if (!std::equal(decomp_data.begin() + start, decomp_data.end(), temp_rom.begin())) { return absl::InternalError(absl::StrFormat( @@ -352,7 +352,7 @@ int GetGraphicsAddress(const uchar* data, uint8_t offset) { return core::SnesToPc(snes_addr); } -Bytes SNES3bppTo8bppSheet(Bytes sheet, int bpp) { +Bytes SnesTo8bppSheet(Bytes sheet, int bpp) { int xx = 0; // positions where we are at on the sheet int yy = 0; int pos = 0; @@ -368,12 +368,9 @@ Bytes SNES3bppTo8bppSheet(Bytes sheet, int bpp) { } Bytes sheet_buffer_out(buffer_size); - // for each tiles, 16 per line - for (int i = 0; i < num_tiles; i++) { - // for each line - for (int y = 0; y < 8; y++) { - //[0] + [1] + [16] - for (int x = 0; x < 8; x++) { + for (int i = 0; i < num_tiles; i++) { // for each tiles, 16 per line + for (int y = 0; y < 8; y++) { // for each line + for (int x = 0; x < 8; x++) { //[0] + [1] + [16] auto b1 = ((sheet[(y * 2) + (bpp * pos)] & (kGraphicsBitmap[x]))); auto b2 = (sheet[((y * 2) + (bpp * pos)) + 1] & (kGraphicsBitmap[x])); auto b3 = (sheet[(16 + y) + (bpp * pos)] & (kGraphicsBitmap[x])); @@ -457,7 +454,6 @@ absl::StatusOr ROM::Compress(const int start, const int length, int mode, comp_accumulator = 0; } } else { - // Anything is better than directly copying bytes... lc_lz2::CompressionCommandAlternative( rom_data_.data(), compressed_chain, cmd_size, cmd_args, src_data_pos, comp_accumulator, cmd_with_max, max_win); @@ -474,8 +470,8 @@ absl::StatusOr ROM::Compress(const int start, const int length, int mode, } } - lc_lz2::MergeCopy( - compressed_chain_start->next); // Skipping compression chain header + // Skipping compression chain header + lc_lz2::MergeCopy(compressed_chain_start->next); lc_lz2::PrintCompressionChain(compressed_chain_start); return lc_lz2::CreateCompressionString(compressed_chain_start->next, mode); } @@ -515,10 +511,8 @@ absl::StatusOr ROM::Decompress(int offset, int size, int mode) { offset += length; break; case kCommandByteFill: - for (int i = 0; i < length; i++) { - buffer[buffer_pos] = rom_data_[offset]; - buffer_pos++; - } + memset(buffer.data() + buffer_pos, (int)(rom_data_[offset]), length); + buffer_pos += length; offset += 1; // Advances 1 byte in the ROM break; case kCommandWordFill: { @@ -543,35 +537,23 @@ absl::StatusOr ROM::Decompress(int offset, int size, int mode) { ushort s1 = ((rom_data_[offset + 1] & kSnesByteMax) << 8); ushort s2 = ((rom_data_[offset] & kSnesByteMax)); int addr = (s1 | s2); - if (mode == kNintendoMode1) { // Reversed byte order for overworld maps - // addr = (s2 | s1); addr = (rom_data_[offset + 1] & kSnesByteMax) | ((rom_data_[offset] & kSnesByteMax) << 8); - if (addr > offset) { - return absl::InternalError(absl::StrFormat( - "Decompress: Offset for command copy exceeds current position " - "(Offset : %#04x | Pos : %#06x)\n", - addr, offset)); - } - - if (buffer_pos + length >= size) { - size *= 2; - buffer.resize(size); - } - - memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length); - buffer_pos += length; - offset += 2; - break; } - - for (int i = 0; i < length; i++) { - buffer[buffer_pos] = buffer[addr + i]; - buffer_pos++; + if (addr > offset) { + return absl::InternalError(absl::StrFormat( + "Decompress: Offset for command copy exceeds current position " + "(Offset : %#04x | Pos : %#06x)\n", + addr, offset)); } - offset += 2; // Advance 2 bytes in the ROM - + if (buffer_pos + length >= size) { + size *= 2; + buffer.resize(size); + } + memcpy(buffer.data() + buffer_pos, buffer.data() + addr, length); + buffer_pos += length; + offset += 2; } break; default: { std::cout << absl::StrFormat( @@ -598,12 +580,12 @@ absl::StatusOr ROM::Load2bppGraphics() { Bytes sheet; const uint8_t sheets[] = {113, 114, 218, 219, 220, 221}; - for (int i = 0; i < 6; i++) { - auto offset = GetGraphicsAddress(rom_data_.data(), sheets[i]); + for (const auto& sheet_id : sheets) { + auto offset = GetGraphicsAddress(rom_data_.data(), sheet_id); ASSIGN_OR_RETURN(auto decomp_sheet, Decompress(offset)) - auto converted_sheet = SNES3bppTo8bppSheet(decomp_sheet, 2); - for (int j = 0; j < converted_sheet.size(); ++j) { - sheet.push_back(converted_sheet.at(j)); + auto converted_sheet = SnesTo8bppSheet(decomp_sheet, 2); + for (const auto& each_pixel : converted_sheet) { + sheet.push_back(each_pixel); } } return sheet; @@ -627,8 +609,6 @@ absl::Status ROM::LoadAllGraphicsData() { } bpp3 = true; } else if (i == 113 || i == 114 || i >= 218) { - // auto offset = GetGraphicsAddress(rom_data_.data(), i); - // ASSIGN_OR_RETURN(sheet, Decompress(offset)) bpp3 = false; } else { auto offset = GetGraphicsAddress(rom_data_.data(), i); @@ -637,7 +617,7 @@ absl::Status ROM::LoadAllGraphicsData() { } if (bpp3) { - auto converted_sheet = SNES3bppTo8bppSheet(sheet, 3); + auto converted_sheet = SnesTo8bppSheet(sheet, 3); graphics_bin_[i] = gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, core::kTilesheetDepth, converted_sheet.data(), 0x1000); @@ -647,15 +627,8 @@ absl::Status ROM::LoadAllGraphicsData() { graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } else { - // auto converted_sheet = SNES3bppTo8bppSheet(sheet, 2); - // graphics_bin_[i] = - // gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, - // core::kTilesheetDepth, converted_sheet.data(), 0x1000); - // graphics_bin_.at(i).CreateTexture(renderer_); - for (int j = 0; j < graphics_bin_.at(0).GetSize(); ++j) { graphics_buffer_.push_back(0xFF); - // graphics_buffer_.push_back(graphics_bin_.at(i).GetByte(j)); } } } diff --git a/src/app/rom.h b/src/app/rom.h index a8beaec6..8f753b28 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -93,7 +93,6 @@ class ROM { void RenderBitmap(gfx::Bitmap* bitmap) const; - auto GetSize() const { return size_; } auto GetTitle() const { return title; } auto GetGraphicsBin() const { return graphics_bin_; } auto GetGraphicsBuffer() const { return graphics_buffer_; } @@ -105,6 +104,7 @@ class ROM { auto begin() { return rom_data_.begin(); } auto end() { return rom_data_.end(); } auto data() { return rom_data_.data(); } + auto size() const { return size_; } uchar& operator[](int i) { if (i > size_) { diff --git a/src/app/zelda3/inventory.cc b/src/app/zelda3/inventory.cc index 96093bdc..b69039cc 100644 --- a/src/app/zelda3/inventory.cc +++ b/src/app/zelda3/inventory.cc @@ -8,22 +8,18 @@ namespace yaze { namespace app { namespace zelda3 { -void Inventory::Create(Bytes& all_gfx) { +void Inventory::Create() { data_.reserve(256 * 256); for (int i = 0; i < 256 * 256; i++) { data_.push_back(0xFF); } - PRINT_IF_ERROR(BuildTileset(all_gfx)) - //tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kInventoryStart))); - - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos))); - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x02))); - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x04))); - tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kBowItemPos + 0x08))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x02))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x04))); - // tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(kLampItemPos + 0x08))); + PRINT_IF_ERROR(BuildTileset()) + for (int i = 0; i < 0x400; i += 0x08) { + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x02))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x04))); + tiles_.push_back(gfx::GetTilesInfo(rom_.toint16(i + kBowItemPos + 0x08))); + } const int offsets[] = {0x00, 0x08, 0x800, 0x808}; auto xx = 0; auto yy = 0; @@ -49,15 +45,15 @@ void Inventory::Create(Bytes& all_gfx) { int source = ypos + xpos + (x + (y * 0x80)); auto destination = xx + yy + offset + (mx + (my * 0x100)); - data_[destination] = (tilesheets_[source] & 0x0F); + data_[destination] = (test_[source] & 0x0F) + tile.palette_ * 0x08; } } if (i == 4) { i = 0; xx += 0x10; - if (xx >= 0x80) { - yy += 0x800; + if (xx >= 0x100) { + yy += 0x1000; xx = 0; } } else { @@ -65,15 +61,24 @@ void Inventory::Create(Bytes& all_gfx) { } } bitmap_.Create(256, 256, 128, data_); - // bitmap_.ApplyPalette(rom_.GetPaletteGroup("hud")[0]); + bitmap_.ApplyPalette(palette_); rom_.RenderBitmap(&bitmap_); } -absl::Status Inventory::BuildTileset(Bytes& all_gfx) { +absl::Status Inventory::BuildTileset() { tilesheets_.reserve(6 * 0x2000); for (int i = 0; i < 6 * 0x2000; i++) tilesheets_.push_back(0xFF); ASSIGN_OR_RETURN(tilesheets_, rom_.Load2bppGraphics()) - tilesheets_bmp_.Create(128, 192 + 96 + 48 - 16, 64, tilesheets_); + Bytes test; + for (int i = 0; i < 0x4000; i++) { + test_.push_back(tilesheets_[i]); + } + for (int i = 0x8000; i < + 0x8000 + 0x2000; i++) { + test_.push_back(tilesheets_[i]); + } + tilesheets_bmp_.Create(128, 0x130, 64, test_); + palette_ = rom_.GetPaletteGroup("hud")[0]; + tilesheets_bmp_.ApplyPalette(palette_); rom_.RenderBitmap(&tilesheets_bmp_); return absl::OkStatus(); } diff --git a/src/app/zelda3/inventory.h b/src/app/zelda3/inventory.h index ed3fa7d3..4b714f8a 100644 --- a/src/app/zelda3/inventory.h +++ b/src/app/zelda3/inventory.h @@ -3,6 +3,7 @@ #include "app/gfx/bitmap.h" #include "app/gfx/snes_tile.h" +#include "app/gfx/snes_palette.h" #include "app/rom.h" #include "gui/canvas.h" @@ -11,7 +12,6 @@ namespace app { namespace zelda3 { constexpr int kInventoryStart = 0x6564A; -constexpr int kLampItemPos = 0x6F6F9; constexpr int kBowItemPos = 0x6F631; class Inventory { @@ -19,11 +19,12 @@ class Inventory { void SetupROM(ROM& rom) { rom_ = rom; } auto Bitmap() const { return bitmap_; } auto Tilesheet() const { return tilesheets_bmp_; } + auto Palette() const { return palette_; } - void Create(Bytes& all_gfx); + void Create(); private: - absl::Status BuildTileset(Bytes& all_gfx); + absl::Status BuildTileset(); ROM rom_; @@ -31,7 +32,9 @@ class Inventory { gfx::Bitmap bitmap_; Bytes tilesheets_; + Bytes test_; gfx::Bitmap tilesheets_bmp_; + gfx::SNESPalette palette_; gui::Canvas canvas_; std::vector tiles_; diff --git a/src/gui/canvas.cc b/src/gui/canvas.cc index e97f2a25..ccef103a 100644 --- a/src/gui/canvas.cc +++ b/src/gui/canvas.cc @@ -64,6 +64,7 @@ void Canvas::DrawContextMenu() { ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); if (ImGui::BeginPopup("context")) { + ImGui::MenuItem("Show Grid", nullptr, &enable_grid_); if (ImGui::MenuItem("Reset Position", nullptr, false)) { scrolling_.x = 0; scrolling_.y = 0; diff --git a/src/gui/color.cc b/src/gui/color.cc new file mode 100644 index 00000000..22c836a1 --- /dev/null +++ b/src/gui/color.cc @@ -0,0 +1,84 @@ +#include "color.h" + +#include + +#include +#include + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_palette.h" + +namespace yaze { +namespace gui { +void DisplayPalette(app::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; + static ImVec4 saved_palette[32] = {}; + if (loaded && !init) { + for (int n = 0; n < palette.size_; n++) { + saved_palette[n].x = palette.GetColor(n).rgb.x / 255; + saved_palette[n].y = palette.GetColor(n).rgb.y / 255; + saved_palette[n].z = palette.GetColor(n).rgb.z / 255; + saved_palette[n].w = 255; // Alpha + } + init = true; + } + + static ImVec4 backup_color; + ImGui::Text("Current ==>"); + ImGui::SameLine(); + ImGui::Text("Previous"); + + ImGui::ColorButton( + "##current", color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40)); + ImGui::SameLine(); + + if (ImGui::ColorButton( + "##previous", backup_color, + ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, + ImVec2(60, 40))) + color = backup_color; + ImGui::Separator(); + +ImGui::BeginGroup(); // Lock X position + ImGui::Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) { + ImGui::PushID(n); + if ((n % 4) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | + ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip; + if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, + ImVec2(20, 20))) + color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, + color.w); // Preserve alpha! + + if (ImGui::BeginDragDropTarget()) { + if (const ImGuiPayload* payload = + ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = + ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::ColorPicker4("##picker", (float*)&color, + misc_flags | ImGuiColorEditFlags_NoSidePreview | + ImGuiColorEditFlags_NoSmallPreview); +} +} // namespace gui +} // namespace yaze \ No newline at end of file diff --git a/src/gui/color.h b/src/gui/color.h new file mode 100644 index 00000000..fc9c5bc4 --- /dev/null +++ b/src/gui/color.h @@ -0,0 +1,20 @@ +#ifndef YAZE_GUI_COLOR_H +#define YAZE_GUI_COLOR_H + +#include + +#include +#include + +#include "app/gfx/bitmap.h" +#include "app/gfx/snes_palette.h" + +namespace yaze { +namespace gui { + +void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded); + +} // namespace gui +} // namespace yaze + +#endif \ No newline at end of file diff --git a/test/asm_test.cc b/test/asm_test.cc index 6ce8cfcc..e9212e8e 100644 --- a/test/asm_test.cc +++ b/test/asm_test.cc @@ -30,7 +30,7 @@ using ::testing::Return; class MockScript : public Script { public: MOCK_METHOD(absl::Status, ApplyPatchToROM, (ROM & rom)); - MOCK_METHOD(absl::Status, GenerateMosaicChangeAssembly, + MOCK_METHOD(absl::Status, PatchOverworldMosaic, (ROM & rom, char mosaic_tiles[yaze::app::core::kNumOverworldMaps], int routine_offset, int hook_offset)); }; @@ -40,15 +40,15 @@ TEST(ASMTest, ApplyMosaicChangePatchOk) { MockScript script; char mosaic_tiles[yaze::app::core::kNumOverworldMaps]; - EXPECT_CALL(script, GenerateMosaicChangeAssembly(_, Eq(mosaic_tiles), - Eq(0x1301D0 + 0x138000), 0)) + EXPECT_CALL(script, PatchOverworldMosaic(_, Eq(mosaic_tiles), + Eq(0x1301D0 + 0x138000), 0)) .WillOnce(Return(absl::OkStatus())); EXPECT_CALL(script, ApplyPatchToROM(_)).WillOnce(Return(absl::OkStatus())); - EXPECT_THAT(script.GenerateMosaicChangeAssembly(rom, mosaic_tiles, - 0x1301D0 + 0x138000, 0), - absl::OkStatus()); + EXPECT_THAT( + script.PatchOverworldMosaic(rom, mosaic_tiles, 0x1301D0 + 0x138000, 0), + absl::OkStatus()); EXPECT_THAT(script.ApplyPatchToROM(rom), absl::OkStatus()); }