Update GraphicsEditor, fix CommandHandler

This commit is contained in:
scawful
2023-11-26 23:12:04 -05:00
parent 620fc934ba
commit 0bf45c86a9
11 changed files with 224 additions and 47 deletions

View File

@@ -53,18 +53,17 @@ absl::Status GraphicsEditor::UpdateGfxEdit() {
ImGui::TableHeadersRow();
NEXT_COLUMN();
UpdateGfxSheetList();
status_ = UpdateGfxSheetList();
NEXT_COLUMN() {
if (rom()->isLoaded()) {
status_ = UpdateGfxTabView();
}
NEXT_COLUMN();
if (rom()->isLoaded()) {
DrawGfxEditToolset();
status_ = UpdateGfxTabView();
}
NEXT_COLUMN() {
if (rom()->isLoaded()) {
status_ = UpdatePaletteColumn();
}
NEXT_COLUMN();
if (rom()->isLoaded()) {
status_ = UpdatePaletteColumn();
}
}
ImGui::EndTable();
@@ -73,6 +72,52 @@ absl::Status GraphicsEditor::UpdateGfxEdit() {
return absl::OkStatus();
}
void GraphicsEditor::DrawGfxEditToolset() {
if (ImGui::BeginTable("##GfxEditToolset", 7, ImGuiTableFlags_SizingFixedFit,
ImVec2(0, 0))) {
for (const auto& name : {"Select", "Pencil", "Fill", "Zoom Out", "Zoom In",
"Current Color", "Tile Size"})
ImGui::TableSetupColumn(name);
ImGui::TableNextColumn();
if (ImGui::Button(ICON_MD_SELECT_ALL)) {
}
ImGui::TableNextColumn();
if (ImGui::Button(ICON_MD_DRAW)) {
}
ImGui::TableNextColumn();
if (ImGui::Button(ICON_MD_FORMAT_COLOR_FILL)) {
}
ImGui::TableNextColumn();
if (ImGui::Button(ICON_MD_ZOOM_OUT)) {
if (current_scale_ >= 0.0f) {
current_scale_ -= 1.0f;
}
}
ImGui::TableNextColumn();
if (ImGui::Button(ICON_MD_ZOOM_IN)) {
if (current_scale_ <= 8.0f) {
current_scale_ += 1.0f;
}
}
ImGui::TableNextColumn();
ImGui::ColorEdit4("Palette Color", (float*)&current_color_,
ImGuiColorEditFlags_NoInputs |
ImGuiColorEditFlags_NoLabel |
ImGuiColorEditFlags_NoAlpha);
ImGui::TableNextColumn();
gui::InputHexByte("Tile Size", &tile_size_, 0x02);
ImGui::EndTable();
}
}
absl::Status GraphicsEditor::UpdateGfxSheetList() {
ImGui::BeginChild(
"##GfxEditChild", ImVec2(0, 0), true,
@@ -115,7 +160,8 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
absl::StrFormat("%02X", key).c_str());
}
},
ImVec2(0x100 + 1, 0x40 + 1), 0x20, 16.0f);
ImVec2(0x100 + 1, 0x40 + 1), 0x20, /*scale=*/1.0f,
/*grid_size=*/16.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::EndChild();
}
@@ -132,12 +178,11 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
ImGuiTabBarFlags_Reorderable |
ImGuiTabBarFlags_FittingPolicyResizeDown |
ImGuiTabBarFlags_TabListPopupButton)) {
// TODO: Manage the room that is being added to the tab bar.
if (ImGui::TabItemButton(
"+", ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable |
ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter |
ImGuiTableFlags_BordersV)) {
open_sheets_.insert(next_tab_id++); // Add new tab
open_sheets_.insert(next_tab_id++);
}
// Submit our regular tabs
@@ -151,9 +196,22 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
ImVec2(0, 0), true,
ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_AlwaysVerticalScrollbar);
current_sheet_canvas_.Update(*rom()->bitmap_manager()[each],
ImVec2(0x100 + 1, 0x40 + 1), 0x20, 4.0f,
16.0f);
current_sheet_ = each;
current_sheet_canvas_.UpdateColorPainter(
*rom()->bitmap_manager()[each], current_color_,
[&]() {
int position =
current_sheet_canvas_.GetCurrentDrawnTilePosition().x +
(current_sheet_canvas_.GetCurrentDrawnTilePosition().y *
0x20 * 8);
gfx::SNESColor color(current_color_);
rom()->bitmap_manager()[each]->WriteWordToPixel(position,
color.GetSNES());
rom()->UpdateBitmap(
rom()->mutable_bitmap_manager()->mutable_bitmap(each).get());
},
ImVec2(0x100 + 1, 0x40 + 1), tile_size_ * current_scale_,
current_scale_, 16.0f);
ImGui::EndChild();
ImGui::EndTabItem();
@@ -174,21 +232,32 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
}
absl::Status GraphicsEditor::UpdatePaletteColumn() {
auto palette_group = rom()->GetPaletteGroup(
kPaletteGroupAddressesKeys[edit_palette_group_name_index_]);
auto palette = palette_group[edit_palette_index_];
if (rom()->isLoaded()) {
gui::TextWithSeparators("ROM Palette");
ImGui::Combo("Palette", (int*)&edit_palette_group_,
ImGui::SetNextItemWidth(100.f);
ImGui::Combo("Palette Group", (int*)&edit_palette_group_name_index_,
kPaletteGroupAddressesKeys,
IM_ARRAYSIZE(kPaletteGroupAddressesKeys));
gui::InputHex("Palette Index", &edit_palette_index_);
ImGui::SetNextItemWidth(100.f);
gui::InputHex("Palette Group Index", &edit_palette_index_);
}
auto palette_group = rom()->mutable_palette_group(
kPaletteGroupAddressesKeys[edit_palette_group_])
[edit_palette_group_index_];
auto palette = palette_group[edit_palette_index_];
gui::SelectablePalettePipeline(edit_palette_index_, refresh_graphics_,
gui::SelectablePalettePipeline(edit_palette_sub_index_, refresh_graphics_,
palette);
if (refresh_graphics_) {
rom()->bitmap_manager()[current_sheet_]->ApplyPaletteWithTransparent(
palette, edit_palette_sub_index_);
rom()->UpdateBitmap(
rom()->mutable_bitmap_manager()->mutable_bitmap(current_sheet_).get());
refresh_graphics_ = false;
}
return absl::OkStatus();
}
@@ -202,11 +271,8 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() {
RETURN_IF_ERROR(rom()->LoadLinkGraphics());
// Split it into the pose data frames
// Create an animation step display for the poses
// Allow the user to modify the frames used in an anim step
// LinkOAM_AnimationSteps:
// #_0D85FB

View File

@@ -67,9 +67,9 @@ class GraphicsEditor : public SharedROM {
absl::Status Update();
private:
// Graphics Editor Tab
absl::Status UpdateGfxEdit();
void DrawGfxEditToolset();
absl::Status UpdateGfxSheetList();
absl::Status UpdateGfxTabView();
absl::Status UpdatePaletteColumn();
@@ -97,14 +97,19 @@ class GraphicsEditor : public SharedROM {
absl::Status DecompressSuperDonkey();
ImVec4 current_color_;
uint16_t current_sheet_ = 0;
uint8_t tile_size_ = 0x04;
std::set<uint16_t> open_sheets_;
std::stack<uint16_t> release_queue_;
uint64_t edit_palette_group_ = 0;
uint64_t edit_palette_group_name_index_ = 0;
uint64_t edit_palette_group_index_ = 0;
uint64_t edit_palette_index_ = 0;
uint64_t edit_palette_sub_index_ = 0;
float sheet_scale_ = 2.0f;
float current_scale_ = 4.0f;
// Prototype Graphics Viewer
int current_palette_ = 0;
uint64_t current_offset_ = 0;
uint64_t current_size_ = 0;

View File

@@ -163,6 +163,28 @@ void Bitmap::ApplyPalette(const SNESPalette &palette) {
SDL_LockSurface(surface_.get());
}
void Bitmap::ApplyPaletteWithTransparent(const SNESPalette &palette,
int index) {
palette_ = palette;
auto start_index = index * 7;
std::vector<ImVec4> colors;
colors.push_back(ImVec4(0, 0, 0, 0));
for (int i = start_index; i < start_index + 7; ++i) {
colors.push_back(palette.GetColor(i).GetRGB());
}
SDL_UnlockSurface(surface_.get());
int i = 0;
for (auto &each : colors) {
surface_->format->palette->colors[i].r = each.x;
surface_->format->palette->colors[i].g = each.y;
surface_->format->palette->colors[i].b = each.z;
surface_->format->palette->colors[i].a = each.w;
i++;
}
SDL_LockSurface(surface_.get());
}
void Bitmap::ApplyPalette(const std::vector<SDL_Color> &palette) {
SDL_UnlockSurface(surface_.get());
for (int i = 0; i < palette.size(); ++i) {

View File

@@ -24,7 +24,6 @@ class Bitmap {
Bitmap(int width, int height, int depth, int data_size);
Bitmap(int width, int height, int depth, const Bytes &data)
: width_(width), height_(height), depth_(depth), data_(data) {
// CreateTextureFromData();
InitializeFromData(width, height, depth, data);
}
@@ -42,20 +41,21 @@ class Bitmap {
void Create(int width, int height, int depth, int data_size);
void Create(int width, int height, int depth, const Bytes &data);
void InitializeFromData(uint32_t width, uint32_t height,
uint32_t depth, const Bytes &data);
void InitializeFromData(uint32_t width, uint32_t height, uint32_t depth,
const Bytes &data);
void ReserveData(uint32_t width, uint32_t height, uint32_t depth,
uint32_t size);
void CreateTexture(std::shared_ptr<SDL_Renderer> renderer);
void UpdateTexture(std::shared_ptr<SDL_Renderer> renderer);
void CreateTexture(SDL_Renderer* renderer);
void UpdateTexture(SDL_Renderer* renderer);
void CreateTexture(SDL_Renderer *renderer);
void UpdateTexture(SDL_Renderer *renderer);
void SaveSurfaceToFile(std::string_view filename);
void SetSurface(SDL_Surface *surface);
void ApplyPalette(const SNESPalette &palette);
void ApplyPaletteWithTransparent(const SNESPalette &palette, int index);
void ApplyPalette(const std::vector<SDL_Color> &palette);
void WriteToPixel(int position, uchar value) {
@@ -66,6 +66,15 @@ class Bitmap {
modified_ = true;
}
void WriteWordToPixel(int position, uint16_t value) {
if (pixel_data_ == nullptr) {
pixel_data_ = data_.data();
}
this->pixel_data_[position] = value & 0xFF;
this->pixel_data_[position + 1] = (value >> 8) & 0xFF;
modified_ = true;
}
void Cleanup() {
// Reset texture_
if (texture_) {
@@ -171,6 +180,8 @@ class BitmapManager {
return nullptr;
}
auto mutable_bitmap(int id) { return bitmap_cache_[id]; }
using value_type = std::pair<const int, std::shared_ptr<gfx::Bitmap>>;
using iterator =
std::unordered_map<int, std::shared_ptr<gfx::Bitmap>>::iterator;

View File

@@ -19,16 +19,38 @@ constexpr ImGuiButtonFlags kMouseFlags =
void Canvas::Update(const gfx::Bitmap &bitmap, ImVec2 bg_size, int tile_size,
float scale, float grid_size) {
if (scale != 1.0f) {
bg_size.x *= scale / 2;
bg_size.y *= scale / 2;
}
DrawBackground(bg_size);
DrawContextMenu();
DrawTileSelector(tile_size);
DrawBitmap(bitmap, 0, 0, scale);
DrawBitmap(bitmap, 2, scale);
DrawGrid(grid_size);
DrawOverlay();
}
void Canvas::UpdateColorPainter(const gfx::Bitmap &bitmap, const ImVec4 &color,
const std::function<void()> &event,
ImVec2 bg_size, int tile_size, float scale,
float grid_size) {
if (scale != 1.0f) {
bg_size.x *= scale / 2;
bg_size.y *= scale / 2;
}
DrawBackground(bg_size);
DrawContextMenu();
DrawBitmap(bitmap, 2, scale);
if (DrawSolidTilePainter(color, tile_size)) {
event();
}
DrawGrid(grid_size);
DrawOverlay();
}
void Canvas::UpdateEvent(const std::function<void()> &event, ImVec2 bg_size,
int tile_size, float grid_size) {
int tile_size, float scale, float grid_size) {
DrawBackground(bg_size);
DrawContextMenu();
event();
@@ -123,6 +145,47 @@ bool Canvas::DrawTilePainter(const Bitmap &bitmap, int size, float scale) {
return false;
}
bool Canvas::DrawSolidTilePainter(const ImVec4 &color, int size) {
const ImGuiIO &io = ImGui::GetIO();
const bool is_hovered = ImGui::IsItemHovered();
is_hovered_ = is_hovered;
// Lock scrolled origin
const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y);
const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
if (is_hovered) {
// Reset the previous tile hover
if (!points_.empty()) {
points_.clear();
}
// Calculate the coordinates of the mouse
ImVec2 painter_pos;
painter_pos.x = std::floor((double)mouse_pos.x / size) * size;
painter_pos.y = std::floor((double)mouse_pos.y / size) * size;
auto painter_pos_end = ImVec2(painter_pos.x + size, painter_pos.y + size);
points_.push_back(painter_pos);
points_.push_back(painter_pos_end);
draw_list_->AddRectFilled(
ImVec2(origin.x + painter_pos.x, origin.y + painter_pos.y),
ImVec2(origin.x + painter_pos.x + size,
origin.y + painter_pos.y + size),
IM_COL32(color.x * 255, color.y * 255, color.z * 255, 255));
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
drawn_tile_pos_ = painter_pos;
return true;
}
} else {
// Erase the hover when the mouse is not in the canvas window.
points_.clear();
}
return false;
}
void Canvas::DrawTileSelector(int size) {
const ImGuiIO &io = ImGui::GetIO();
const bool is_hovered = ImGui::IsItemHovered(); // Hovered
@@ -196,6 +259,14 @@ void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, bool ready) {
}
}
void Canvas::DrawBitmap(const Bitmap &bitmap, int border_offset, float scale) {
draw_list_->AddImage(
(void *)bitmap.texture(),
ImVec2(canvas_p0_.x + border_offset, canvas_p0_.y + border_offset),
ImVec2(canvas_p0_.x + (bitmap.width() * scale),
canvas_p0_.y + (bitmap.height() * scale)));
}
void Canvas::DrawBitmap(const Bitmap &bitmap, int x_offset, int y_offset,
float scale) {
draw_list_->AddImage(

View File

@@ -25,8 +25,13 @@ class Canvas {
void Update(const gfx::Bitmap& bitmap, ImVec2 bg_size, int tile_size,
float scale = 1.0f, float grid_size = 64.0f);
void UpdateColorPainter(const gfx::Bitmap& bitmap, const ImVec4& color,
const std::function<void()>& event, ImVec2 bg_size,
int tile_size, float scale = 1.0f,
float grid_size = 64.0f);
void UpdateEvent(const std::function<void()>& event, ImVec2 bg_size,
int tile_size, float grid_size = 64.0f);
int tile_size, float scale = 1.0f, float grid_size = 64.0f);
// Background for the Canvas represents region without any content drawn to
// it, but can be controlled by the user.
@@ -40,6 +45,7 @@ class Canvas {
// and allows the user to left click to paint the tile or right
// click to select a new tile to paint with.
bool DrawTilePainter(const Bitmap& bitmap, int size, float scale = 1.0f);
bool DrawSolidTilePainter(const ImVec4& color, int size);
// Dictates which tile is currently selected based on what the user clicks
// in the canvas window. Represented and split apart into a grid of tiles.
@@ -56,6 +62,7 @@ class Canvas {
// Draws the contents of the Bitmap image to the Canvas
void DrawBitmap(const Bitmap& bitmap, int border_offset = 0,
bool ready = true);
void DrawBitmap(const Bitmap& bitmap, int border_offset, float scale);
void DrawBitmap(const Bitmap& bitmap, int x_offset = 0, int y_offset = 0,
float scale = 1.0f);

View File

@@ -126,8 +126,9 @@ bool InputHexWord(const char* label, uint16_t* data, float input_width) {
ImGuiInputTextFlags_CharsHexadecimal);
}
bool InputHexByte(const char* label, uint8_t* data, float input_width) {
return ImGui::InputScalarLeft(label, ImGuiDataType_U8, data, &kStepOneHex,
bool InputHexByte(const char* label, uint8_t* data, uint8_t step,
float input_width) {
return ImGui::InputScalarLeft(label, ImGuiDataType_U8, data, &step,
&kStepFastHex, "%02X", input_width,
ImGuiInputTextFlags_CharsHexadecimal);
}

View File

@@ -19,7 +19,7 @@ IMGUI_API bool InputHex(const char* label, uint64_t* data);
IMGUI_API bool InputHexShort(const char* label, uint32_t* data);
IMGUI_API bool InputHexWord(const char* label, uint16_t* data,
float input_width = 50.f);
IMGUI_API bool InputHexByte(const char* label, uint8_t* data,
IMGUI_API bool InputHexByte(const char* label, uint8_t* data, uint8_t step = 0x01,
float input_width = 50.f);
using ItemLabelFlags = enum ItemLabelFlag {

View File

@@ -29,12 +29,6 @@ void SelectablePalettePipeline(uint64_t& palette_id, bool& refresh_graphics,
ImGui::BeginGroup(); // Lock X position
ImGui::Text("Palette");
for (int n = 0; n < palette.size(); n++) {
// static gfx::SNESColor transparent_color;
// if ((n % 8) == 0) {
// gui::SNESColorButton("##transparent", transparent_color, 0,
// ImVec2(20, 20));
// ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
// }
ImGui::PushID(n);
if ((n % 7) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);

View File

@@ -425,6 +425,8 @@ class ROM : public core::ExperimentFlags {
gfx::Bitmap* mutable_graphics_sheet(int index) {
return &graphics_bin_.at(index);
}
auto bitmap_manager() { return graphics_manager_; }
auto mutable_bitmap_manager() { return &graphics_manager_; }
auto title() const { return title_; }
auto size() const { return size_; }
@@ -499,8 +501,6 @@ class ROM : public core::ExperimentFlags {
std::stack<gfx::Bitmap*> bitmaps_to_create_;
std::stack<gfx::Bitmap*> bitmaps_to_render_;
auto bitmap_manager() { return graphics_manager_; }
std::vector<std::vector<uint8_t>> main_blockset_ids;
std::vector<std::vector<uint8_t>> room_blockset_ids;
std::vector<std::vector<uint8_t>> spriteset_ids;