Dungeon object updates
This commit is contained in:
@@ -14,8 +14,8 @@ set(
|
||||
app/editor/overworld_editor.cc
|
||||
app/editor/screen_editor.cc
|
||||
app/editor/sprite_editor.cc
|
||||
app/editor/resources/music_editor.cc
|
||||
app/editor/resources/palette_editor.cc
|
||||
app/editor/modules/music_editor.cc
|
||||
app/editor/modules/palette_editor.cc
|
||||
app/editor/modules/assembly_editor.cc
|
||||
app/editor/modules/tile16_editor.cc
|
||||
app/editor/modules/gfx_group_editor.cc
|
||||
|
||||
@@ -23,6 +23,12 @@ uint32_t PcToSnes(uint32_t addr) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint32_t MapBankToWordAddress(uint8_t bank, uint16_t addr) {
|
||||
uint32_t result = 0;
|
||||
result = (bank << 16) | addr;
|
||||
return result;
|
||||
}
|
||||
|
||||
int AddressFromBytes(uint8_t addr1, uint8_t addr2, uint8_t addr3) {
|
||||
return (addr1 << 16) | (addr2 << 8) | addr3;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class ExperimentFlags {
|
||||
bool kUseBitmapManager = true;
|
||||
|
||||
// Log instructions to the GUI debugger.
|
||||
bool kLogInstructions = true;
|
||||
bool kLogInstructions = false;
|
||||
|
||||
// Flag to enable ImGui input config flags. Currently is
|
||||
// handled manually by controller class but should be
|
||||
@@ -35,7 +35,7 @@ class ExperimentFlags {
|
||||
bool kSaveWithChangeQueue = false;
|
||||
|
||||
// Attempt to run the dungeon room draw routine when opening a room.
|
||||
bool kDrawDungeonRoomGraphics = false;
|
||||
bool kDrawDungeonRoomGraphics = true;
|
||||
};
|
||||
|
||||
ExperimentFlags() = default;
|
||||
@@ -58,11 +58,43 @@ class ExperimentFlags {
|
||||
static std::shared_ptr<Flags> flags_;
|
||||
};
|
||||
|
||||
// NotifyFlag is a special type class which stores two copies of a type
|
||||
// and uses that to check if the value was updated last or not
|
||||
// It should have an accessor which says if it was modified or not
|
||||
// and when that is read it should reset the value and state
|
||||
template <typename T>
|
||||
class NotifyFlag {
|
||||
public:
|
||||
NotifyFlag() : value_(), modified_(false) {}
|
||||
|
||||
void set(const T &value) {
|
||||
value_ = value;
|
||||
modified_ = true;
|
||||
}
|
||||
|
||||
const T &get() {
|
||||
modified_ = false;
|
||||
return value_;
|
||||
}
|
||||
|
||||
void operator=(const T &value) { set(value); }
|
||||
operator T() const { return get(); }
|
||||
|
||||
bool isModified() const { return modified_; }
|
||||
|
||||
private:
|
||||
T value_;
|
||||
bool modified_;
|
||||
};
|
||||
|
||||
uint32_t SnesToPc(uint32_t addr);
|
||||
uint32_t PcToSnes(uint32_t addr);
|
||||
|
||||
uint32_t MapBankToWordAddress(uint8_t bank, uint16_t addr);
|
||||
|
||||
int AddressFromBytes(uint8_t addr1, uint8_t addr2, uint8_t addr3);
|
||||
int HexToDec(char *input, int length);
|
||||
|
||||
bool StringReplace(std::string &str, const std::string &from,
|
||||
const std::string &to);
|
||||
|
||||
|
||||
@@ -58,92 +58,8 @@ absl::Status DungeonEditor::Update() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawRoomSelector() {
|
||||
if (rom()->isLoaded()) {
|
||||
gui::InputHexWord("Room ID", ¤t_room_id_);
|
||||
// gui::InputHexByte("Palette ID", &rooms_[current_room_id_].palette);
|
||||
|
||||
if (ImGuiID child_id = ImGui::GetID((void*)(intptr_t)9);
|
||||
ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
int i = 0;
|
||||
for (const auto each_room_name : zelda3::dungeon::kRoomNames) {
|
||||
ImGui::Selectable(each_room_name.data(), current_room_id_ == i,
|
||||
ImGuiSelectableFlags_AllowDoubleClick);
|
||||
if (ImGui::IsItemClicked()) {
|
||||
active_rooms_.push_back(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawDungeonTabView() {
|
||||
static int next_tab_id = 0;
|
||||
|
||||
if (ImGui::BeginTabBar("MyTabBar", kDungeonTabBarFlags)) {
|
||||
// TODO: Manage the room that is being added to the tab bar.
|
||||
if (ImGui::TabItemButton("##tabitem", kDungeonTabFlags)) {
|
||||
active_rooms_.push_back(next_tab_id++); // Add new tab
|
||||
}
|
||||
|
||||
// Submit our regular tabs
|
||||
for (int n = 0; n < active_rooms_.Size;) {
|
||||
bool open = true;
|
||||
|
||||
if (ImGui::BeginTabItem(
|
||||
zelda3::dungeon::kRoomNames[active_rooms_[n]].data(), &open,
|
||||
ImGuiTabItemFlags_None)) {
|
||||
DrawDungeonCanvas(active_rooms_[n]);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (!open)
|
||||
active_rooms_.erase(active_rooms_.Data + n);
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
||||
ImGui::BeginGroup();
|
||||
|
||||
gui::InputHexByte("Layout", &rooms_[room_id].layout);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Blockset", &rooms_[room_id].blockset);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Spriteset", &rooms_[room_id].spriteset);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Palette", &rooms_[room_id].palette);
|
||||
|
||||
gui::InputHexByte("Floor1", &rooms_[room_id].floor1);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Floor2", &rooms_[room_id].floor2);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexWord("Message ID", &rooms_[room_id].message_id_);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
canvas_.DrawBackground();
|
||||
canvas_.DrawContextMenu();
|
||||
canvas_.DrawGrid();
|
||||
canvas_.DrawOverlay();
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawToolset() {
|
||||
if (ImGui::BeginTable("DWToolset", 12, ImGuiTableFlags_SizingFixedFit,
|
||||
if (ImGui::BeginTable("DWToolset", 13, ImGuiTableFlags_SizingFixedFit,
|
||||
ImVec2(0, 0))) {
|
||||
TableSetupColumn("#undoTool");
|
||||
TableSetupColumn("#redoTool");
|
||||
@@ -231,10 +147,99 @@ void DungeonEditor::DrawToolset() {
|
||||
ImGui::SetTooltip("Blocks");
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Button(ICON_MD_PALETTE)) {
|
||||
// Open the palette module
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawRoomSelector() {
|
||||
if (rom()->isLoaded()) {
|
||||
gui::InputHexWord("Room ID", ¤t_room_id_);
|
||||
// gui::InputHexByte("Palette ID", &rooms_[current_room_id_].palette);
|
||||
|
||||
if (ImGuiID child_id = ImGui::GetID((void*)(intptr_t)9);
|
||||
ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
int i = 0;
|
||||
for (const auto each_room_name : zelda3::dungeon::kRoomNames) {
|
||||
ImGui::Selectable(each_room_name.data(), current_room_id_ == i,
|
||||
ImGuiSelectableFlags_AllowDoubleClick);
|
||||
if (ImGui::IsItemClicked()) {
|
||||
active_rooms_.push_back(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawDungeonTabView() {
|
||||
static int next_tab_id = 0;
|
||||
|
||||
if (ImGui::BeginTabBar("MyTabBar", kDungeonTabBarFlags)) {
|
||||
// TODO: Manage the room that is being added to the tab bar.
|
||||
if (ImGui::TabItemButton("##tabitem", kDungeonTabFlags)) {
|
||||
active_rooms_.push_back(next_tab_id++); // Add new tab
|
||||
}
|
||||
|
||||
// Submit our regular tabs
|
||||
for (int n = 0; n < active_rooms_.Size;) {
|
||||
bool open = true;
|
||||
|
||||
if (ImGui::BeginTabItem(
|
||||
zelda3::dungeon::kRoomNames[active_rooms_[n]].data(), &open,
|
||||
ImGuiTabItemFlags_None)) {
|
||||
DrawDungeonCanvas(active_rooms_[n]);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (!open)
|
||||
active_rooms_.erase(active_rooms_.Data + n);
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
||||
ImGui::BeginGroup();
|
||||
|
||||
gui::InputHexByte("Layout", &rooms_[room_id].layout);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Blockset", &rooms_[room_id].blockset);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Spriteset", &rooms_[room_id].spriteset);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Palette", &rooms_[room_id].palette);
|
||||
|
||||
gui::InputHexByte("Floor1", &rooms_[room_id].floor1);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexByte("Floor2", &rooms_[room_id].floor2);
|
||||
ImGui::SameLine();
|
||||
|
||||
gui::InputHexWord("Message ID", &rooms_[room_id].message_id_);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
canvas_.DrawBackground();
|
||||
canvas_.DrawContextMenu();
|
||||
canvas_.DrawGrid();
|
||||
canvas_.DrawOverlay();
|
||||
}
|
||||
|
||||
void DungeonEditor::DrawRoomGraphics() {
|
||||
const auto height = 0x40;
|
||||
room_gfx_canvas_.DrawBackground(ImVec2(256 + 1, 0x10 * 0x40 + 1));
|
||||
@@ -301,6 +306,9 @@ void DungeonEditor::DrawObjectRenderer() {
|
||||
for (const auto object_name : zelda3::dungeon::Type1RoomObjectNames) {
|
||||
if (ImGui::Selectable(object_name.data(), selected_object == i)) {
|
||||
selected_object = i;
|
||||
object_renderer_.LoadObject(i);
|
||||
rom()->RenderBitmap(object_renderer_.bitmap());
|
||||
object_loaded_ = true;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
@@ -312,11 +320,14 @@ void DungeonEditor::DrawObjectRenderer() {
|
||||
ImGui::BeginChild("DungeonObjectCanvas", ImVec2(276, 0x10 * 0x40 + 1),
|
||||
true);
|
||||
|
||||
dungeon_object_canvas_.DrawBackground(ImVec2(256 + 1, 0x10 * 0x40 + 1));
|
||||
dungeon_object_canvas_.DrawContextMenu();
|
||||
dungeon_object_canvas_.DrawTileSelector(32);
|
||||
dungeon_object_canvas_.DrawGrid(32.0f);
|
||||
dungeon_object_canvas_.DrawOverlay();
|
||||
object_canvas_.DrawBackground(ImVec2(256 + 1, 0x10 * 0x40 + 1));
|
||||
object_canvas_.DrawContextMenu();
|
||||
object_canvas_.DrawTileSelector(32);
|
||||
// if (object_loaded_) {
|
||||
// object_canvas_.DrawBitmap(*object_renderer_.bitmap(), 0, 0);
|
||||
// }
|
||||
object_canvas_.DrawGrid(32.0f);
|
||||
object_canvas_.DrawOverlay();
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class DungeonEditor : public Editor,
|
||||
uint16_t current_room_id_ = 0;
|
||||
bool is_loaded_ = false;
|
||||
bool show_object_render_ = false;
|
||||
bool object_loaded_ = false;
|
||||
|
||||
gfx::Bitmap room_gfx_bmp_;
|
||||
|
||||
@@ -60,6 +61,11 @@ class DungeonEditor : public Editor,
|
||||
|
||||
std::vector<zelda3::dungeon::Room> rooms_;
|
||||
zelda3::dungeon::DungeonObjectRenderer object_renderer_;
|
||||
gui::Canvas canvas_;
|
||||
gui::Canvas room_gfx_canvas_;
|
||||
gui::Canvas object_canvas_;
|
||||
|
||||
std::vector<gfx::BitmapManager> room_graphics_;
|
||||
|
||||
enum BackgroundType {
|
||||
kNoBackground,
|
||||
@@ -73,13 +79,6 @@ class DungeonEditor : public Editor,
|
||||
int background_type_ = kNoBackground;
|
||||
int placement_type_ = kNoType;
|
||||
|
||||
gui::Canvas canvas_;
|
||||
gui::Canvas room_gfx_canvas_;
|
||||
|
||||
gui::Canvas dungeon_object_canvas_;
|
||||
|
||||
std::vector<gfx::BitmapManager> room_graphics_;
|
||||
|
||||
ImGuiTableFlags toolset_table_flags_ =
|
||||
ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable |
|
||||
ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/compression.h"
|
||||
#include "app/gfx/scad_format.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/gui/canvas.h"
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include "app/editor/graphics_editor.h"
|
||||
#include "app/editor/modules/assembly_editor.h"
|
||||
#include "app/editor/overworld_editor.h"
|
||||
#include "app/editor/resources/music_editor.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/music_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/editor/screen_editor.h"
|
||||
#include "app/editor/sprite_editor.h"
|
||||
#include "app/emu/emulator.h"
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#include "app/editor/dungeon_editor.h"
|
||||
#include "app/editor/graphics_editor.h"
|
||||
#include "app/editor/modules/assembly_editor.h"
|
||||
#include "app/editor/resources/music_editor.h"
|
||||
#include "app/editor/modules/music_editor.h"
|
||||
#include "app/editor/overworld_editor.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/editor/screen_editor.h"
|
||||
#include "app/editor/sprite_editor.h"
|
||||
#include "app/emu/emulator.h"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "app/core/editor.h"
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "app/core/pipeline.h"
|
||||
#include "app/editor/modules/gfx_group_editor.h"
|
||||
#include "app/editor/modules/tile16_editor.h"
|
||||
#include "app/editor/resources/palette_editor.h"
|
||||
#include "app/editor/modules/palette_editor.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
|
||||
@@ -623,18 +623,18 @@ class CPU : public Memory, public Loggable, public core::ExperimentFlags {
|
||||
void XCE();
|
||||
|
||||
// Memory access routines
|
||||
uint8_t ReadByte(uint16_t address) const override {
|
||||
uint8_t ReadByte(uint32_t address) const override {
|
||||
auto value = memory.ReadByte(address);
|
||||
return value;
|
||||
}
|
||||
uint16_t ReadWord(uint16_t address) const override {
|
||||
uint16_t ReadWord(uint32_t address) const override {
|
||||
return memory.ReadWord(address);
|
||||
}
|
||||
uint32_t ReadWordLong(uint16_t address) const override {
|
||||
uint32_t ReadWordLong(uint32_t address) const override {
|
||||
return memory.ReadWordLong(address);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ReadByteVector(uint16_t address,
|
||||
std::vector<uint8_t> ReadByteVector(uint32_t address,
|
||||
uint16_t size) const override {
|
||||
return memory.ReadByteVector(address, size);
|
||||
}
|
||||
|
||||
@@ -48,11 +48,21 @@ void DrawMemoryWindow(Memory* memory) {
|
||||
// Display memory areas
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("ROM");
|
||||
ImGui::Text("ROM Bank 0-63");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x000000");
|
||||
ImGui::Text("0x8000");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d MB", memoryImpl->rom_.size());
|
||||
ImGui::Text("128 KB");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("LoROM");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("ROM Bank 64-111");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x0000");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("64 KB");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("LoROM");
|
||||
|
||||
@@ -60,9 +70,39 @@ void DrawMemoryWindow(Memory* memory) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("RAM");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x700000");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("64 KB");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("LoROM");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("System RAM (WRAM)");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x7E0000");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d KB", memoryImpl->ram_.size());
|
||||
ImGui::Text("128 KB");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("LoROM");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("ROM Bank 128-191");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x8000");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("128 KB");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("LoROM");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("ROM Bank 192-255");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x0000");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("64 KB");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("LoROM");
|
||||
}
|
||||
@@ -109,7 +149,6 @@ void Emulator::Run() {
|
||||
ImGui::Button(ICON_MD_DOUBLE_ARROW);
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_MD_SUBDIRECTORY_ARROW_RIGHT);
|
||||
ImGui::SameLine();
|
||||
|
||||
if (running_) {
|
||||
HandleEvents();
|
||||
@@ -331,8 +370,9 @@ void Emulator::RenderCPUInstructionLog(
|
||||
ImGui::Checkbox("Show All Opcodes", &showAllOpcodes);
|
||||
|
||||
// Instruction list
|
||||
ImGui::BeginChild("InstructionList", ImVec2(0, 0),
|
||||
ImGuiChildFlags_AlwaysAutoResize);
|
||||
ImGui::BeginChild(
|
||||
"InstructionList", ImVec2(0, 0),
|
||||
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY);
|
||||
for (const auto& entry : instructionLog) {
|
||||
if (ShouldDisplay(entry, filterBuf, showAllOpcodes)) {
|
||||
if (ImGui::Selectable(absl::StrFormat("%04X: %02X %s %s", entry.address,
|
||||
|
||||
@@ -109,10 +109,10 @@ constexpr uint32_t kOAMSize = 0x220;
|
||||
class Memory {
|
||||
public:
|
||||
virtual ~Memory() = default;
|
||||
virtual uint8_t ReadByte(uint16_t address) const = 0;
|
||||
virtual uint16_t ReadWord(uint16_t address) const = 0;
|
||||
virtual uint32_t ReadWordLong(uint16_t address) const = 0;
|
||||
virtual std::vector<uint8_t> ReadByteVector(uint16_t address,
|
||||
virtual uint8_t ReadByte(uint32_t address) const = 0;
|
||||
virtual uint16_t ReadWord(uint32_t address) const = 0;
|
||||
virtual uint32_t ReadWordLong(uint32_t address) const = 0;
|
||||
virtual std::vector<uint8_t> ReadByteVector(uint32_t address,
|
||||
uint16_t length) const = 0;
|
||||
|
||||
virtual void WriteByte(uint32_t address, uint8_t value) = 0;
|
||||
@@ -149,7 +149,7 @@ class MemoryImpl : public Memory, public Loggable {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_.reserve(0x1000000); // 16 MB
|
||||
memory_.resize(0x1000000); // 16 MB
|
||||
|
||||
const size_t ROM_CHUNK_SIZE = 0x8000; // 32 KB
|
||||
const size_t SRAM_SIZE = 0x10000; // 64 KB
|
||||
@@ -229,25 +229,25 @@ class MemoryImpl : public Memory, public Loggable {
|
||||
memory_.begin() + kOAMStart + kOAMSize, oam_.begin());
|
||||
}
|
||||
|
||||
uint8_t ReadByte(uint16_t address) const override {
|
||||
uint8_t ReadByte(uint32_t address) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
return memory_.at(mapped_address);
|
||||
}
|
||||
uint16_t ReadWord(uint16_t address) const override {
|
||||
uint16_t ReadWord(uint32_t address) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
return static_cast<uint16_t>(memory_.at(mapped_address)) |
|
||||
(static_cast<uint16_t>(memory_.at(mapped_address + 1)) << 8);
|
||||
}
|
||||
uint32_t ReadWordLong(uint16_t address) const override {
|
||||
uint32_t ReadWordLong(uint32_t address) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
return static_cast<uint32_t>(memory_.at(mapped_address)) |
|
||||
(static_cast<uint32_t>(memory_.at(mapped_address + 1)) << 8) |
|
||||
(static_cast<uint32_t>(memory_.at(mapped_address + 2)) << 16);
|
||||
}
|
||||
std::vector<uint8_t> ReadByteVector(uint16_t address,
|
||||
std::vector<uint8_t> ReadByteVector(uint32_t address,
|
||||
uint16_t length) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
|
||||
@@ -23,11 +23,11 @@ class MockClock : public Clock {
|
||||
|
||||
class MockMemory : public Memory {
|
||||
public:
|
||||
MOCK_CONST_METHOD1(ReadByte, uint8_t(uint16_t address));
|
||||
MOCK_CONST_METHOD1(ReadWord, uint16_t(uint16_t address));
|
||||
MOCK_CONST_METHOD1(ReadWordLong, uint32_t(uint16_t address));
|
||||
MOCK_CONST_METHOD1(ReadByte, uint8_t(uint32_t address));
|
||||
MOCK_CONST_METHOD1(ReadWord, uint16_t(uint32_t address));
|
||||
MOCK_CONST_METHOD1(ReadWordLong, uint32_t(uint32_t address));
|
||||
MOCK_METHOD(std::vector<uint8_t>, ReadByteVector,
|
||||
(uint16_t address, uint16_t length), (const, override));
|
||||
(uint32_t address, uint16_t length), (const, override));
|
||||
|
||||
MOCK_METHOD2(WriteByte, void(uint32_t address, uint8_t value));
|
||||
MOCK_METHOD2(WriteWord, void(uint32_t address, uint16_t value));
|
||||
@@ -76,20 +76,20 @@ class MockMemory : public Memory {
|
||||
void Init() {
|
||||
ON_CALL(*this, ReadByte(::testing::_))
|
||||
.WillByDefault(
|
||||
[this](uint16_t address) { return memory_.at(address); });
|
||||
[this](uint32_t address) { return memory_.at(address); });
|
||||
ON_CALL(*this, ReadWord(::testing::_))
|
||||
.WillByDefault([this](uint16_t address) {
|
||||
.WillByDefault([this](uint32_t address) {
|
||||
return static_cast<uint16_t>(memory_.at(address)) |
|
||||
(static_cast<uint16_t>(memory_.at(address + 1)) << 8);
|
||||
});
|
||||
ON_CALL(*this, ReadWordLong(::testing::_))
|
||||
.WillByDefault([this](uint16_t address) {
|
||||
.WillByDefault([this](uint32_t address) {
|
||||
return static_cast<uint32_t>(memory_.at(address)) |
|
||||
(static_cast<uint32_t>(memory_.at(address + 1)) << 8) |
|
||||
(static_cast<uint32_t>(memory_.at(address + 2)) << 16);
|
||||
});
|
||||
ON_CALL(*this, ReadByteVector(::testing::_, ::testing::_))
|
||||
.WillByDefault([this](uint16_t address, uint16_t length) {
|
||||
.WillByDefault([this](uint32_t address, uint16_t length) {
|
||||
std::vector<uint8_t> data;
|
||||
for (int i = 0; i < length; i++) {
|
||||
data.push_back(memory_.at(address + i));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "app/emu/cpu.h"
|
||||
#include "app/emu/memory/memory.h"
|
||||
#include "app/emu/video/ppu.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
@@ -31,8 +32,9 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
}
|
||||
|
||||
void LoadObject(uint16_t objectId) {
|
||||
rom_data_ = rom()->vector();
|
||||
// Prepare the CPU and memory environment
|
||||
memory_.Initialize(rom()->vector());
|
||||
memory_.Initialize(rom_data_);
|
||||
|
||||
// Fetch the subtype pointers for the given object ID
|
||||
auto subtypeInfo = FetchSubtypeInfo(objectId);
|
||||
@@ -44,11 +46,12 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
RenderObject(subtypeInfo);
|
||||
}
|
||||
|
||||
gfx::Bitmap* bitmap() { return &bitmap_; }
|
||||
|
||||
private:
|
||||
struct SubtypeInfo {
|
||||
uint16_t subtypePtr;
|
||||
uint16_t routinePtr;
|
||||
// Additional fields as needed
|
||||
uint32_t subtypePtr;
|
||||
uint32_t routinePtr;
|
||||
};
|
||||
|
||||
SubtypeInfo FetchSubtypeInfo(uint16_t objectId) {
|
||||
@@ -56,13 +59,19 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
|
||||
// Determine the subtype based on objectId
|
||||
// Assuming subtype is determined by some bits in objectId; modify as needed
|
||||
uint8_t subtype = (objectId >> 8) & 0xFF; // Example: top 8 bits
|
||||
uint8_t subtype = 1; // Example: top 8 bits
|
||||
|
||||
// Based on the subtype, fetch the correct pointers
|
||||
switch (subtype) {
|
||||
case 1: // Subtype 1
|
||||
info.subtypePtr = core::subtype1_tiles + (objectId & 0xFF) * 2;
|
||||
info.routinePtr = core::subtype1_tiles + 0x200 + (objectId & 0xFF) * 2;
|
||||
std::cout << "Subtype 1 " << std::hex << info.subtypePtr << std::endl;
|
||||
info.routinePtr =
|
||||
memory_.ReadWord(core::MapBankToWordAddress(0x01, info.routinePtr));
|
||||
std::cout << "Subtype 1 " << std::hex << info.routinePtr << std::endl;
|
||||
std::cout << "Subtype 1 " << std::hex << core::SnesToPc(info.routinePtr)
|
||||
<< std::endl;
|
||||
break;
|
||||
case 2: // Subtype 2
|
||||
info.subtypePtr = core::subtype2_tiles + (objectId & 0x7F) * 2;
|
||||
@@ -86,13 +95,57 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
}
|
||||
|
||||
void ConfigureObject(const SubtypeInfo& info) {
|
||||
// TODO: Use the information in info to set up the object's initial state
|
||||
cpu.A = 0x00;
|
||||
cpu.X = 0x00;
|
||||
|
||||
// Might need to set the height and width manually?
|
||||
}
|
||||
|
||||
/**
|
||||
* Example:
|
||||
* the STA $BF, $CD, $C2, $CE are the location of the object in the room
|
||||
* $B2 is used for size loop
|
||||
* so if object size is setted on 07 that draw code will be repeated 7 times
|
||||
* and since Y is increasing by 4 it makes the object draw from left to right
|
||||
|
||||
RoomDraw_Rightwards2x2_1to15or32:
|
||||
#_018B89: JSR RoomDraw_GetSize_1to15or32
|
||||
|
||||
.next
|
||||
#_018B8C: JSR RoomDraw_Rightwards2x2
|
||||
|
||||
#_018B8F: DEC.b $B2
|
||||
#_018B91: BNE .next
|
||||
|
||||
#_018B93: RTS
|
||||
|
||||
RoomDraw_Rightwards2x2:
|
||||
#_019895: LDA.w RoomDrawObjectData+0,X
|
||||
#_019898: STA.b [$BF],Y
|
||||
|
||||
#_01989A: LDA.w RoomDrawObjectData+2,X
|
||||
#_01989D: STA.b [$CB],Y
|
||||
|
||||
#_01989F: LDA.w RoomDrawObjectData+4,X
|
||||
#_0198A2: STA.b [$C2],Y
|
||||
|
||||
#_0198A4: LDA.w RoomDrawObjectData+6,X
|
||||
#_0198A7: STA.b [$CE],Y
|
||||
|
||||
#_0198A9: INY
|
||||
#_0198AA: INY
|
||||
#_0198AB: INY
|
||||
#_0198AC: INY
|
||||
|
||||
#_0198AD: RTS
|
||||
*
|
||||
*/
|
||||
|
||||
void RenderObject(const SubtypeInfo& info) {
|
||||
cpu.PC = info.routinePtr;
|
||||
cpu.PB = 0x01;
|
||||
|
||||
int i = 0;
|
||||
while (true) {
|
||||
uint8_t opcode = cpu.FetchByte();
|
||||
cpu.ExecuteInstruction(opcode);
|
||||
@@ -103,12 +156,32 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i > 50) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
||||
UpdateObjectBitmap();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateObjectBitmap() {
|
||||
// TODO: Implement logic to transfer object draw data to the Bitmap
|
||||
// Object draw data
|
||||
uint8_t room_object_draw_data0 = memory_.ReadByte(0x7E00BF);
|
||||
uint8_t room_object_draw_data1 = memory_.ReadByte(0x7E00CB);
|
||||
uint8_t room_object_draw_data2 = memory_.ReadByte(0x7E00C2);
|
||||
uint8_t room_object_draw_data3 = memory_.ReadByte(0x7E00CE);
|
||||
|
||||
// Used with Y to index the room object draw data
|
||||
uint8_t size_loop = memory_.ReadByte(0x7E00B2);
|
||||
|
||||
// Update the bitmap with this data by copying the tiles from vram.
|
||||
|
||||
std::cout << "Object draw data: " << std::hex << (int)room_object_draw_data0
|
||||
<< " " << (int)room_object_draw_data1 << " "
|
||||
<< (int)room_object_draw_data2 << " "
|
||||
<< (int)room_object_draw_data3 << std::endl;
|
||||
std::cout << "Size loop: " << std::hex << (int)size_loop << std::endl;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> rom_data_;
|
||||
@@ -116,7 +189,7 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
emu::ClockImpl clock_;
|
||||
emu::CPU cpu{memory_, clock_};
|
||||
emu::PPU ppu{memory_, clock_};
|
||||
gfx::Bitmap bitmap;
|
||||
gfx::Bitmap bitmap_;
|
||||
PseudoVram vram_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user