yaze 0.2.0
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
screen_editor.cc
Go to the documentation of this file.
1#include "screen_editor.h"
2
3#include <algorithm>
4#include <fstream>
5#include <iostream>
6#include <sstream>
7#include <string>
8
9#include "absl/status/statusor.h"
10#include "absl/strings/str_format.h"
11#include "absl/strings/string_view.h"
12#include "app/core/constants.h"
14#include "app/gfx/bitmap.h"
15#include "app/gfx/snes_tile.h"
16#include "app/gfx/tilesheet.h"
17#include "app/gui/canvas.h"
18#include "app/gui/icons.h"
19#include "app/gui/input.h"
21#include "imgui/imgui.h"
22
23namespace yaze {
24namespace app {
25namespace editor {
26
27using core::Renderer;
28
29constexpr uint32_t kRedPen = 0xFF0000FF;
30
31absl::Status ScreenEditor::Update() {
32 TAB_BAR("##TabBar")
33 TAB_ITEM("Dungeon Maps")
34 if (rom()->is_loaded()) {
36 }
43
44 return absl::OkStatus();
45}
46
48 TAB_ITEM("Inventory Menu")
49
50 static bool create = false;
51 if (!create && rom()->is_loaded()) {
54 create = true;
55 }
56
58
59 if (ImGui::BeginTable("InventoryScreen", 3, ImGuiTableFlags_Resizable)) {
60 ImGui::TableSetupColumn("Canvas");
61 ImGui::TableSetupColumn("Tiles");
62 ImGui::TableSetupColumn("Palette");
63 ImGui::TableHeadersRow();
64
65 ImGui::TableNextColumn();
71
72 ImGui::TableNextColumn();
73 tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4));
78
79 ImGui::TableNextColumn();
81
82 ImGui::EndTable();
83 }
84 ImGui::Separator();
86}
87
89 if (ImGui::BeginTable("InventoryToolset", 8, ImGuiTableFlags_SizingFixedFit,
90 ImVec2(0, 0))) {
91 ImGui::TableSetupColumn("#drawTool");
92 ImGui::TableSetupColumn("#sep1");
93 ImGui::TableSetupColumn("#zoomOut");
94 ImGui::TableSetupColumn("#zoomIN");
95 ImGui::TableSetupColumn("#sep2");
96 ImGui::TableSetupColumn("#bg2Tool");
97 ImGui::TableSetupColumn("#bg3Tool");
98 ImGui::TableSetupColumn("#itemTool");
99
108
109 ImGui::EndTable();
110 }
111}
112
114 std::vector<std::array<uint8_t, 25>> current_floor_rooms_d;
115 std::vector<std::array<uint8_t, 25>> current_floor_gfx_d;
116 int total_floors_d;
117 uint8_t nbr_floor_d;
118 uint8_t nbr_basement_d;
119
120 for (int d = 0; d < 14; d++) {
121 current_floor_rooms_d.clear();
122 current_floor_gfx_d.clear();
124 int ptr,
125 rom()->ReadWord(zelda3::screen::kDungeonMapRoomsPtr + (d * 2)));
127 int ptrGFX,
128 rom()->ReadWord(zelda3::screen::kDungeonMapRoomsPtr + (d * 2)));
129 ptr |= 0x0A0000; // Add bank to the short ptr
130 ptrGFX |= 0x0A0000; // Add bank to the short ptr
131 int pcPtr = core::SnesToPc(ptr); // Contains data for the next 25 rooms
132 int pcPtrGFX =
133 core::SnesToPc(ptrGFX); // Contains data for the next 25 rooms
134
136 ushort bossRoomD,
137 rom()->ReadWord(zelda3::screen::kDungeonMapBossRooms + (d * 2)));
138
140 nbr_basement_d,
141 rom()->ReadByte(zelda3::screen::kDungeonMapFloors + (d * 2)));
142 nbr_basement_d &= 0x0F;
143
145 nbr_floor_d,
146 rom()->ReadByte(zelda3::screen::kDungeonMapFloors + (d * 2)));
147 nbr_floor_d &= 0xF0;
148 nbr_floor_d = nbr_floor_d >> 4;
149
150 total_floors_d = nbr_basement_d + nbr_floor_d;
151
152 dungeon_map_labels_.emplace_back();
153
154 // for each floor in the dungeon
155 for (int i = 0; i < total_floors_d; i++) {
156 dungeon_map_labels_[d].emplace_back();
157
158 std::array<uint8_t, 25> rdata;
159 std::array<uint8_t, 25> gdata;
160
161 // for each room on the floor
162 for (int j = 0; j < 25; j++) {
163 // rdata[j] = 0x0F;
164 gdata[j] = 0xFF;
165 rdata[j] = rom()->data()[pcPtr + j + (i * 25)]; // Set the rooms
166
167 if (rdata[j] == 0x0F) {
168 gdata[j] = 0xFF;
169 } else {
170 gdata[j] = rom()->data()[pcPtrGFX++];
171 }
172
173 std::string label = core::UppercaseHexByte(rdata[j]);
174 dungeon_map_labels_[d][i][j] = label;
175 }
176
177 current_floor_gfx_d.push_back(gdata); // Add new floor gfx data
178 current_floor_rooms_d.push_back(rdata); // Add new floor data
179 }
180
181 dungeon_maps_.emplace_back(bossRoomD, nbr_floor_d, nbr_basement_d,
182 current_floor_rooms_d, current_floor_gfx_d);
183 }
184
185 return absl::OkStatus();
186}
187
189 for (int d = 0; d < 14; d++) {
190 int ptr = zelda3::screen::kDungeonMapRoomsPtr + (d * 2);
191 int ptrGFX = zelda3::screen::kDungeonMapGfxPtr + (d * 2);
192 int pcPtr = core::SnesToPc(ptr);
193 int pcPtrGFX = core::SnesToPc(ptrGFX);
194
195 const int nbr_floors = dungeon_maps_[d].nbr_of_floor;
196 const int nbr_basements = dungeon_maps_[d].nbr_of_basement;
197 for (int i = 0; i < nbr_floors + nbr_basements; i++) {
198 for (int j = 0; j < 25; j++) {
199 RETURN_IF_ERROR(rom()->WriteByte(pcPtr + j + (i * 25),
200 dungeon_maps_[d].floor_rooms[i][j]));
201 RETURN_IF_ERROR(rom()->WriteByte(pcPtrGFX + j + (i * 25),
202 dungeon_maps_[d].floor_gfx[i][j]));
203 pcPtrGFX++;
204 }
205 }
206 }
207
208 return absl::OkStatus();
209}
210
213
214 for (int i = 0; i < 186; i++) {
216 if (rom()->data()[zelda3::screen::kDungeonMapExpCheck] != 0xB9) {
218 }
219
220 ASSIGN_OR_RETURN(auto tl, rom()->ReadWord(addr + (i * 8)));
221 gfx::TileInfo t1 = gfx::WordToTileInfo(tl); // Top left
222
223 ASSIGN_OR_RETURN(auto tr, rom()->ReadWord(addr + 2 + (i * 8)));
224 gfx::TileInfo t2 = gfx::WordToTileInfo(tr); // Top right
225
226 ASSIGN_OR_RETURN(auto bl, rom()->ReadWord(addr + 4 + (i * 8)));
227 gfx::TileInfo t3 = gfx::WordToTileInfo(bl); // Bottom left
228
229 ASSIGN_OR_RETURN(auto br, rom()->ReadWord(addr + 6 + (i * 8)));
230 gfx::TileInfo t4 = gfx::WordToTileInfo(br); // Bottom right
231
232 tile16_sheet_.ComposeTile16(rom()->graphics_buffer(), t1, t2, t3, t4);
233 }
234
236 *rom()->mutable_dungeon_palette(3)));
238
239 for (int i = 0; i < tile16_sheet_.num_tiles(); ++i) {
240 if (tile16_individual_.count(i) == 0) {
241 auto tile = tile16_sheet_.GetTile16(i);
242 tile16_individual_[i] = tile;
244 }
245 }
246
247 return absl::OkStatus();
248}
249
251 auto current_dungeon = dungeon_maps_[selected_dungeon];
252 if (ImGui::BeginTabBar("##DungeonMapTabs")) {
253 auto nbr_floors =
254 current_dungeon.nbr_of_floor + current_dungeon.nbr_of_basement;
255 for (int i = 0; i < nbr_floors; i++) {
256 std::string tab_name = absl::StrFormat("Floor %d", i + 1);
257 if (i >= current_dungeon.nbr_of_floor) {
258 tab_name = absl::StrFormat("Basement %d",
259 i - current_dungeon.nbr_of_floor + 1);
260 }
261
262 if (ImGui::BeginTabItem(tab_name.c_str())) {
263 floor_number = i;
264 // screen_canvas_.LoadCustomLabels(dungeon_map_labels_[selected_dungeon]);
265 // screen_canvas_.set_current_labels(floor_number);
266 screen_canvas_.DrawBackground(ImVec2(325, 325));
268
269 auto boss_room = current_dungeon.boss_room;
270 for (int j = 0; j < 25; j++) {
271 if (current_dungeon.floor_rooms[floor_number][j] != 0x0F) {
272 int tile16_id = current_dungeon.floor_rooms[floor_number][j];
273 int posX = ((j % 5) * 32);
274 int posY = ((j / 5) * 32);
275
276 if (tile16_individual_.count(tile16_id) == 0) {
277 auto tile = tile16_sheet_.GetTile16(tile16_id);
278 std::cout << "Tile16: " << tile16_id << std::endl;
280 tile16_individual_[tile16_id] = tile;
281 }
282 screen_canvas_.DrawBitmap(tile16_individual_[tile16_id], (posX * 2),
283 (posY * 2), 4.0f);
284
285 if (current_dungeon.floor_rooms[floor_number][j] == boss_room) {
286 screen_canvas_.DrawOutlineWithColor((posX * 2), (posY * 2), 64,
287 64, kRedPen);
288 }
289
290 std::string label =
292 screen_canvas_.DrawText(label, (posX * 2), (posY * 2));
293 }
294 }
295
296 screen_canvas_.DrawGrid(64.f, 5);
298
299 if (!screen_canvas_.points().empty()) {
300 int x = screen_canvas_.points().front().x / 64;
301 int y = screen_canvas_.points().front().y / 64;
302 selected_room = x + (y * 5);
303 }
304 ImGui::EndTabItem();
305 }
306 }
307 ImGui::EndTabBar();
308 }
309
311 "Selected Room",
312 &current_dungeon.floor_rooms[floor_number].at(selected_room));
313
314 gui::InputHexWord("Boss Room", &current_dungeon.boss_room);
315
316 if (ImGui::Button("Copy Floor", ImVec2(100, 0))) {
317 copy_button_pressed = true;
318 }
319 ImGui::SameLine();
320 if (ImGui::Button("Paste Floor", ImVec2(100, 0))) {
322 }
323}
324
327 if (LoadDungeonMaps().ok()) {
328 if (LoadDungeonMapTile16().ok()) {
329 sheets_.emplace(0, rom()->gfx_sheets()[212]);
330 sheets_.emplace(1, rom()->gfx_sheets()[213]);
331 sheets_.emplace(2, rom()->gfx_sheets()[214]);
332 sheets_.emplace(3, rom()->gfx_sheets()[215]);
334 } else {
335 ImGui::Text("Failed to load dungeon map tile16");
336 }
337 } else {
338 ImGui::Text("Failed to load dungeon maps");
339 }
340 }
341
342 static std::vector<std::string> dungeon_names = {
343 "Sewers/Sanctuary", "Hyrule Castle", "Eastern Palace",
344 "Desert Palace", "Tower of Hera", "Agahnim's Tower",
345 "Palace of Darkness", "Swamp Palace", "Skull Woods",
346 "Thieves' Town", "Ice Palace", "Misery Mire",
347 "Turtle Rock", "Ganon's Tower"};
348
349 if (ImGui::BeginTable("DungeonMapsTable", 4, ImGuiTableFlags_Resizable)) {
350 ImGui::TableSetupColumn("Dungeon");
351 ImGui::TableSetupColumn("Map");
352 ImGui::TableSetupColumn("Rooms Gfx");
353 ImGui::TableSetupColumn("Tiles Gfx");
354 ImGui::TableHeadersRow();
355
356 // Dungeon column
357 ImGui::TableNextColumn();
358 for (int i = 0; i < dungeon_names.size(); i++) {
359 rom()->resource_label()->SelectableLabelWithNameEdit(
360 selected_dungeon == i, "Dungeon Names", absl::StrFormat("%d", i),
361 dungeon_names[i]);
362 if (ImGui::IsItemClicked()) {
364 }
365 }
366
367 // Map column
368 ImGui::TableNextColumn();
370
371 ImGui::TableNextColumn();
372 if (ImGui::BeginChild("##DungeonMapTiles", ImVec2(0, 0), true)) {
373 tilesheet_canvas_.DrawBackground(ImVec2((256 * 2) + 2, (192 * 2) + 4));
379
380 if (!tilesheet_canvas_.points().empty()) {
381 selected_tile16_ = tilesheet_canvas_.points().front().x / 32 +
382 (tilesheet_canvas_.points().front().y / 32) * 16;
383 }
384 }
385 ImGui::EndChild();
386
387 ImGui::TableNextColumn();
388 tilemap_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4));
393
394 ImGui::EndTable();
395 }
396}
397
399 TAB_ITEM("Title Screen")
401}
403 TAB_ITEM("Naming Screen")
405}
407 TAB_ITEM("Overworld Map")
409}
410
412 static bool show_bg1 = true;
413 static bool show_bg2 = true;
414 static bool show_bg3 = true;
415
416 static bool drawing_bg1 = true;
417 static bool drawing_bg2 = false;
418 static bool drawing_bg3 = false;
419
420 ImGui::Checkbox("Show BG1", &show_bg1);
421 ImGui::SameLine();
422 ImGui::Checkbox("Show BG2", &show_bg2);
423
424 ImGui::Checkbox("Draw BG1", &drawing_bg1);
425 ImGui::SameLine();
426 ImGui::Checkbox("Draw BG2", &drawing_bg2);
427 ImGui::SameLine();
428 ImGui::Checkbox("Draw BG3", &drawing_bg3);
429}
430
431} // namespace editor
432} // namespace app
433} // namespace yaze
static Renderer & GetInstance()
Definition renderer.h:30
void RenderBitmap(gfx::Bitmap *bitmap)
Used to render a bitmap to the screen.
Definition renderer.h:52
std::vector< std::vector< std::array< std::string, 25 > > > dungeon_map_labels_
absl::Status Update() override
zelda3::screen::Inventory inventory_
std::vector< zelda3::screen::DungeonMap > dungeon_maps_
std::unordered_map< int, gfx::Bitmap > tile16_individual_
SNES 16-bit tile metadata container.
Definition snes_tile.h:52
void Init(int width, int height, TileType tile_type)
Definition tilesheet.cc:49
Bitmap GetTile16(int tile_x, int tile_y)
Definition tilesheet.h:54
void ComposeTile16(const std::vector< uint8_t > &graphics_buffer, const TileInfo &top_left, const TileInfo &top_right, const TileInfo &bottom_left, const TileInfo &bottom_right)
Definition tilesheet.cc:62
bool DrawTileSelector(int size)
Definition canvas.cc:343
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0), bool drag=false)
Definition canvas.cc:69
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
Definition canvas.cc:689
void DrawText(std::string text, int x, int y)
Definition canvas.cc:618
void DrawBitmap(const Bitmap &bitmap, int border_offset=0, bool ready=true)
Definition canvas.cc:464
void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color)
Definition canvas.cc:522
auto points() const
Definition canvas.h:143
void DrawBitmapTable(const BitmapTable &gfx_bin)
Definition canvas.cc:501
void DrawContextMenu(gfx::Bitmap *bitmap=nullptr)
Definition canvas.cc:104
#define TAB_BAR(w)
Definition constants.h:6
#define END_TAB_BAR()
Definition constants.h:7
#define RETURN_IF_ERROR(expression)
Definition constants.h:69
#define END_TAB_ITEM()
Definition constants.h:12
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition constants.h:77
#define TEXT_COLUMN(w)
Definition constants.h:23
#define TAB_ITEM(w)
Definition constants.h:11
unsigned short ushort
Definition constants.h:119
#define BUTTON_COLUMN(w)
Definition constants.h:19
#define ICON_MD_MORE_VERT
Definition icons.h:1241
#define ICON_MD_DRAW
Definition icons.h:623
#define ICON_MD_ZOOM_OUT
Definition icons.h:2191
#define ICON_MD_REDO
Definition icons.h:1568
#define ICON_MD_BUILD
Definition icons.h:326
#define ICON_MD_ZOOM_IN
Definition icons.h:2189
#define ICON_MD_UNDO
Definition icons.h:2034
uint32_t SnesToPc(uint32_t addr) noexcept
Definition common.h:223
std::string UppercaseHexByte(uint8_t byte, bool leading)
Definition labeling.cc:21
constexpr uint32_t kRedPen
TileInfo WordToTileInfo(uint16_t word)
Definition snes_tile.cc:324
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
Definition input.cc:176
absl::Status DisplayPalette(app::gfx::SnesPalette &palette, bool loaded)
Definition color.cc:56
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)
Definition input.cc:162
constexpr int kDungeonMapTile16Expanded
Definition dungeon_map.h:23
constexpr int kDungeonMapGfxPtr
Definition dungeon_map.h:15
constexpr int kDungeonMapBossRooms
Definition dungeon_map.h:26
constexpr int kDungeonMapTile16
Definition dungeon_map.h:22
constexpr int kDungeonMapFloors
Definition dungeon_map.h:13
constexpr int kDungeonMapRoomsPtr
Definition dungeon_map.h:12
constexpr int kDungeonMapExpCheck
Definition dungeon_map.h:21
Definition common.cc:21