Refactor Emulator and Snes classes for improved memory access

- Updated Emulator class to remove inheritance from SharedRom and streamline ROM handling.
- Refactored memory access methods in Emulator and Snes classes to use consistent naming conventions.
- Enhanced DungeonObjectRenderer to utilize the updated Snes class for CPU and memory operations, improving clarity and maintainability.
- Cleaned up unnecessary comments and improved code formatting for better readability.
This commit is contained in:
scawful
2025-05-15 22:53:37 -04:00
parent 86d72fe0ca
commit 1031509e8a
6 changed files with 78 additions and 116 deletions

View File

@@ -1,5 +1,7 @@
#include "app/zelda3/dungeon/object_renderer.h"
#include "app/gfx/arena.h"
namespace yaze {
namespace zelda3 {
@@ -8,8 +10,7 @@ void DungeonObjectRenderer::LoadObject(uint32_t routine_ptr,
vram_.sheets = sheet_ids;
rom_data_ = rom()->vector();
// Prepare the CPU and memory environment
memory_.Initialize(rom_data_);
snes_.memory().Initialize(rom_data_);
// Configure the object based on the fetched information
ConfigureObject();
@@ -19,16 +20,16 @@ void DungeonObjectRenderer::LoadObject(uint32_t routine_ptr,
}
void DungeonObjectRenderer::ConfigureObject() {
cpu.A = 0x03D8;
cpu.X = 0x03D8;
cpu.DB = 0x7E;
snes_.cpu().A = 0x03D8;
snes_.cpu().X = 0x03D8;
snes_.cpu().DB = 0x7E;
// VRAM target destinations
cpu.WriteLong(0xBF, 0x7E2000);
cpu.WriteLong(0xCB, 0x7E2080);
cpu.WriteLong(0xC2, 0x7E2002);
cpu.WriteLong(0xCE, 0x7E2082);
cpu.SetAccumulatorSize(false);
cpu.SetIndexSize(false);
snes_.cpu().WriteLong(0xBF, 0x7E2000);
snes_.cpu().WriteLong(0xCB, 0x7E2080);
snes_.cpu().WriteLong(0xC2, 0x7E2002);
snes_.cpu().WriteLong(0xCE, 0x7E2082);
snes_.cpu().SetAccumulatorSize(false);
snes_.cpu().SetIndexSize(false);
}
/**
@@ -59,15 +60,15 @@ void DungeonObjectRenderer::ConfigureObject() {
#_0198AD: RTS
*/
void DungeonObjectRenderer::RenderObject(uint32_t routine_ptr) {
cpu.PB = 0x01;
cpu.PC = routine_ptr;
snes_.cpu().PB = 0x01;
snes_.cpu().PC = routine_ptr;
// Set up initial state for object drawing
cpu.Y = 0; // Start at the beginning of the tilemap
cpu.D = 0x7E; // Direct page register for memory access
snes_.cpu().Y = 0; // Start at the beginning of the tilemap
snes_.cpu().D = 0x7E; // Direct page register for memory access
// Push return address to stack
cpu.PushLong(0x01 << 16 | 0xFFFF); // Push a dummy return address
snes_.cpu().PushLong(0x01 << 16 | 0xFFFF); // Push a dummy return address
// Set up a maximum instruction count to prevent infinite loops
const int MAX_INSTRUCTIONS = 10000;
@@ -75,17 +76,18 @@ void DungeonObjectRenderer::RenderObject(uint32_t routine_ptr) {
// Execute instructions until we hit a return instruction or max count
while (instruction_count < MAX_INSTRUCTIONS) {
uint8_t opcode = cpu.ReadByte(cpu.PB << 16 | cpu.PC);
uint8_t opcode =
snes_.cpu().ReadByte(snes_.cpu().PB << 16 | snes_.cpu().PC);
// Check for RTS (Return from Subroutine) instruction
if (opcode == 0x60) {
// Execute the RTS instruction
cpu.ExecuteInstruction(opcode);
snes_.cpu().ExecuteInstruction(opcode);
break; // Exit the loop after RTS
}
// Execute the instruction
cpu.ExecuteInstruction(opcode);
snes_.cpu().ExecuteInstruction(opcode);
instruction_count++;
}
@@ -108,7 +110,7 @@ void DungeonObjectRenderer::UpdateObjectBitmap() {
// Iterate over tilemap in memory to read tile IDs
for (int tile_index = 0; tile_index < 512; tile_index++) {
// Read the tile ID from memory
uint16_t tile_id = memory_.ReadWord(0x7E2000 + tile_index * 2);
uint16_t tile_id = snes_.memory().ReadWord(0x7E2000 + tile_index * 2);
// Skip empty tiles (0x0000)
if (tile_id == 0) continue;
@@ -128,8 +130,8 @@ void DungeonObjectRenderer::UpdateObjectBitmap() {
int tile_y = (tile_index / 32) * 8;
// Get the graphics sheet
auto& sheet = GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(
vram_.sheets[sheet_number]);
auto& sheet =
gfx::Arena::Get().mutable_gfx_sheets()->at(vram_.sheets[sheet_number]);
// Calculate the offset in the tilemap
int tilemap_offset = tile_y * 256 + tile_x;
@@ -137,19 +139,6 @@ void DungeonObjectRenderer::UpdateObjectBitmap() {
// Copy the tile from the graphics sheet to the tilemap
sheet.Get8x8Tile(tile_id % 32, 0, 0, tilemap_, tilemap_offset);
}
// Create the bitmap from the tilemap
bitmap_.Create(256, 256, 8, tilemap_);
}
void DungeonObjectRenderer::SetPalette(const gfx::SnesPalette& palette,
size_t transparent_index) {
// Apply the palette to the bitmap
bitmap_.SetPaletteWithTransparent(palette, transparent_index);
// Store the palette in the VRAM structure for future reference
vram_.palettes.clear();
vram_.palettes.push_back(palette);
}
} // namespace zelda3

View File

@@ -1,9 +1,7 @@
#include <cstdint>
#include <vector>
#include "app/emu/cpu/cpu.h"
#include "app/emu/memory/memory.h"
#include "app/emu/video/ppu.h"
#include "app/emu/snes.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
#include "app/rom.h"
@@ -14,80 +12,55 @@ namespace zelda3 {
/**
* @struct PseudoVram
* @brief Simulates the SNES VRAM for object rendering
*
*
* This structure holds the sheet IDs and palettes needed for rendering
* dungeon objects in Link to the Past.
*/
struct PseudoVram {
std::array<uint8_t, 16> sheets = { 0 };
std::array<uint8_t, 16> sheets = {0};
std::vector<gfx::SnesPalette> palettes;
};
/**
* @class DungeonObjectRenderer
* @brief Renders dungeon objects from Link to the Past
*
*
* This class uses the emulator subsystem to simulate the SNES CPU
* drawing routines for dungeon objects. It captures the tile data
* written to memory and renders it to a bitmap.
*/
class DungeonObjectRenderer : public SharedRom {
class DungeonObjectRenderer {
public:
DungeonObjectRenderer() = default;
/**
* @brief Loads and renders a dungeon object
*
*
* @param routine_ptr Pointer to the drawing routine in ROM
* @param sheet_ids Array of graphics sheet IDs used by the object
*/
void LoadObject(uint32_t routine_ptr, std::array<uint8_t, 16>& sheet_ids);
/**
* @brief Configures the CPU state for object rendering
*/
void ConfigureObject();
/**
* @brief Executes the object drawing routine
*
*
* @param routine_ptr Pointer to the drawing routine in ROM
*/
void RenderObject(uint32_t routine_ptr);
/**
* @brief Updates the bitmap with the rendered object
*/
void UpdateObjectBitmap();
/**
* @brief Sets the palette for the rendered object
*
* @param palette The palette to use for the object
* @param transparent_index Index of the transparent color (default: 0)
*/
void SetPalette(const gfx::SnesPalette& palette, size_t transparent_index = 0);
/**
* @brief Gets the rendered bitmap
*
* @return gfx::Bitmap* Pointer to the bitmap
*/
gfx::Bitmap* bitmap() { return &bitmap_; }
/**
* @brief Gets the memory implementation
*
* @return Memory implementation
*/
auto memory() { return memory_; }
/**
* @brief Gets a mutable pointer to the memory implementation
*
* @return Mutable pointer to the memory implementation
*/
auto mutable_memory() { return &memory_; }
auto mutable_memory() { return &tilemap_; }
auto rom() { return rom_; }
auto mutable_rom() { return &rom_; }
private:
std::vector<uint8_t> tilemap_;
@@ -95,11 +68,8 @@ class DungeonObjectRenderer : public SharedRom {
PseudoVram vram_;
emu::MemoryImpl memory_;
emu::CpuCallbacks cpu_callbacks_;
emu::Ppu ppu{memory_};
emu::Cpu cpu{memory_, cpu_callbacks_};
Rom* rom_;
emu::Snes snes_;
gfx::Bitmap bitmap_;
};