Update PaletteEditor, remove Delta experiment

This commit is contained in:
scawful
2023-05-15 08:23:13 -05:00
parent 3abfaf3336
commit 46fe8993ea
18 changed files with 247 additions and 852 deletions

View File

@@ -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}")
endif()

View File

@@ -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;

View File

@@ -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}"
)

View File

@@ -1,54 +0,0 @@
#include "client.h"
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#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

View File

@@ -1,44 +0,0 @@
#ifndef YAZE_APP_DELTA_CLIENT_H
#define YAZE_APP_DELTA_CLIENT_H
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#include <vector>
#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<Repository> repos_;
std::unique_ptr<YazeDelta::Stub> stub_;
};
} // namespace delta
} // namespace app
} // namespace yaze
#endif

View File

@@ -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;
}

View File

@@ -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 {}

View File

@@ -1,87 +0,0 @@
#include "service.h"
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#include <fstream>
#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<Repository>& repos, const std::string& name) {
for (auto& repo : repos) {
if (repo.project_name() == name) {
return repo.mutable_tree();
}
}
}
auto FindBranch(google::protobuf::RepeatedPtrField<Branch>* 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

View File

@@ -1,48 +0,0 @@
#ifndef YAZE_APP_DELTA_SERVICE_H
#define YAZE_APP_DELTA_SERVICE_H
#include <filesystem>
#include <google/protobuf/message.h>
#include <grpc/support/log.h>
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
#include <vector>
#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<Repository> repos_;
};
} // namespace delta
} // namespace app
} // namespace yaze
#endif

View File

@@ -1,229 +0,0 @@
#include "viewer.h"
#include <ImGuiColorTextEdit/TextEditor.h>
#include <ImGuiFileDialog/ImGuiFileDialog.h>
#include <imgui/imgui.h>
#include <imgui/misc/cpp/imgui_stdlib.h>
#include <imgui_memory_editor.h>
#include "absl/status/status.h"
#include "app/core/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

View File

@@ -1,45 +0,0 @@
#ifndef YAZE_APP_DELTA_VIEWER_H
#define YAZE_APP_DELTA_VIEWER_H
#include <ImGuiColorTextEdit/TextEditor.h>
#include <ImGuiFileDialog/ImGuiFileDialog.h>
#include <imgui/imgui.h>
#include <imgui/misc/cpp/imgui_stdlib.h>
#include <imgui_memory_editor.h>
#include "absl/status/status.h"
#include "app/core/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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View File

@@ -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<float> 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<SNESColor> 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<SNESPalette> palettes;
};

View File

@@ -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<uint8_t>(bgr & 0xFF);
rom_data_[address + 1] = static_cast<uint8_t>((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,

View File

@@ -9,6 +9,7 @@
#include <filesystem>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
@@ -72,6 +73,48 @@ struct CompressionPiece {
using CompressionPiece = struct CompressionPiece;
using CompressionPiecePointer = std::shared_ptr<CompressionPiece>;
const std::map<std::string, uint32_t> 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<std::string, size_t> 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<Bytes> 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);

View File

@@ -1,74 +0,0 @@
#include <asar/interface-lib.h>
#include <gmock/gmock.h>
#include <google/protobuf/repeated_field.h>
#include <gtest/gtest.h>
#include <array>
#include <cstdint>
#include <fstream>
#include <sstream>
#include <string>
#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