Refactor Tile16Editor for improved tile selection and palette synchronization

- Adjusted tile8 source canvas dimensions for better scaling in Tile16Editor.
- Enhanced click detection and selection logic for tile editing, ensuring a smoother user experience.
- Implemented critical fixes for palette application consistency, aligning with the overworld palette for accurate color representation.
- Improved logging for tile interactions and palette updates to facilitate debugging and user feedback.
This commit is contained in:
scawful
2025-09-29 11:11:27 -04:00
parent c7aa0f4409
commit 2d3a615fb4
2 changed files with 125 additions and 99 deletions

View File

@@ -34,7 +34,7 @@ absl::Status Tile16Editor::Initialize(
// Copy the graphics bitmap (palette will be set later by overworld editor)
current_gfx_bmp_.Create(current_gfx_bmp.width(), current_gfx_bmp.height(),
current_gfx_bmp.depth(), current_gfx_bmp.vector());
current_gfx_bmp_.SetPalette(current_gfx_bmp.palette()); // Temporary palette
current_gfx_bmp_.SetPalette(current_gfx_bmp.palette()); // Temporary palette
core::Renderer::Get().RenderBitmap(&current_gfx_bmp_);
// Copy the tile16 blockset bitmap
@@ -286,7 +286,8 @@ absl::Status Tile16Editor::UpdateBlockset() {
blockset_canvas_.DrawTileSelector(32.0f);
// Then check for single click to update tile selection
if (ImGui::IsItemClicked(ImGuiMouseButton_Left) && blockset_canvas_.IsMouseHovering()) {
if (ImGui::IsItemClicked(ImGuiMouseButton_Left) &&
blockset_canvas_.IsMouseHovering()) {
tile_selected = true;
}
@@ -294,14 +295,16 @@ absl::Status Tile16Editor::UpdateBlockset() {
// Get mouse position relative to canvas
const ImGuiIO& io = ImGui::GetIO();
ImVec2 canvas_pos = blockset_canvas_.zero_point();
ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
ImVec2 mouse_pos =
ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
// Calculate grid position (32x32 tiles in blockset)
int grid_x = static_cast<int>(mouse_pos.x / 32);
int grid_y = static_cast<int>(mouse_pos.y / 32);
int selected_tile = grid_x + grid_y * 8; // 8 tiles per row in blockset
int selected_tile = grid_x + grid_y * 8; // 8 tiles per row in blockset
if (selected_tile != current_tile16_ && selected_tile >= 0 && selected_tile < 512) {
if (selected_tile != current_tile16_ && selected_tile >= 0 &&
selected_tile < 512) {
RETURN_IF_ERROR(SetCurrentTile(selected_tile));
util::logf("Selected Tile16 from blockset: %d (grid: %d,%d)",
selected_tile, grid_x, grid_y);
@@ -377,7 +380,8 @@ absl::Status Tile16Editor::UpdateBlocksetBitmap() {
// Use optimized batch operations for better performance
if (tile16_blockset_bmp_.is_active() && current_tile16_bmp_.is_active()) {
// Calculate the position of this tile in the blockset bitmap
constexpr int kTilesPerRow = 8; // Standard SNES tile16 layout is 8 tiles per row
constexpr int kTilesPerRow =
8; // Standard SNES tile16 layout is 8 tiles per row
int tile_x = (current_tile16_ % kTilesPerRow) * kTile16Size;
int tile_y = (current_tile16_ / kTilesPerRow) * kTile16Size;
@@ -386,10 +390,12 @@ absl::Status Tile16Editor::UpdateBlocksetBitmap() {
// Copy pixel data from current tile to blockset bitmap using batch operations
for (int tile_y_offset = 0; tile_y_offset < kTile16Size; ++tile_y_offset) {
for (int tile_x_offset = 0; tile_x_offset < kTile16Size; ++tile_x_offset) {
for (int tile_x_offset = 0; tile_x_offset < kTile16Size;
++tile_x_offset) {
int src_index = tile_y_offset * kTile16Size + tile_x_offset;
int dst_index = (tile_y + tile_y_offset) * tile16_blockset_bmp_.width() +
(tile_x + tile_x_offset);
int dst_index =
(tile_y + tile_y_offset) * tile16_blockset_bmp_.width() +
(tile_x + tile_x_offset);
if (src_index < static_cast<int>(current_tile16_bmp_.size()) &&
dst_index < static_cast<int>(tile16_blockset_bmp_.size())) {
@@ -401,20 +407,24 @@ absl::Status Tile16Editor::UpdateBlocksetBitmap() {
// Mark the blockset bitmap as modified and use batch texture update
tile16_blockset_bmp_.set_modified(true);
tile16_blockset_bmp_.QueueTextureUpdate(nullptr); // Use batch operations
tile16_blockset_bmp_.QueueTextureUpdate(nullptr); // Use batch operations
// Also update the tile16 blockset atlas if available
if (tile16_blockset_->atlas.is_active()) {
// Update the atlas with the new tile data
for (int tile_y_offset = 0; tile_y_offset < kTile16Size; ++tile_y_offset) {
for (int tile_x_offset = 0; tile_x_offset < kTile16Size; ++tile_x_offset) {
for (int tile_y_offset = 0; tile_y_offset < kTile16Size;
++tile_y_offset) {
for (int tile_x_offset = 0; tile_x_offset < kTile16Size;
++tile_x_offset) {
int src_index = tile_y_offset * kTile16Size + tile_x_offset;
int dst_index = (tile_y + tile_y_offset) * tile16_blockset_->atlas.width() +
(tile_x + tile_x_offset);
int dst_index =
(tile_y + tile_y_offset) * tile16_blockset_->atlas.width() +
(tile_x + tile_x_offset);
if (src_index < static_cast<int>(current_tile16_bmp_.size()) &&
dst_index < static_cast<int>(tile16_blockset_->atlas.size())) {
tile16_blockset_->atlas.WriteToPixel(dst_index, current_tile16_bmp_.data()[src_index]);
tile16_blockset_->atlas.WriteToPixel(
dst_index, current_tile16_bmp_.data()[src_index]);
}
}
}
@@ -702,52 +712,54 @@ absl::Status Tile16Editor::UpdateTile16Edit() {
}
// Streamlined tile8 canvas with scrolling
if (ImGui::BeginChild(
"##Tile8ScrollRegion",
ImVec2(tile8_source_canvas_.width(), tile8_source_canvas_.height()),
true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
tile8_source_canvas_.set_draggable(false);
// CRITICAL FIX: Don't use draggable mode as it conflicts with tile selection
tile8_source_canvas_.set_draggable(false);
tile8_source_canvas_.DrawBackground();
tile8_source_canvas_.DrawContextMenu();
gui::BeginPadding(2);
gui::BeginChildWithScrollbar("##Tile8EditorBlocksetScrollRegion");
// CRITICAL FIX: Don't use draggable mode as it conflicts with tile selection
tile8_source_canvas_.DrawBackground();
gui::EndPadding();
tile8_source_canvas_.DrawContextMenu();
// Tile8 selection with improved feedback
bool tile8_selected = false;
tile8_source_canvas_.DrawTileSelector(32.0F);
// Tile8 selection with improved feedback
bool tile8_selected = false;
tile8_source_canvas_.DrawTileSelector(32.0F);
// Check for clicks properly
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
tile8_selected = true;
}
if (tile8_selected) {
// Get mouse position relative to canvas more accurately
const ImGuiIO& io = ImGui::GetIO();
ImVec2 canvas_pos = tile8_source_canvas_.zero_point();
ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
// Account for the 4x scale when calculating tile position
int tile_x = static_cast<int>(mouse_pos.x / (8 * 4)); // 8 pixel tile * 4x scale = 32 pixels per tile
int tile_y = static_cast<int>(mouse_pos.y / (8 * 4));
// Calculate tiles per row based on bitmap width (should be 16 for 128px wide bitmap)
int tiles_per_row = current_gfx_bmp_.width() / 8;
int new_tile8 = tile_x + (tile_y * tiles_per_row);
if (new_tile8 != current_tile8_ && new_tile8 >= 0 &&
new_tile8 < static_cast<int>(current_gfx_individual_.size()) &&
current_gfx_individual_[new_tile8].is_active()) {
current_tile8_ = new_tile8;
RETURN_IF_ERROR(UpdateTile8Palette(current_tile8_));
util::logf("Selected Tile8: %d", current_tile8_);
}
}
tile8_source_canvas_.DrawBitmap(current_gfx_bmp_, 2, 2, 4.0F);
tile8_source_canvas_.DrawGrid();
tile8_source_canvas_.DrawOverlay();
// Check for clicks properly
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
tile8_selected = true;
}
if (tile8_selected) {
// Get mouse position relative to canvas more accurately
const ImGuiIO& io = ImGui::GetIO();
ImVec2 canvas_pos = tile8_source_canvas_.zero_point();
ImVec2 mouse_pos =
ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
// Account for the 4x scale when calculating tile position
int tile_x = static_cast<int>(
mouse_pos.x /
(8 * 4)); // 8 pixel tile * 4x scale = 32 pixels per tile
int tile_y = static_cast<int>(mouse_pos.y / (8 * 4));
// Calculate tiles per row based on bitmap width (should be 16 for 128px wide bitmap)
int tiles_per_row = current_gfx_bmp_.width() / 8;
int new_tile8 = tile_x + (tile_y * tiles_per_row);
if (new_tile8 != current_tile8_ && new_tile8 >= 0 &&
new_tile8 < static_cast<int>(current_gfx_individual_.size()) &&
current_gfx_individual_[new_tile8].is_active()) {
current_tile8_ = new_tile8;
RETURN_IF_ERROR(UpdateTile8Palette(current_tile8_));
util::logf("Selected Tile8: %d", current_tile8_);
}
}
tile8_source_canvas_.DrawBitmap(current_gfx_bmp_, 2, 2, 4.0F);
tile8_source_canvas_.DrawGrid();
tile8_source_canvas_.DrawOverlay();
EndChild();
// Tile16 editor column - compact and focused
@@ -811,7 +823,8 @@ absl::Status Tile16Editor::UpdateTile16Edit() {
// Get mouse position relative to tile16 canvas
const ImGuiIO& io = ImGui::GetIO();
ImVec2 canvas_pos = tile16_edit_canvas_.zero_point();
ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x,
io.MousePos.y - canvas_pos.y);
// Convert canvas coordinates to tile16 coordinates (0-15 range)
// The canvas is 64x64 display pixels showing a 16x16 tile at 4x scale
@@ -828,7 +841,8 @@ absl::Status Tile16Editor::UpdateTile16Edit() {
// Pass the flipped tile if we created one, otherwise pass nullptr to use original with flips
const gfx::Bitmap* tile_to_draw =
(x_flip || y_flip) ? tile_to_paint : nullptr;
RETURN_IF_ERROR(DrawToCurrentTile16(ImVec2(tile_x, tile_y), tile_to_draw));
RETURN_IF_ERROR(
DrawToCurrentTile16(ImVec2(tile_x, tile_y), tile_to_draw));
}
}
@@ -1091,7 +1105,10 @@ absl::Status Tile16Editor::SetCurrentTile(int tile_id) {
// CRITICAL FIX: Use the same complete palette that the overworld uses
// This ensures tile16 editor colors match the overworld exactly
auto overworld_palette = rom()->palette_group().overworld_main[0]; // Get the current overworld palette
auto overworld_palette =
rom()
->palette_group()
.overworld_main[0]; // Get the current overworld palette
if (overworld_palette.size() > 0) {
current_tile16_bmp_.SetPalette(overworld_palette);
}
@@ -1349,7 +1366,8 @@ absl::Status Tile16Editor::CyclePalette(bool forward) {
// Apply the selected palette to all graphics consistently
current_gfx_bmp_.SetPaletteWithTransparent(main_palette, current_palette_);
current_tile16_bmp_.SetPaletteWithTransparent(main_palette, current_palette_);
current_tile16_bmp_.SetPaletteWithTransparent(main_palette,
current_palette_);
// Update individual tile8 graphics with the same palette coordination
for (auto& tile_gfx : current_gfx_individual_) {
@@ -1362,7 +1380,8 @@ absl::Status Tile16Editor::CyclePalette(bool forward) {
core::Renderer::Get().UpdateBitmap(&current_gfx_bmp_);
core::Renderer::Get().UpdateBitmap(&current_tile16_bmp_);
util::logf("Updated all tile16 editor graphics to use palette %d", current_palette_);
util::logf("Updated all tile16 editor graphics to use palette %d",
current_palette_);
}
return absl::OkStatus();
@@ -1599,11 +1618,13 @@ absl::Status Tile16Editor::CommitChangesToOverworld() {
for (int ty = 0; ty < kTile16Size; ++ty) {
for (int tx = 0; tx < kTile16Size; ++tx) {
int src_index = ty * kTile16Size + tx;
int dst_index = (tile_y + ty) * tile16_blockset_->atlas.width() + (tile_x + tx);
int dst_index =
(tile_y + ty) * tile16_blockset_->atlas.width() + (tile_x + tx);
if (src_index < static_cast<int>(current_tile16_bmp_.size()) &&
dst_index < static_cast<int>(tile16_blockset_->atlas.size())) {
tile16_blockset_->atlas.WriteToPixel(dst_index, current_tile16_bmp_.data()[src_index]);
tile16_blockset_->atlas.WriteToPixel(
dst_index, current_tile16_bmp_.data()[src_index]);
}
}
}
@@ -1617,7 +1638,8 @@ absl::Status Tile16Editor::CommitChangesToOverworld() {
RETURN_IF_ERROR(on_changes_committed_());
}
util::logf("Committed Tile16 %d changes to overworld system", current_tile16_);
util::logf("Committed Tile16 %d changes to overworld system",
current_tile16_);
return absl::OkStatus();
}
@@ -1651,7 +1673,8 @@ absl::Status Tile16Editor::UpdateTile8Palette(int tile8_id) {
// CRITICAL FIX: Use consistent palette application for all tile8 graphics
// Apply the current palette selection to match overworld appearance
current_gfx_individual_[tile8_id].SetPaletteWithTransparent(target_palette, current_palette_);
current_gfx_individual_[tile8_id].SetPaletteWithTransparent(target_palette,
current_palette_);
Renderer::Get().UpdateBitmap(&current_gfx_individual_[tile8_id]);
@@ -1669,24 +1692,27 @@ absl::Status Tile16Editor::RefreshAllPalettes() {
// CRITICAL FIX: Update tile8 source graphics display with forced texture update
current_gfx_bmp_.SetPaletteWithTransparent(main_palette, current_palette_);
current_gfx_bmp_.set_modified(true); // Force update
current_gfx_bmp_.set_modified(true); // Force update
Renderer::Get().UpdateBitmap(&current_gfx_bmp_);
// Update current tile16 being edited
current_tile16_bmp_.SetPaletteWithTransparent(main_palette, current_palette_);
current_tile16_bmp_.set_modified(true); // Force update
current_tile16_bmp_.set_modified(true); // Force update
Renderer::Get().UpdateBitmap(&current_tile16_bmp_);
// Update all individual tile8 graphics to use the same palette
for (size_t i = 0; i < current_gfx_individual_.size(); ++i) {
if (current_gfx_individual_[i].is_active()) {
current_gfx_individual_[i].SetPaletteWithTransparent(main_palette, current_palette_);
current_gfx_individual_[i].set_modified(true); // Force update
current_gfx_individual_[i].SetPaletteWithTransparent(main_palette,
current_palette_);
current_gfx_individual_[i].set_modified(true); // Force update
Renderer::Get().UpdateBitmap(&current_gfx_individual_[i]);
}
}
util::logf("Refreshed all palettes in tile16 editor to use overworld palette %d", current_palette_);
util::logf(
"Refreshed all palettes in tile16 editor to use overworld palette %d",
current_palette_);
return absl::OkStatus();
}
@@ -1720,8 +1746,8 @@ void Tile16Editor::DrawPaletteSettings() {
Separator();
Text("Current State:");
static constexpr std::array<const char*, 7> palette_group_names = {
"OW Main", "OW Aux", "OW Anim", "Dungeon", "Sprites", "Armor", "Sword"
};
"OW Main", "OW Aux", "OW Anim", "Dungeon",
"Sprites", "Armor", "Sword"};
Text("Palette Group: %d (%s)", current_palette_group_,
(current_palette_group_ < 7)
? palette_group_names[current_palette_group_]

View File

@@ -229,7 +229,7 @@ class Tile16Editor : public gfx::GfxContext {
// Tile8 canvas to get the tile to drawing in the tile16_edit_canvas_
gui::Canvas tile8_source_canvas_{
"Tile8SourceCanvas",
ImVec2(gfx::kTilesheetWidth * 4, gfx::kTilesheetHeight * 0x10 * 4),
ImVec2(gfx::kTilesheetWidth * 8, gfx::kTilesheetHeight * 0x10 * 8),
gui::CanvasGridSize::k32x32};
gfx::Bitmap current_gfx_bmp_;