yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
tile16_editor.cc
Go to the documentation of this file.
1#include "tile16_editor.h"
2
3#include <future>
4
5#include "absl/status/status.h"
8#include "app/gfx/bitmap.h"
10#include "app/gui/canvas.h"
11#include "app/gui/input.h"
12#include "app/gui/style.h"
13#include "app/rom.h"
15#include "imgui/imgui.h"
16#include "util/hex.h"
17
18namespace yaze {
19namespace editor {
20
21using core::Renderer;
22
23using ImGui::BeginChild;
24using ImGui::BeginMenu;
25using ImGui::BeginMenuBar;
26using ImGui::BeginTabBar;
27using ImGui::BeginTabItem;
28using ImGui::BeginTable;
29using ImGui::Button;
30using ImGui::Checkbox;
31using ImGui::EndChild;
32using ImGui::EndMenu;
33using ImGui::EndMenuBar;
34using ImGui::EndTabBar;
35using ImGui::EndTabItem;
36using ImGui::EndTable;
37using ImGui::GetContentRegionAvail;
38using ImGui::Separator;
39using ImGui::TableHeadersRow;
40using ImGui::TableNextColumn;
41using ImGui::TableNextRow;
42using ImGui::TableSetupColumn;
43using ImGui::Text;
44
46 const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap &current_gfx_bmp,
47 std::array<uint8_t, 0x200> &all_tiles_types) {
48 all_tiles_types_ = all_tiles_types;
49 current_gfx_bmp_.Create(current_gfx_bmp.width(), current_gfx_bmp.height(),
50 current_gfx_bmp.depth(), current_gfx_bmp.vector());
51 RETURN_IF_ERROR(current_gfx_bmp_.SetPalette(current_gfx_bmp.palette()));
54 tile16_blockset_bmp.width(), tile16_blockset_bmp.height(),
55 tile16_blockset_bmp.depth(), tile16_blockset_bmp.vector());
57 tile16_blockset_bmp_.SetPalette(tile16_blockset_bmp.palette()));
60 ImVector<std::string> tile16_names;
61 for (int i = 0; i < 0x200; ++i) {
62 std::string str = util::HexByte(all_tiles_types_[i]);
63 tile16_names.push_back(str);
64 }
65 *tile8_source_canvas_.mutable_labels(0) = tile16_names;
66 *tile8_source_canvas_.custom_labels_enabled() = true;
67
68 gui::AddTableColumn(tile_edit_table_, "##tile16ID", [&]() {
69 ImGui::Text("Tile16 ID: %02X", current_tile16_);
70 });
72 [&]() { ImGui::Text("Tile8 ID: %02X", current_tile8_); });
73
74 gui::AddTableColumn(tile_edit_table_, "##tile16Flip", [&]() {
75 ImGui::Checkbox("X Flip", &x_flip);
76 ImGui::Checkbox("Y Flip", &y_flip);
77 ImGui::Checkbox("Priority", &priority_tile);
78 });
79
80 return absl::OkStatus();
81}
82
83absl::Status Tile16Editor::Update() {
85 return absl::InvalidArgumentError("Blockset not initialized, open a ROM.");
86 }
87
88 if (BeginMenuBar()) {
89 if (BeginMenu("View")) {
90 Checkbox("Show Collision Types",
91 tile8_source_canvas_.custom_labels_enabled());
92 EndMenu();
93 }
94 EndMenuBar();
95 }
96
97 if (BeginTabBar("Tile16 Editor Tabs")) {
100 EndTabBar();
101 }
102 return absl::OkStatus();
103}
104
106 if (BeginTabItem("Tile16 Editing")) {
107 if (BeginTable("#Tile16EditorTable", 2, TABLE_BORDERS_RESIZABLE,
108 ImVec2(0, 0))) {
109 TableSetupColumn("Blockset", ImGuiTableColumnFlags_WidthFixed,
110 GetContentRegionAvail().x);
111 TableSetupColumn("Properties", ImGuiTableColumnFlags_WidthStretch,
112 GetContentRegionAvail().x);
113 TableHeadersRow();
114 TableNextRow();
115 TableNextColumn();
117
118 TableNextColumn();
120
121 EndTable();
122 }
123 EndTabItem();
124 }
125}
126
129 gui::BeginChildWithScrollbar("##Tile16EditorBlocksetScrollRegion");
130 blockset_canvas_.DrawBackground();
132 blockset_canvas_.DrawContextMenu();
133 blockset_canvas_.DrawTileSelector(32);
135 blockset_canvas_.DrawGrid();
136 blockset_canvas_.DrawOverlay();
137 EndChild();
138
139 if (!blockset_canvas_.points().empty()) {
140 notify_tile16.edit() = blockset_canvas_.GetTileIdFromMousePos();
141 notify_tile16.commit();
142
143 if (notify_tile16.modified()) {
146 auto ow_main_pal_group = rom()->palette_group().overworld_main;
148 current_tile16_bmp_.SetPalette(ow_main_pal_group[current_palette_]));
150 }
151 }
152
153 return absl::OkStatus();
154}
155
156absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) {
157 constexpr int tile8_size = 8;
158 constexpr int tile16_size = 16;
159
160 // Calculate the tile index for x and y based on the click_position
161 // Adjusting for Tile16 (16x16) which contains 4 Tile8 (8x8)
162 int tile_index_x = static_cast<int>(click_position.x) / tile8_size;
163 int tile_index_y = static_cast<int>(click_position.y) / tile8_size;
164 std::cout << "Tile Index X: " << tile_index_x << std::endl;
165 std::cout << "Tile Index Y: " << tile_index_y << std::endl;
166
167 // Calculate the pixel start position within the Tile16
168 ImVec2 start_position;
169 start_position.x = tile_index_x * 0x40;
170 start_position.y = tile_index_y * 0x40;
171 std::cout << "Start Position X: " << start_position.x << std::endl;
172 std::cout << "Start Position Y: " << start_position.y << std::endl;
173
174 // Draw the Tile8 to the correct position within the Tile16
175 for (int y = 0; y < tile8_size; ++y) {
176 for (int x = 0; x < tile8_size; ++x) {
177 int pixel_index =
178 (start_position.y + y) * tile16_size + ((start_position.x) + x);
179 int gfx_pixel_index = y * tile8_size + x;
180 current_tile16_bmp_.WriteToPixel(
181 pixel_index,
182 current_gfx_individual_[current_tile8_].data()[gfx_pixel_index]);
183 }
184 }
185
186 return absl::OkStatus();
187}
188
190 auto ow_main_pal_group = rom()->palette_group().overworld_main;
191
192 if (BeginChild("Tile8 Selector", ImVec2(GetContentRegionAvail().x, 0x175),
193 true)) {
194 tile8_source_canvas_.DrawBackground();
195 tile8_source_canvas_.DrawContextMenu(&current_gfx_bmp_);
196 if (tile8_source_canvas_.DrawTileSelector(32)) {
198 current_gfx_individual_[current_tile8_].SetPaletteWithTransparent(
199 ow_main_pal_group[0], current_palette_));
202 }
203 tile8_source_canvas_.DrawBitmap(current_gfx_bmp_, 0, 0, 4.0f);
204 tile8_source_canvas_.DrawGrid();
205 tile8_source_canvas_.DrawOverlay();
206 }
207 EndChild();
208
209 // The user selected a tile8
210 if (!tile8_source_canvas_.points().empty()) {
211 uint16_t x = tile8_source_canvas_.points().front().x / 16;
212 uint16_t y = tile8_source_canvas_.points().front().y / 16;
213
214 current_tile8_ = x + (y * 8);
216 current_gfx_individual_[current_tile8_].SetPaletteWithTransparent(
217 ow_main_pal_group[0], current_palette_));
220 }
221
222 if (BeginChild("Tile16 Editor Options",
223 ImVec2(GetContentRegionAvail().x, 0x50), true)) {
224 tile16_edit_canvas_.DrawBackground();
226 tile16_edit_canvas_.DrawBitmap(current_tile16_bmp_, 0, 0, 4.0f);
227 if (!tile8_source_canvas_.points().empty()) {
228 if (tile16_edit_canvas_.DrawTilePainter(
231 DrawToCurrentTile16(tile16_edit_canvas_.drawn_tile_position()));
233 }
234 }
235 tile16_edit_canvas_.DrawGrid();
236 tile16_edit_canvas_.DrawOverlay();
237 }
238 EndChild();
239
240 Separator();
241 Text("Options:");
242 gui::InputHexByte("Palette", &notify_palette.edit());
243 notify_palette.commit();
244 if (notify_palette.modified()) {
245 auto palette = palettesets_[current_palette_].main_;
246 auto value = notify_palette.get();
247 if (notify_palette.get() > 0x04 && notify_palette.get() < 0x06) {
248 palette = palettesets_[current_palette_].aux1;
249 value -= 0x04;
250 } else if (notify_palette.get() > 0x06) {
251 palette = palettesets_[current_palette_].aux2;
252 value -= 0x06;
253 }
254
255 if (value > 0x00) {
257 current_gfx_bmp_.SetPaletteWithTransparent(palette, value));
259
261 current_tile16_bmp_.SetPaletteWithTransparent(palette, value));
263 }
264 }
266 return absl::OkStatus();
267}
268
270 auto ow_main_pal_group = rom()->palette_group().overworld_main;
271 current_gfx_individual_.reserve(1024);
272
273 std::vector<std::future<std::array<uint8_t, 0x40>>> futures;
274
275 for (int index = 0; index < 1024; index++) {
276 auto task_function = [&]() {
277 std::array<uint8_t, 0x40> tile_data;
278 // Copy the pixel data for the current tile into the vector
279 for (int ty = 0; ty < 8; ty++) {
280 for (int tx = 0; tx < 8; tx++) {
281 // Current Gfx Data is 16 sheets of 8x8 tiles ordered 16 wide by 4
282 // tall
283
284 // Calculate the position in the tile data vector
285 int position = tx + (ty * 0x08);
286
287 // Calculate the position in the current gfx data
288 int num_columns = current_gfx_bmp_.width() / 8;
289 int x = (index % num_columns) * 8 + tx;
290 int y = (index / num_columns) * 8 + ty;
291 int gfx_position = x + (y * 0x100);
292
293 // Get the pixel value from the current gfx data
294 uint8_t value = current_gfx_bmp_.data()[gfx_position];
295
296 if (value & 0x80) {
297 value -= 0x88;
298 }
299
300 tile_data[position] = value;
301 }
302 }
303 return tile_data;
304 };
305 futures.emplace_back(std::async(std::launch::async, task_function));
306 }
307
308 for (auto &future : futures) {
309 future.wait();
310 auto tile_data = future.get();
311 current_gfx_individual_.emplace_back();
312 auto &tile_bitmap = current_gfx_individual_.back();
313 tile_bitmap.Create(0x08, 0x08, 0x08, tile_data);
314 RETURN_IF_ERROR(tile_bitmap.SetPaletteWithTransparent(ow_main_pal_group[0],
316 Renderer::GetInstance().RenderBitmap(&tile_bitmap);
317 }
318
320
321 return absl::OkStatus();
322}
323
324absl::Status Tile16Editor::SetCurrentTile(int id) {
325 current_tile16_ = id;
327 auto ow_main_pal_group = rom()->palette_group().overworld_main;
329 current_tile16_bmp_.SetPalette(ow_main_pal_group[current_palette_]));
331 return absl::OkStatus();
332}
333
334#pragma mark - Tile16Transfer
335
337 if (BeginTabItem("Tile16 Transfer")) {
338 if (BeginTable("#Tile16TransferTable", 2, TABLE_BORDERS_RESIZABLE,
339 ImVec2(0, 0))) {
340 TableSetupColumn("Current ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
341 GetContentRegionAvail().x / 2);
342 TableSetupColumn("Transfer ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
343 GetContentRegionAvail().x / 2);
344 TableHeadersRow();
345 TableNextRow();
346
347 TableNextColumn();
349
350 TableNextColumn();
352
353 EndTable();
354 }
355
356 EndTabItem();
357 }
358 return absl::OkStatus();
359}
360
362 // Create a button for loading another ROM
363 if (Button("Load ROM")) {
365 transfer_status_ = transfer_rom_.LoadFromFile(file_name);
366 transfer_started_ = true;
367 }
368
369 // TODO: Implement tile16 transfer
372
373 // Load the Link to the Past overworld.
375 transfer_overworld_.set_current_map(0);
376 palette_ = transfer_overworld_.current_area_palette();
377
378 // Create the tile16 blockset image
380 0x80, 0x2000, 0x80, transfer_overworld_.tile16_blockset_data(),
383 }
384
385 // Create a canvas for holding the tiles which will be exported
387 (8192 * 2), 0x20, transfer_blockset_loaded_, true,
388 3);
389
390 return absl::OkStatus();
391}
392
393} // namespace editor
394} // namespace yaze
auto rom()
Definition rom.h:382
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath.
void CreateAndRenderBitmap(int width, int height, int depth, const std::vector< uint8_t > &data, gfx::Bitmap &bitmap, gfx::SnesPalette &palette)
Definition renderer.h:59
void UpdateBitmap(gfx::Bitmap *bitmap)
Used to update a bitmap on the screen.
Definition renderer.h:55
static Renderer & GetInstance()
Definition renderer.h:26
void RenderBitmap(gfx::Bitmap *bitmap)
Used to render a bitmap to the screen.
Definition renderer.h:48
static Renderer & GetInstance()
Definition renderer.h:26
util::NotifyValue< uint32_t > notify_tile16
absl::Status UpdateTransferTileCanvas()
std::array< uint8_t, 0x200 > all_tiles_types_
gfx::SnesPalette palette_
absl::Status UpdateTile16Transfer()
absl::Status Initialize(const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap &current_gfx_bmp, std::array< uint8_t, 0x200 > &all_tiles_types)
absl::Status SetCurrentTile(int id)
absl::Status DrawToCurrentTile16(ImVec2 pos)
zelda3::Overworld transfer_overworld_
std::vector< gfx::Bitmap > current_gfx_individual_
std::array< gfx::Bitmap, kNumGfxSheets > transfer_gfx_
std::array< gfx::Bitmap, zelda3::kNumTile16Individual > & tile16_individual_
util::NotifyValue< uint8_t > notify_palette
Represents a bitmap image.
Definition bitmap.h:67
auto vector() const
Definition bitmap.h:167
int height() const
Definition bitmap.h:160
int width() const
Definition bitmap.h:159
auto palette() const
Definition bitmap.h:156
auto depth() const
Definition bitmap.h:161
static std::unordered_map< uint8_t, gfx::Paletteset > palettesets_
#define TABLE_BORDERS_RESIZABLE
Definition macro.h:91
#define PRINT_IF_ERROR(expression)
Definition macro.h:25
#define RETURN_IF_ERROR(expression)
Definition macro.h:51
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:59
Editors are the view controllers for the application.
void BitmapCanvasPipeline(gui::Canvas &canvas, const gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id)
Definition canvas.cc:831
void BeginPadding(int i)
Definition style.cc:372
void AddTableColumn(Table &table, const std::string &label, GuiElement element)
Definition input.cc:337
void DrawTable(Table &params)
Definition input.cc:343
void EndPadding()
Definition style.cc:376
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
Definition input.cc:167
void BeginChildWithScrollbar(const char *str_id)
Definition style.cc:384
std::string HexByte(uint8_t byte, HexStringParams params)
Definition hex.cc:33
Main namespace for the application.
Definition controller.cc:18
absl::StatusOr< std::array< gfx::Bitmap, kNumGfxSheets > > LoadAllGraphicsData(Rom &rom, bool defer_render)
This function iterates over all graphics sheets in the Rom and loads them into memory....
Definition rom.cc:77