diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d48a6cd5..d8ed1571 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,57 +129,4 @@ set_target_properties(yaze RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/yaze.res" ) -endif() - -# add_subdirectory(app/delta) - -# add_executable( -# yaze_delta -# app/delta/delta.cc -# app/delta/viewer.cc -# app/delta/service.cc -# app/delta/client.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} -# ${ASAR_STATIC_SRC} -# ) - -# target_include_directories( -# yaze_delta PUBLIC -# lib/ -# app/ -# lib/asar/src/ -# ${ASAR_INCLUDE_DIR} -# ${CMAKE_SOURCE_DIR}/src/ -# ${PNG_INCLUDE_DIRS} -# ${SDL2_INCLUDE_DIR} -# ${GLEW_INCLUDE_DIRS} -# ) - -# target_link_libraries( -# yaze_delta PUBLIC -# ${ABSL_TARGETS} -# ${SDL_TARGETS} -# ${PNG_LIBRARIES} -# ${GLEW_LIBRARIES} -# ${OPENGL_LIBRARIES} -# ${CMAKE_DL_LIBS} -# delta-service -# asar-static -# ImGui -# ) -# target_compile_definitions(yaze_delta PRIVATE "linux") -# target_compile_definitions(yaze_delta PRIVATE "stricmp=strcasecmp") - -# set (source "${CMAKE_SOURCE_DIR}/assets") -# set (destination "${CMAKE_CURRENT_BINARY_DIR}/assets") -# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD -# COMMAND ${CMAKE_COMMAND} -E create_symlink ${source} ${destination} -# DEPENDS ${destination} -# COMMENT "symbolic link resources folder from ${source} => ${destination}") \ No newline at end of file +endif() \ No newline at end of file diff --git a/src/app/core/constants.h b/src/app/core/constants.h index c727b5a0..a8a84372 100644 --- a/src/app/core/constants.h +++ b/src/app/core/constants.h @@ -65,6 +65,10 @@ #define APPEND_NUMBER_INNER(expression, number) expression##number +#define TEXT_WITH_SEPARATOR(text) \ + ImGui::Text(text); \ + ImGui::Separator(); + using ushort = unsigned short; using uint = unsigned int; using uchar = unsigned char; diff --git a/src/app/delta/CMakeLists.txt b/src/app/delta/CMakeLists.txt deleted file mode 100644 index 087dd9f7..00000000 --- a/src/app/delta/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ - -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 deleted file mode 100644 index 4a24a78d..00000000 --- a/src/app/delta/client.cc +++ /dev/null @@ -1,54 +0,0 @@ -#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); - new_repo.mutable_tree()->Add(); - - 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 deleted file mode 100644 index 6c3d7f74..00000000 --- a/src/app/delta/client.h +++ /dev/null @@ -1,44 +0,0 @@ -#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: - Client() = default; - 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 deleted file mode 100644 index 4a413d67..00000000 --- a/src/app/delta/delta.cc +++ /dev/null @@ -1,32 +0,0 @@ -#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()) { - 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 deleted file mode 100644 index c15090b3..00000000 --- a/src/app/delta/delta.proto +++ /dev/null @@ -1,105 +0,0 @@ -syntax = "proto3"; -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) {} - - rpc Merge(MergeRequest) returns (MergeResponse) {} - rpc UndoMerge(UndoMergeRequest) returns (UndoMergeResponse) {} -} - -enum ChangeType { - OVERWORLD_MAP = 0; - DUNGEON_MAP = 1; - MONOLOGUE = 2; - PALETTE = 3; - OBJECT = 4; - ASSEMBLY = 5; - MISC = 6; -} - -message Delta { - int64 offset = 1; - int64 length = 2; - bytes data = 3; - ChangeType type = 4; -} - -message Commit { - int64 commit_id = 1; - int64 parent_commit_id = 2; - string author_name = 3; - string message_header = 4; - optional string message_body = 5; - repeated Delta delta = 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 author_name = 1; - string repository_name= 2; - string branch_name = 3; - repeated Commit commits = 4; -} -message PushResponse {} - -message PullRequest { - string repository_name = 1; - string branch_name = 2; - repeated Commit commits = 3; -} - -message PullResponse {} - -message SyncRequest {} - -message SyncResponse {} - -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/service.cc b/src/app/delta/service.cc deleted file mode 100644 index cdfb5504..00000000 --- a/src/app/delta/service.cc +++ /dev/null @@ -1,87 +0,0 @@ -#include "service.h" - -#include -#include -#include -#include -#include - -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.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; - -namespace { -auto FindRepository(std::vector& repos, const std::string& name) { - for (auto& repo : repos) { - if (repo.project_name() == name) { - return repo.mutable_tree(); - } - } -} - -auto FindBranch(google::protobuf::RepeatedPtrField* repo, - const std::string& branch_name) { - for (auto it = repo->begin(); it != repo->end(); ++it) { - if (it->branch_name() == branch_name) { - return it->mutable_commits(); - } - } -} -} // namespace - -Status DeltaService::Init(grpc::ServerContext* context, - const InitRequest* request, InitResponse* reply) { - std::filesystem::create_directories("./.yaze"); - repos_.push_back(request->repo()); - // std::ofstream commit_stream("./.yaze/commits"); - // for (const auto& repo : repos_) { - // for (const auto& branch : repo.tree()) { - // for (const auto& commit : branch.commits()) { - // commit_stream << commit.DebugString(); - // } - // } - // } - return Status::OK; -} - -Status DeltaService::Push(grpc::ServerContext* context, - const PushRequest* request, PushResponse* reply) { - const auto& repository_name = request->repository_name(); - const auto& branch_name = request->branch_name(); - auto repo = FindRepository(repos_, repository_name); - auto mutable_commits = FindBranch(repo, branch_name); - auto size = request->commits().size(); - for (int i = 1; i < size; ++i) { - *mutable_commits->Add() = request->commits().at(i); - } - return Status::OK; -} - -Status DeltaService::Pull(grpc::ServerContext* context, - const PullRequest* request, PullResponse* reply) { - return Status::OK; -} - -Status DeltaService::Clone(grpc::ServerContext* context, - const CloneRequest* request, CloneResponse* reply) { - return Status::OK; -} - -} // namespace delta -} // namespace app -} // namespace yaze diff --git a/src/app/delta/service.h b/src/app/delta/service.h deleted file mode 100644 index d986def7..00000000 --- a/src/app/delta/service.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef YAZE_APP_DELTA_SERVICE_H -#define YAZE_APP_DELTA_SERVICE_H - -#include - -#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::Status; - -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; - - Status Clone(grpc::ServerContext* context, const CloneRequest* request, - CloneResponse* reply) override; - - auto Repos() const { return repos_; } - - private: - std::vector repos_; -}; - -} // namespace delta -} // namespace app -} // namespace yaze - -#endif \ No newline at end of file diff --git a/src/app/delta/viewer.cc b/src/app/delta/viewer.cc deleted file mode 100644 index c3848ebe..00000000 --- a/src/app/delta/viewer.cc +++ /dev/null @@ -1,229 +0,0 @@ -#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; - } -} - -} // 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_.size()); - } - - 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 | - 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[] = { - {"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); - - 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 deleted file mode 100644 index edcc8d48..00000000 --- a/src/app/delta/viewer.h +++ /dev/null @@ -1,45 +0,0 @@ -#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/delta/client.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 DrawFileDialog(); - - void DrawYazeMenu(); - void DrawFileMenu() const; - void DrawViewMenu(); - - void DrawBranchTree(); - - std::string client_address_; - - ROM rom_; - Client client_; -}; -} // namespace delta -} // namespace app -} // namespace yaze - -#endif \ No newline at end of file diff --git a/src/app/editor/palette_editor.cc b/src/app/editor/palette_editor.cc index 00e6c381..11d0bd80 100644 --- a/src/app/editor/palette_editor.cc +++ b/src/app/editor/palette_editor.cc @@ -7,34 +7,113 @@ #include "gui/canvas.h" #include "gui/icons.h" +static inline float ImSaturate(float f) { + return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; +} + +#define IM_F32_TO_INT8_SAT(_VAL) \ + ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 + +int CustomFormatString(char* buf, size_t buf_size, const char* fmt, ...) { + va_list args; + va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + va_end(args); + if (buf == NULL) return w; + if (w == -1 || w >= (int)buf_size) w = (int)buf_size - 1; + buf[w] = 0; + return w; +} + namespace yaze { namespace app { namespace editor { -absl::Status PaletteEditor::Update() { - 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); +namespace { +void DrawPaletteTooltips(gfx::SNESPalette& palette, int size) {} - 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! +using namespace ImGui; - ImGui::PopID(); - } +} // namespace + +void PaletteEditor::DrawPaletteGroup(int i) { + const int palettesPerRow = 4; + ImGui::BeginTable("palette_table", palettesPerRow, + ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable); + + auto size = rom_.GetPaletteGroup(kPaletteGroupNames[i].data()).size(); + auto palettes = rom_.GetPaletteGroup(kPaletteGroupNames[i].data()); + for (int j = 0; j < size; j++) { + if (j % palettesPerRow == 0) { + ImGui::TableNextRow(); + } + ImGui::TableSetColumnIndex(j % palettesPerRow); + ImGui::Text("%d", j); + + auto palette = palettes[j]; + auto pal_size = palette.size_; + + for (int n = 0; n < pal_size; n++) { + ImGui::PushID(n); + if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + std::string popupId = kPaletteCategoryNames[i].data() + + std::to_string(j) + "_" + std::to_string(n); + if (ImGui::ColorButton(popupId.c_str(), palette[n].RGB(), + palette_button_flags)) { + if (ImGui::ColorEdit4(popupId.c_str(), palette[n].ToFloatArray(), + palette_button_flags)) + current_color_ = + ImVec4(palette[n].rgb.x, palette[n].rgb.y, palette[n].rgb.z, + palette[n].rgb.w); // Preserve alpha! } + + if (ImGui::BeginPopupContextItem(popupId.c_str())) { + auto col = palette[n].ToFloatArray(); + if (ImGui::ColorEdit4( + "Edit Color", col, + ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha)) { + // palette[n].rgb.x = current_color_rgba.x; + // palette[n].rgb.y = current_color_rgba.y; + // palette[n].rgb.z = current_color_rgba.z; + // rom_.UpdatePaletteColor(kPaletteGroupNames[groupIndex].data(), j, + // n, palette[n]); + } + if (Button("Copy as..", ImVec2(-1, 0))) OpenPopup("Copy"); + if (BeginPopup("Copy")) { + int cr = IM_F32_TO_INT8_SAT(col[0]); + int cg = IM_F32_TO_INT8_SAT(col[1]); + int cb = IM_F32_TO_INT8_SAT(col[2]); + char buf[64]; + CustomFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff)", + col[0], col[1], col[2]); + if (Selectable(buf)) SetClipboardText(buf); + CustomFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d)", cr, cg, cb); + if (Selectable(buf)) SetClipboardText(buf); + CustomFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", cr, cg, + cb); + if (Selectable(buf)) SetClipboardText(buf); + EndPopup(); + } + + ImGui::EndPopup(); + } + + ImGui::PopID(); + } + } + + ImGui::EndTable(); +} + +absl::Status PaletteEditor::Update() { + for (int i = 0; i < kNumPalettes; ++i) { + if (ImGui::TreeNode(kPaletteCategoryNames[i].data())) { + DrawPaletteGroup(i); ImGui::TreePop(); } } @@ -49,13 +128,12 @@ void PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, bool loaded) { // 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 + 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; } @@ -68,9 +146,9 @@ void PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, bool loaded) { ImGui::OpenPopup("mypicker"); backup_color = color; } + if (ImGui::BeginPopup("mypicker")) { - ImGui::Text("Current Overworld Palette"); - ImGui::Separator(); + TEXT_WITH_SEPARATOR("Current Overworld Palette"); ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); @@ -94,25 +172,22 @@ void PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, bool loaded) { color = backup_color; ImGui::Separator(); ImGui::Text("Palette"); - for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) { + 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::ColorButton("##palette", saved_palette_[n], + palette_button_flags_2, 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); + 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); + memcpy((float*)&saved_palette_[n], payload->Data, sizeof(float) * 4); ImGui::EndDragDropTarget(); } diff --git a/src/app/editor/palette_editor.h b/src/app/editor/palette_editor.h index 80ab485f..3b62c688 100644 --- a/src/app/editor/palette_editor.h +++ b/src/app/editor/palette_editor.h @@ -13,15 +13,18 @@ namespace yaze { namespace app { namespace editor { +constexpr int kNumPalettes = 11; + static constexpr absl::string_view kPaletteCategoryNames[] = { "Sword", "Shield", "Clothes", "World Colors", "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"}; + "swords", "shields", "armors", "ow_main", + "ow_aux", "global_sprites", "dungeon_main", "ow_mini_map", + "ow_mini_map", "3d_object", "3d_object"}; + class PaletteEditor { public: @@ -31,8 +34,17 @@ class PaletteEditor { auto SetupROM(ROM& rom) { rom_ = rom; } private: + void DrawPaletteGroup(int i); + + ImVec4 saved_palette_[256] = {}; ImVec4 current_color_; ROM rom_; + + ImGuiColorEditFlags palette_button_flags = + ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags palette_button_flags_2 = ImGuiColorEditFlags_NoAlpha | + ImGuiColorEditFlags_NoPicker | + ImGuiColorEditFlags_NoTooltip; }; } // namespace editor diff --git a/src/app/gfx/snes_palette.cc b/src/app/gfx/snes_palette.cc index 5ff1c878..c69a03e0 100644 --- a/src/app/gfx/snes_palette.cc +++ b/src/app/gfx/snes_palette.cc @@ -190,7 +190,7 @@ SDL_Palette* SNESPalette::GetSDL_Palette() { return sdl_palette.get(); } -PaletteGroup::PaletteGroup(uint8_t mSize) : size(mSize) {} +PaletteGroup::PaletteGroup(uint8_t mSize) : size_(mSize) {} } // namespace gfx } // namespace app diff --git a/src/app/gfx/snes_palette.h b/src/app/gfx/snes_palette.h index 1c0e4143..e213e52e 100644 --- a/src/app/gfx/snes_palette.h +++ b/src/app/gfx/snes_palette.h @@ -47,10 +47,18 @@ 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); + auto RGB() { return ImVec4(rgb.x / 255, rgb.y / 255, rgb.z / 255, rgb.w); } + + float* ToFloatArray() const { + static std::vector colorArray(4); + colorArray[0] = rgb.x / 255.0f; + colorArray[1] = rgb.y / 255.0f; + colorArray[2] = rgb.z / 255.0f; + colorArray[3] = rgb.w; + return colorArray.data(); } + bool modified = false; bool transparent = false; uint16_t snes = 0; ImVec4 rgb; @@ -82,6 +90,7 @@ class SNESPalette { SDL_Palette* GetSDL_Palette(); int size_ = 0; + auto size() const { return colors.size(); } std::vector colors; }; @@ -90,23 +99,24 @@ struct PaletteGroup { explicit PaletteGroup(uint8_t mSize); void AddPalette(SNESPalette pal) { palettes.emplace_back(pal); - size = palettes.size(); + size_ = palettes.size(); } void AddColor(SNESColor color) { - if (size == 0) { + if (size_ == 0) { SNESPalette empty_pal; palettes.emplace_back(empty_pal); } palettes[0].AddColor(color); } SNESPalette operator[](int i) { - if (i > size) { + if (i > size_) { std::cout << "PaletteGroup: Index out of bounds" << std::endl; return palettes[0]; } return palettes[i]; } - int size = 0; + int size_ = 0; + auto size() const { return palettes.size(); } std::vector palettes; }; diff --git a/src/app/rom.cc b/src/app/rom.cc index be3f94b7..0b208c56 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -816,6 +816,54 @@ void ROM::LoadAllPalettes() { } } +void ROM::SaveAllPalettes() { + // Iterate through all palette_groups_ + for (auto& group : palette_groups_) { + const std::string& groupName = group.first; + auto& palettes = group.second; + + // Iterate through all palettes in the group + for (size_t i = 0; i < palettes.size(); ++i) { + auto palette = palettes[i]; + + // Iterate through all colors in the palette + for (size_t j = 0; j < palette.size(); ++j) { + gfx::SNESColor color = palette[j]; + + // If the color is modified, save the color to the ROM + if (color.modified) { + WriteColor(GetPaletteAddress(groupName, i, j), color); + color.modified = false; // Reset the modified flag after saving + } + } + } + } +} + +void ROM::WriteColor(uint32_t address, const gfx::SNESColor& color) { + uint16_t bgr = ((color.snes >> 10) & 0x1F) | ((color.snes & 0x1F) << 10) | + (color.snes & 0x7C00); + + // Write the 16-bit color value to the ROM at the specified address + rom_data_[address] = static_cast(bgr & 0xFF); + rom_data_[address + 1] = static_cast((bgr >> 8) & 0xFF); +} + +uint32_t ROM::GetPaletteAddress(const std::string& groupName, + size_t paletteIndex, size_t colorIndex) const { + // Retrieve the base address for the palette group + uint32_t baseAddress = paletteGroupBaseAddresses.at(groupName); + + // Retrieve the number of colors for each palette in the group + size_t colorsPerPalette = paletteGroupColorCounts.at(groupName); + + // Calculate the address for the specified color in the ROM + uint32_t address = + baseAddress + (paletteIndex * colorsPerPalette * 2) + (colorIndex * 2); + + return address; +} + // ============================================================================ absl::Status ROM::ApplyAssembly(const absl::string_view& filename, diff --git a/src/app/rom.h b/src/app/rom.h index b4bfc614..e83c4160 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,48 @@ struct CompressionPiece { using CompressionPiece = struct CompressionPiece; using CompressionPiecePointer = std::shared_ptr; +const std::map paletteGroupBaseAddresses = { + {"ow_main", core::overworldPaletteMain}, + {"ow_aux", core::overworldPaletteAuxialiary}, + {"ow_animated", core::overworldPaletteAnimated}, + {"hud", core::hudPalettes}, + {"global_sprites", + core::globalSpritePalettesLW}, // Assuming LW is the first palette + {"armors", core::armorPalettes}, + {"swords", core::swordPalettes}, + {"shields", core::shieldPalettes}, + {"sprites_aux1", core::spritePalettesAux1}, + {"sprites_aux2", core::spritePalettesAux2}, + {"sprites_aux3", core::spritePalettesAux3}, + {"dungeon_main", core::dungeonMainPalettes}, + {"grass", core::hardcodedGrassLW}, // Assuming LW is the first color + {"3d_object", + core::triforcePalette}, // Assuming triforcePalette is the first palette + {"ow_mini_map", core::overworldMiniMapPalettes}, +}; + +const std::map paletteGroupColorCounts = { + {"ow_main", 35}, + {"ow_aux", 21}, + {"ow_animated", 7}, + {"hud", 32}, + {"global_sprites", 60}, // Assuming both LW and DW + // palettes have the same + // color count + {"armors", 15}, + {"swords", 3}, + {"shields", 4}, + {"sprites_aux1", 7}, + {"sprites_aux2", 7}, + {"sprites_aux3", 7}, + {"dungeon_main", 90}, + {"grass", 1}, // Assuming grass palettes are + // individual colors + {"3d_object", 8}, // Assuming both triforcePalette and crystalPalette have + // the same color count + {"ow_mini_map", 128}, +}; + class ROM { public: absl::StatusOr Compress(const int start, const int length, @@ -91,6 +134,11 @@ class ROM { absl::Status LoadFromBytes(const Bytes& data); void LoadAllPalettes(); + void SaveAllPalettes(); + + uint32_t GetPaletteAddress(const std::string& groupName, size_t paletteIndex, + size_t colorIndex) const; + absl::Status SaveToFile(); gfx::SNESColor ReadColor(int offset); @@ -98,6 +146,7 @@ class ROM { void Write(int addr, int value); void WriteShort(int addr, int value); + void WriteColor(uint32_t address, const gfx::SNESColor& color); absl::Status ApplyAssembly(const absl::string_view& filename, size_t patch_size); diff --git a/test/delta_test.cc b/test/delta_test.cc deleted file mode 100644 index a4db2f78..00000000 --- a/test/delta_test.cc +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "app/core/constants.h" -#include "app/delta/client.h" -#include "app/delta/service.h" -#include "app/rom.h" -#include "src/app/delta/delta.grpc.pb.h" -#include "src/app/delta/delta.pb.h" - -namespace yaze_test { -namespace delta_test { - -TEST(DeltaTest, InitRepoAndPushOk) { - yaze::app::delta::DeltaService service; - yaze::app::ROM rom; - Bytes test_bytes; - test_bytes.push_back(0x40); - EXPECT_TRUE(rom.LoadFromBytes(test_bytes).ok()); - grpc::ServerContext* context; - InitRequest init_request; - auto repo = init_request.mutable_repo(); - repo->set_project_name("test_repo"); - Branch branch; - branch.set_branch_name("test_branch"); - auto new_mutable_commits = branch.mutable_commits(); - new_mutable_commits->Reserve(5); - for (int i = 0; i < 5; ++i) { - auto new_commit = new Commit(); - new_commit->set_commit_id(i); - new_mutable_commits->Add(); - new_mutable_commits->at(i) = *new_commit; - } - auto mutable_tree = repo->mutable_tree(); - mutable_tree->Add(); - mutable_tree->at(0) = branch; - InitResponse init_response; - auto init_status = service.Init(context, &init_request, &init_response); - EXPECT_TRUE(init_status.ok()); - - PushRequest request; - request.set_branch_name("test_branch"); - request.set_repository_name("test_repo"); - auto mutable_commits = request.mutable_commits(); - mutable_commits->Reserve(5); - for (int i = 0; i < 5; ++i) { - auto new_commit = new Commit(); - new_commit->set_commit_id(i * 2); - mutable_commits->Add(); - mutable_commits->at(i) = *new_commit; - } - PushResponse reply; - auto status = service.Push(context, &request, &reply); - EXPECT_TRUE(status.ok()); - - auto repos = service.Repos(); - auto result_branch = repos.at(0).tree(); - std::cerr << result_branch.at(0).DebugString() << std::endl; -} - -} // namespace delta_test -} // namespace yaze_test \ No newline at end of file