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_.ApplyPalette(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_.ApplyPalette(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 return absl::OkStatus();
68}
69
70absl::Status Tile16Editor::Update() {
72 return absl::InvalidArgumentError("Blockset not initialized, open a ROM.");
73 }
74
76 if (BeginTabBar("Tile16 Editor Tabs")) {
79 EndTabBar();
80 }
81
82 return absl::OkStatus();
83}
84
85absl::Status Tile16Editor::DrawMenu() {
86 if (BeginMenuBar()) {
87 if (BeginMenu("View")) {
88 Checkbox("Show Collision Types",
89 tile8_source_canvas_.custom_labels_enabled());
90 EndMenu();
91 }
92
93 EndMenuBar();
94 }
95
96 return absl::OkStatus();
97}
98
100 if (BeginTabItem("Tile16 Editing")) {
101 if (BeginTable("#Tile16EditorTable", 2, TABLE_BORDERS_RESIZABLE,
102 ImVec2(0, 0))) {
103 TableSetupColumn("Blockset", ImGuiTableColumnFlags_WidthFixed,
104 GetContentRegionAvail().x);
105 TableSetupColumn("Properties", ImGuiTableColumnFlags_WidthStretch,
106 GetContentRegionAvail().x);
107 TableHeadersRow();
108 TableNextRow();
109 TableNextColumn();
111 if (!status_.ok()) {
112 EndTable();
113 }
114
115 TableNextColumn();
117 if (status_ != absl::OkStatus()) {
118 EndTable();
119 }
121
122 EndTable();
123 }
124
125 EndTabItem();
126 }
127}
128
131 gui::BeginChildWithScrollbar("##Tile16EditorBlocksetScrollRegion");
132 blockset_canvas_.DrawBackground();
134 blockset_canvas_.DrawContextMenu();
135 blockset_canvas_.DrawTileSelector(32);
137 blockset_canvas_.DrawGrid();
138 blockset_canvas_.DrawOverlay();
139 EndChild();
140
141 if (!blockset_canvas_.points().empty()) {
142 notify_tile16.mutable_get() = blockset_canvas_.GetTileIdFromMousePos();
143 notify_tile16.apply_changes();
144
145 if (notify_tile16.modified()) {
148 auto ow_main_pal_group = rom()->palette_group().overworld_main;
150 ow_main_pal_group[current_palette_]));
152 }
153 }
154
155 return absl::OkStatus();
156}
157
158absl::Status Tile16Editor::DrawToCurrentTile16(ImVec2 click_position) {
159 constexpr int tile8_size = 8;
160 constexpr int tile16_size = 16;
161
162 // Calculate the tile index for x and y based on the click_position
163 // Adjusting for Tile16 (16x16) which contains 4 Tile8 (8x8)
164 int tile_index_x = static_cast<int>(click_position.x) / tile8_size;
165 int tile_index_y = static_cast<int>(click_position.y) / tile8_size;
166 std::cout << "Tile Index X: " << tile_index_x << std::endl;
167 std::cout << "Tile Index Y: " << tile_index_y << std::endl;
168
169 // Calculate the pixel start position within the Tile16
170 ImVec2 start_position;
171 start_position.x = tile_index_x * 0x40;
172 start_position.y = tile_index_y * 0x40;
173 std::cout << "Start Position X: " << start_position.x << std::endl;
174 std::cout << "Start Position Y: " << start_position.y << std::endl;
175
176 // Draw the Tile8 to the correct position within the Tile16
177 for (int y = 0; y < tile8_size; ++y) {
178 for (int x = 0; x < tile8_size; ++x) {
179 int pixel_index =
180 (start_position.y + y) * tile16_size + ((start_position.x) + x);
181 int gfx_pixel_index = y * tile8_size + x;
182 current_tile16_bmp_.WriteToPixel(
183 pixel_index,
184 current_gfx_individual_[current_tile8_].data()[gfx_pixel_index]);
185 }
186 }
187
188 return absl::OkStatus();
189}
190
192 auto ow_main_pal_group = rom()->palette_group().overworld_main;
193
194 if (BeginChild("Tile8 Selector", ImVec2(GetContentRegionAvail().x, 0x175),
195 true)) {
196 tile8_source_canvas_.DrawBackground();
197 tile8_source_canvas_.DrawContextMenu(&current_gfx_bmp_);
198 if (tile8_source_canvas_.DrawTileSelector(32)) {
200 current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
201 ow_main_pal_group[0], current_palette_));
204 }
205 tile8_source_canvas_.DrawBitmap(current_gfx_bmp_, 0, 0, 4.0f);
206 tile8_source_canvas_.DrawGrid();
207 tile8_source_canvas_.DrawOverlay();
208 }
209 EndChild();
210
211 // The user selected a tile8
212 if (!tile8_source_canvas_.points().empty()) {
213 uint16_t x = tile8_source_canvas_.points().front().x / 16;
214 uint16_t y = tile8_source_canvas_.points().front().y / 16;
215
216 current_tile8_ = x + (y * 8);
218 current_gfx_individual_[current_tile8_].ApplyPaletteWithTransparent(
219 ow_main_pal_group[0], current_palette_));
222 }
223
224 if (BeginChild("Tile16 Editor Options",
225 ImVec2(GetContentRegionAvail().x, 0x50), true)) {
226 tile16_edit_canvas_.DrawBackground();
228 tile16_edit_canvas_.DrawBitmap(current_tile16_bmp_, 0, 0, 4.0f);
229 if (!tile8_source_canvas_.points().empty()) {
230 if (tile16_edit_canvas_.DrawTilePainter(
233 DrawToCurrentTile16(tile16_edit_canvas_.drawn_tile_position()));
235 }
236 }
237 tile16_edit_canvas_.DrawGrid();
238 tile16_edit_canvas_.DrawOverlay();
239 }
240 EndChild();
241 return absl::OkStatus();
242}
243
245 Separator();
246 Text("Tile16 ID: %d", current_tile16_);
247 Text("Tile8 ID: %d", current_tile8_);
248 Text("Options:");
249 gui::InputHexByte("Palette", &notify_palette.mutable_get());
250 notify_palette.apply_changes();
251 if (notify_palette.modified()) {
252 auto palette = palettesets_[current_palette_].main_;
253 auto value = notify_palette.get();
254 if (notify_palette.get() > 0x04 && notify_palette.get() < 0x06) {
255 palette = palettesets_[current_palette_].aux1;
256 value -= 0x04;
257 } else if (notify_palette.get() > 0x06) {
258 palette = palettesets_[current_palette_].aux2;
259 value -= 0x06;
260 }
261
262 if (value > 0x00) {
264 current_gfx_bmp_.ApplyPaletteWithTransparent(palette, value));
266
268 current_tile16_bmp_.ApplyPaletteWithTransparent(palette, value));
270 }
271 }
272
273 Checkbox("X Flip", &x_flip);
274 Checkbox("Y Flip", &y_flip);
275 Checkbox("Priority Tile", &priority_tile);
276
277 return absl::OkStatus();
278}
279
281 auto ow_main_pal_group = rom()->palette_group().overworld_main;
282 current_gfx_individual_.reserve(1024);
283
284 std::vector<std::future<std::array<uint8_t, 0x40>>> futures;
285
286 for (int index = 0; index < 1024; index++) {
287 auto task_function = [&]() {
288 std::array<uint8_t, 0x40> tile_data;
289 // Copy the pixel data for the current tile into the vector
290 for (int ty = 0; ty < 8; ty++) {
291 for (int tx = 0; tx < 8; tx++) {
292 // Current Gfx Data is 16 sheets of 8x8 tiles ordered 16 wide by 4
293 // tall
294
295 // Calculate the position in the tile data vector
296 int position = tx + (ty * 0x08);
297
298 // Calculate the position in the current gfx data
299 int num_columns = current_gfx_bmp_.width() / 8;
300 int x = (index % num_columns) * 8 + tx;
301 int y = (index / num_columns) * 8 + ty;
302 int gfx_position = x + (y * 0x100);
303
304 // Get the pixel value from the current gfx data
305 uint8_t value = current_gfx_bmp_.data()[gfx_position];
306
307 if (value & 0x80) {
308 value -= 0x88;
309 }
310
311 tile_data[position] = value;
312 }
313 }
314 return tile_data;
315 };
316 futures.emplace_back(std::async(std::launch::async, task_function));
317 }
318
319 for (auto &future : futures) {
320 future.wait();
321 auto tile_data = future.get();
322 current_gfx_individual_.emplace_back();
323 auto &tile_bitmap = current_gfx_individual_.back();
324 tile_bitmap.Create(0x08, 0x08, 0x08, tile_data);
325 RETURN_IF_ERROR(tile_bitmap.ApplyPaletteWithTransparent(
326 ow_main_pal_group[0], current_palette_));
327 Renderer::GetInstance().RenderBitmap(&tile_bitmap);
328 }
329
331
332 return absl::OkStatus();
333}
334
335absl::Status Tile16Editor::SetCurrentTile(int id) {
336 current_tile16_ = id;
338 auto ow_main_pal_group = rom()->palette_group().overworld_main;
340 current_tile16_bmp_.ApplyPalette(ow_main_pal_group[current_palette_]));
342 return absl::OkStatus();
343}
344
345#pragma mark - Tile16Transfer
346
348 if (BeginTabItem("Tile16 Transfer")) {
349 if (BeginTable("#Tile16TransferTable", 2, TABLE_BORDERS_RESIZABLE,
350 ImVec2(0, 0))) {
351 TableSetupColumn("Current ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
352 GetContentRegionAvail().x / 2);
353 TableSetupColumn("Transfer ROM Tiles", ImGuiTableColumnFlags_WidthFixed,
354 GetContentRegionAvail().x / 2);
355 TableHeadersRow();
356 TableNextRow();
357
358 TableNextColumn();
360
361 TableNextColumn();
363
364 EndTable();
365 }
366
367 EndTabItem();
368 }
369 return absl::OkStatus();
370}
371
373 // Create a button for loading another ROM
374 if (Button("Load ROM")) {
376 transfer_status_ = transfer_rom_.LoadFromFile(file_name);
377 transfer_started_ = true;
378 }
379
380 // TODO: Implement tile16 transfer
383
384 // Load the Link to the Past overworld.
386 transfer_overworld_.set_current_map(0);
387 palette_ = transfer_overworld_.current_area_palette();
388
389 // Create the tile16 blockset image
390 RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
391 0x80, 0x2000, 0x80, transfer_overworld_.tile16_blockset_data(),
394 }
395
396 // Create a canvas for holding the tiles which will be exported
398 (8192 * 2), 0x20, transfer_blockset_loaded_, true,
399 3);
400
401 return absl::OkStatus();
402}
403
404} // namespace editor
405} // namespace yaze
auto rom()
Definition rom.h:383
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath.
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 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_
absl::Status DrawTileEditControls()
std::array< gfx::Bitmap, zelda3::kNumTile16Individual > & tile16_individual_
absl::Status InitBlockset(const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap &current_gfx_bmp, std::array< uint8_t, 0x200 > &all_tiles_types)
util::NotifyValue< uint8_t > notify_palette
Represents a bitmap image.
Definition bitmap.h:66
auto vector() const
Definition bitmap.h:166
int height() const
Definition bitmap.h:159
int width() const
Definition bitmap.h:158
auto palette() const
Definition bitmap.h:155
auto depth() const
Definition bitmap.h:160
static std::unordered_map< uint8_t, gfx::Paletteset > palettesets_
#define TABLE_BORDERS_RESIZABLE
Definition macro.h:102
#define PRINT_IF_ERROR(expression)
Definition macro.h:36
#define RETURN_IF_ERROR(expression)
Definition macro.h:62
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:70
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:358
void EndPadding()
Definition style.cc:362
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:370
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:78