Implement critical palette synchronization fixes in Tile16Editor and OverworldEditor

- Updated Tile16Editor to ensure consistent palette application across all graphics, aligning with the overworld palette for accurate color representation.
- Added functionality to immediately apply palette changes in Tile16Editor, enhancing visual consistency during editing.
- Implemented critical fixes to refresh all graphics with the correct overworld palette, improving user experience and reducing discrepancies in tile appearance.
- Enhanced logging for palette updates to facilitate debugging and provide user feedback on changes.
This commit is contained in:
scawful
2025-09-29 10:58:36 -04:00
parent 2c4ccc9d0a
commit c7aa0f4409
3 changed files with 61 additions and 62 deletions

View File

@@ -144,6 +144,10 @@ absl::Status OverworldEditor::Load() {
tile16_editor_.Initialize(tile16_blockset_bmp_, current_gfx_bmp_, tile16_editor_.Initialize(tile16_blockset_bmp_, current_gfx_bmp_,
*overworld_.mutable_all_tiles_types())); *overworld_.mutable_all_tiles_types()));
// CRITICAL FIX: Initialize tile16 editor with the correct overworld palette
tile16_editor_.set_palette(palette_);
tile16_editor_.set_rom(rom_);
// Set up callback for when tile16 changes are committed // Set up callback for when tile16 changes are committed
tile16_editor_.set_on_changes_committed([this]() -> absl::Status { tile16_editor_.set_on_changes_committed([this]() -> absl::Status {
// Regenerate the overworld editor's tile16 blockset // Regenerate the overworld editor's tile16 blockset

View File

@@ -31,10 +31,10 @@ absl::Status Tile16Editor::Initialize(
std::array<uint8_t, 0x200>& all_tiles_types) { std::array<uint8_t, 0x200>& all_tiles_types) {
all_tiles_types_ = all_tiles_types; all_tiles_types_ = all_tiles_types;
// Copy the graphics bitmap // 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_.Create(current_gfx_bmp.width(), current_gfx_bmp.height(),
current_gfx_bmp.depth(), current_gfx_bmp.vector()); current_gfx_bmp.depth(), current_gfx_bmp.vector());
current_gfx_bmp_.SetPalette(current_gfx_bmp.palette()); current_gfx_bmp_.SetPalette(current_gfx_bmp.palette()); // Temporary palette
core::Renderer::Get().RenderBitmap(&current_gfx_bmp_); core::Renderer::Get().RenderBitmap(&current_gfx_bmp_);
// Copy the tile16 blockset bitmap // Copy the tile16 blockset bitmap
@@ -967,6 +967,7 @@ absl::Status Tile16Editor::LoadTile8() {
"Current graphics bitmap not initialized"); "Current graphics bitmap not initialized");
} }
// CRITICAL FIX: Use the same palette system as the overworld
const auto& ow_main_pal_group = rom()->palette_group().overworld_main; const auto& ow_main_pal_group = rom()->palette_group().overworld_main;
if (ow_main_pal_group.size() == 0) { if (ow_main_pal_group.size() == 0) {
return absl::FailedPreconditionError("Overworld palette group not loaded"); return absl::FailedPreconditionError("Overworld palette group not loaded");
@@ -1088,11 +1089,11 @@ absl::Status Tile16Editor::SetCurrentTile(int tile_id) {
// Create the bitmap with the extracted data // Create the bitmap with the extracted data
current_tile16_bmp_.Create(kTile16Size, kTile16Size, 8, tile_data); current_tile16_bmp_.Create(kTile16Size, kTile16Size, 8, tile_data);
// Set the correct palette - tile16 should have independent palette // CRITICAL FIX: Use the same complete palette that the overworld uses
const auto& ow_main_pal_group = rom()->palette_group().overworld_main; // This ensures tile16 editor colors match the overworld exactly
if (ow_main_pal_group.size() > 0) { auto overworld_palette = rom()->palette_group().overworld_main[0]; // Get the current overworld palette
// Use SetPalette instead of SetPaletteWithTransparent for tile16 if (overworld_palette.size() > 0) {
current_tile16_bmp_.SetPalette(ow_main_pal_group[0]); current_tile16_bmp_.SetPalette(overworld_palette);
} }
// Render the bitmap // Render the bitmap
@@ -1339,25 +1340,29 @@ absl::Status Tile16Editor::CyclePalette(bool forward) {
current_palette_ = new_palette; current_palette_ = new_palette;
// Update all graphics with new palette // CRITICAL FIX: Use the same palette coordination as the overworld
// The palette selection should affect how tiles appear in the tile16 editor
const auto& ow_main_pal_group = rom()->palette_group().overworld_main; const auto& ow_main_pal_group = rom()->palette_group().overworld_main;
if (ow_main_pal_group.size() > current_palette_) { if (ow_main_pal_group.size() > 0) {
current_gfx_bmp_.SetPaletteWithTransparent(ow_main_pal_group[0], // Use the main overworld palette but apply the selected palette index
current_palette_); auto main_palette = ow_main_pal_group[0];
current_tile16_bmp_.SetPaletteWithTransparent(ow_main_pal_group[0],
current_palette_);
// Update individual tile8 graphics // Apply the selected palette to all graphics consistently
current_gfx_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_) { for (auto& tile_gfx : current_gfx_individual_) {
if (tile_gfx.is_active()) { if (tile_gfx.is_active()) {
tile_gfx.SetPaletteWithTransparent(ow_main_pal_group[0], tile_gfx.SetPaletteWithTransparent(main_palette, current_palette_);
current_palette_);
core::Renderer::Get().UpdateBitmap(&tile_gfx); core::Renderer::Get().UpdateBitmap(&tile_gfx);
} }
} }
core::Renderer::Get().UpdateBitmap(&current_gfx_bmp_); core::Renderer::Get().UpdateBitmap(&current_gfx_bmp_);
core::Renderer::Get().UpdateBitmap(&current_tile16_bmp_); core::Renderer::Get().UpdateBitmap(&current_tile16_bmp_);
util::logf("Updated all tile16 editor graphics to use palette %d", current_palette_);
} }
return absl::OkStatus(); return absl::OkStatus();
@@ -1635,50 +1640,18 @@ absl::Status Tile16Editor::UpdateTile8Palette(int tile8_id) {
return absl::OkStatus(); // Skip inactive tiles return absl::OkStatus(); // Skip inactive tiles
} }
// Get the appropriate palette group // CRITICAL FIX: Always use the overworld main palette for consistency
// This ensures all tile8 graphics match the overworld colors exactly
const auto& palette_groups = rom()->palette_group(); const auto& palette_groups = rom()->palette_group();
gfx::SnesPalette target_palette; gfx::SnesPalette target_palette = palette_groups.overworld_main[0];
switch (current_palette_group_) {
case 0:
target_palette = palette_groups.overworld_main[0];
break;
case 1:
target_palette = palette_groups.overworld_aux[0];
break;
case 2:
target_palette = palette_groups.overworld_animated[0];
break;
case 3:
target_palette = palette_groups.dungeon_main[0];
break;
case 4:
target_palette = palette_groups.global_sprites[0];
break;
case 5:
target_palette = palette_groups.armors[0];
break;
case 6:
target_palette = palette_groups.swords[0];
break;
default:
target_palette = palette_groups.overworld_main[0];
break;
}
// Calculate which graphics sheet this tile belongs to // Calculate which graphics sheet this tile belongs to
const int tiles_per_row = current_gfx_bmp_.width() / 8; // Usually 16 const int tiles_per_row = current_gfx_bmp_.width() / 8; // Usually 16
const int sheet_index = tile8_id / (tiles_per_row * 8); // 8 rows per sheet const int sheet_index = tile8_id / (tiles_per_row * 8); // 8 rows per sheet
// For certain sheets (like sheet 0 - trees), use SetPalette instead of SetPaletteWithTransparent // CRITICAL FIX: Use consistent palette application for all tile8 graphics
if (sheet_index == 0 || current_palette_group_ >= 3) { // Apply the current palette selection to match overworld appearance
// Trees sheet and sprite sheets work better with direct palette current_gfx_individual_[tile8_id].SetPaletteWithTransparent(target_palette, current_palette_);
current_gfx_individual_[tile8_id].SetPalette(target_palette);
} else {
// Other sheets use the transparent palette system
current_gfx_individual_[tile8_id].SetPaletteWithTransparent(
target_palette, current_palette_);
}
Renderer::Get().UpdateBitmap(&current_gfx_individual_[tile8_id]); Renderer::Get().UpdateBitmap(&current_gfx_individual_[tile8_id]);
@@ -1686,25 +1659,34 @@ absl::Status Tile16Editor::UpdateTile8Palette(int tile8_id) {
} }
absl::Status Tile16Editor::RefreshAllPalettes() { absl::Status Tile16Editor::RefreshAllPalettes() {
const auto& palette_groups = rom()->palette_group(); // CRITICAL FIX: Ensure all graphics use the same palette coordination as overworld
if (!rom_) {
return absl::FailedPreconditionError("ROM not set");
}
// Update tile8 graphics const auto& palette_groups = rom()->palette_group();
current_gfx_bmp_.SetPaletteWithTransparent(palette_groups.overworld_main[0], auto main_palette = palette_groups.overworld_main[0];
current_palette_);
// 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
Renderer::Get().UpdateBitmap(&current_gfx_bmp_); Renderer::Get().UpdateBitmap(&current_gfx_bmp_);
// Update current tile16 // Update current tile16 being edited
current_tile16_bmp_.SetPaletteWithTransparent( current_tile16_bmp_.SetPaletteWithTransparent(main_palette, current_palette_);
palette_groups.overworld_main[0], current_palette_); current_tile16_bmp_.set_modified(true); // Force update
Renderer::Get().UpdateBitmap(&current_tile16_bmp_); Renderer::Get().UpdateBitmap(&current_tile16_bmp_);
// Update all individual tile8 graphics // Update all individual tile8 graphics to use the same palette
for (size_t i = 0; i < current_gfx_individual_.size(); ++i) { for (size_t i = 0; i < current_gfx_individual_.size(); ++i) {
if (current_gfx_individual_[i].is_active()) { if (current_gfx_individual_[i].is_active()) {
RETURN_IF_ERROR(UpdateTile8Palette(static_cast<int>(i))); 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_);
return absl::OkStatus(); return absl::OkStatus();
} }

View File

@@ -13,6 +13,7 @@
#include "app/gfx/snes_tile.h" #include "app/gfx/snes_tile.h"
#include "app/gui/canvas.h" #include "app/gui/canvas.h"
#include "app/gui/input.h" #include "app/gui/input.h"
#include "util/log.h"
#include "app/rom.h" #include "app/rom.h"
#include "app/zelda3/overworld/overworld.h" #include "app/zelda3/overworld/overworld.h"
#include "imgui/imgui.h" #include "imgui/imgui.h"
@@ -125,6 +126,18 @@ class Tile16Editor : public gfx::GfxContext {
void set_rom(Rom* rom) { rom_ = rom; } void set_rom(Rom* rom) { rom_ = rom; }
Rom* rom() const { return rom_; } Rom* rom() const { return rom_; }
// Set the palette from overworld to ensure color consistency
void set_palette(const gfx::SnesPalette& palette) {
palette_ = palette;
// Apply to all graphics immediately
if (rom_) {
auto status = RefreshAllPalettes();
if (!status.ok()) {
util::logf("Failed to refresh palettes: %s", status.message().data());
}
}
}
// Callback for when changes are committed to notify parent editor // Callback for when changes are committed to notify parent editor
void set_on_changes_committed(std::function<absl::Status()> callback) { void set_on_changes_committed(std::function<absl::Status()> callback) {
on_changes_committed_ = callback; on_changes_committed_ = callback;