5#include "absl/strings/str_format.h"
13 : rom_(rom), room_gfx_buffer_(room_gfx_buffer) {
21 LOG_DEBUG(
"ObjectDrawer",
"Drawing object 0x%02X at (%d,%d) size=%d tiles=%zu",
22 object.id_,
object.x_,
object.y_,
object.size_,
object.tiles().size());
25 return absl::FailedPreconditionError(
"ROM not loaded");
29 return absl::FailedPreconditionError(
"Draw routines not initialized");
33 auto mutable_obj =
const_cast<RoomObject&
>(object);
35 mutable_obj.EnsureTilesLoaded();
41 if (mutable_obj.tiles().empty()) {
42 return absl::OkStatus();
48 LOG_DEBUG(
"ObjectDrawer",
"Object %04X -> routine_id=%d",
object.id_, routine_id);
50 if (routine_id < 0 || routine_id >=
static_cast<int>(
draw_routines_.size())) {
51 LOG_DEBUG(
"ObjectDrawer",
"Using fallback 1x1 drawing for object %04X",
object.id_);
53 if (!mutable_obj.tiles().empty()) {
54 const auto& tile_info = mutable_obj.tiles()[0];
55 WriteTile8(target_bg,
object.x_,
object.y_, tile_info);
57 return absl::OkStatus();
60 LOG_DEBUG(
"ObjectDrawer",
"Executing draw routine %d for object %04X", routine_id,
object.id_);
64 return absl::OkStatus();
68 const std::vector<RoomObject>& objects,
73 for (
const auto&
object : objects) {
79 auto& bg1_bmp = bg1.
bitmap();
80 auto& bg2_bmp = bg2.
bitmap();
82 if (bg1_bmp.modified() && bg1_bmp.surface() && bg1_bmp.mutable_data().size() > 0) {
83 SDL_LockSurface(bg1_bmp.surface());
84 memcpy(bg1_bmp.surface()->pixels, bg1_bmp.mutable_data().data(), bg1_bmp.mutable_data().size());
85 SDL_UnlockSurface(bg1_bmp.surface());
86 printf(
"[ObjectDrawer] Synced BG1 bitmap data to SDL surface (%zu bytes)\n", bg1_bmp.mutable_data().size());
89 if (bg2_bmp.modified() && bg2_bmp.surface() && bg2_bmp.mutable_data().size() > 0) {
90 SDL_LockSurface(bg2_bmp.surface());
91 memcpy(bg2_bmp.surface()->pixels, bg2_bmp.mutable_data().data(), bg2_bmp.mutable_data().size());
92 SDL_UnlockSurface(bg2_bmp.surface());
93 printf(
"[ObjectDrawer] Synced BG2 bitmap data to SDL surface (%zu bytes)\n", bg2_bmp.mutable_data().size());
96 return absl::OkStatus();
228 std::span<const gfx::TileInfo> tiles) {
231 int size = obj.
size_;
232 if (size == 0) size = 32;
234 for (
int s = 0; s < size; s++) {
235 if (tiles.size() >= 4) {
246 std::span<const gfx::TileInfo> tiles) {
248 int size = obj.
size_;
249 if (size == 0) size = 26;
251 for (
int s = 0; s < size; s++) {
252 if (tiles.size() >= 4) {
267 std::span<const gfx::TileInfo> tiles) {
269 int size = obj.
size_ & 0x0F;
271 for (
int s = 0; s < size; s++) {
272 if (tiles.size() >= 4) {
287 std::span<const gfx::TileInfo> tiles) {
294 std::span<const gfx::TileInfo> tiles) {
296 int size = obj.
size_ & 0x0F;
298 for (
int s = 0; s < size; s++) {
299 if (tiles.size() >= 4) {
310 std::span<const gfx::TileInfo> tiles) {
312 int size = obj.
size_ & 0x0F;
314 for (
int s = 0; s < size + 6; s++) {
315 if (tiles.size() >= 4) {
317 for (
int i = 0; i < 5; i++) {
327 std::span<const gfx::TileInfo> tiles) {
329 int size = obj.
size_ & 0x0F;
331 for (
int s = 0; s < size + 6; s++) {
332 if (tiles.size() >= 4) {
334 for (
int i = 0; i < 5; i++) {
344 std::span<const gfx::TileInfo> tiles) {
350 std::span<const gfx::TileInfo> tiles) {
356 std::span<const gfx::TileInfo> tiles) {
358 int size = obj.
size_ & 0x0F;
360 for (
int s = 0; s < size; s++) {
361 if (tiles.size() >= 2) {
370 std::span<const gfx::TileInfo> tiles) {
372 int size = obj.
size_ & 0x0F;
374 for (
int s = 0; s < size; s++) {
375 if (tiles.size() >= 1) {
383 std::span<const gfx::TileInfo> tiles) {
385 int size = obj.
size_ & 0x0F;
387 for (
int s = 0; s < size; s++) {
388 if (tiles.size() >= 1) {
396 std::span<const gfx::TileInfo> tiles) {
398 int size = obj.
size_ & 0x0F;
400 for (
int s = 0; s < size; s++) {
401 if (tiles.size() >= 2) {
410 const std::span<const gfx::TileInfo> tiles) {
412 int size = obj.
size_ & 0x0F;
414 for (
int s = 0; s < size; s++) {
415 if (tiles.size() >= 2) {
424 std::span<const gfx::TileInfo> tiles) {
427 if (tiles.size() >= 1) {
434 std::span<const gfx::TileInfo> tiles) {
436 int size = obj.
size_ & 0x0F;
438 for (
int s = 0; s < size; s++) {
439 if (tiles.size() >= 16) {
441 for (
int y = 0; y < 4; ++y) {
442 for (
int x = 0; x < 4; ++x) {
443 WriteTile8(bg, obj.
x_ + (s * 4) + x, obj.
y_ + y, tiles[y * 4 + x]);
451 std::span<const gfx::TileInfo> tiles) {
453 int size = obj.
size_ & 0x0F;
455 for (
int s = 0; s < size; s++) {
456 if (tiles.size() >= 1) {
464 std::span<const gfx::TileInfo> tiles) {
467 if (tiles.size() >= 1) {
474 std::span<const gfx::TileInfo> tiles) {
476 int size = obj.
size_ & 0x0F;
478 for (
int s = 0; s < size; s++) {
479 if (tiles.size() >= 16) {
481 for (
int y = 0; y < 4; ++y) {
482 for (
int x = 0; x < 4; ++x) {
483 WriteTile8(bg, obj.
x_ + (s * 6) + x, obj.
y_ + y, tiles[y * 4 + x]);
491 std::span<const gfx::TileInfo> tiles) {
493 int size = obj.
size_ & 0x0F;
495 for (
int s = 0; s < size; s++) {
496 if (tiles.size() >= 6) {
498 for (
int y = 0; y < 3; ++y) {
499 for (
int x = 0; x < 2; ++x) {
500 WriteTile8(bg, obj.
x_ + (s * 4) + x, obj.
y_ + y, tiles[y * 2 + x]);
508 std::span<const gfx::TileInfo> tiles) {
510 int size = obj.
size_ & 0x0F;
512 for (
int s = 0; s < size; s++) {
513 if (tiles.size() >= 8) {
515 for (
int y = 0; y < 4; ++y) {
516 for (
int x = 0; x < 2; ++x) {
517 WriteTile8(bg, obj.
x_ + (s * 6) + x, obj.
y_ + y, tiles[y * 2 + x]);
525 std::span<const gfx::TileInfo> tiles) {
527 int size = obj.
size_ & 0x0F;
529 for (
int s = 0; s < size; s++) {
530 if (tiles.size() >= 12) {
532 for (
int y = 0; y < 3; ++y) {
533 for (
int x = 0; x < 4; ++x) {
534 WriteTile8(bg, obj.
x_ + (s * 6) + x, obj.
y_ + y, tiles[y * 4 + x]);
542 std::span<const gfx::TileInfo> tiles) {
544 int size = obj.
size_ & 0x0F;
546 for (
int s = 0; s < size; s++) {
547 if (tiles.size() >= 8) {
549 for (
int y = 0; y < 2; ++y) {
550 for (
int x = 0; x < 4; ++x) {
551 WriteTile8(bg, obj.
x_ + (s * 6) + x, obj.
y_ + y, tiles[y * 4 + x]);
559 std::span<const gfx::TileInfo> tiles) {
561 int size = obj.
size_ & 0x0F;
563 for (
int s = 0; s < size; s++) {
564 if (tiles.size() >= 4) {
579 std::span<const gfx::TileInfo> tiles) {
582 int size = obj.
size_;
583 if (size == 0) size = 32;
585 for (
int s = 0; s < size; s++) {
586 if (tiles.size() >= 4) {
597 std::span<const gfx::TileInfo> tiles) {
599 int size = obj.
size_;
600 if (size == 0) size = 26;
602 LOG_DEBUG(
"ObjectDrawer",
"DrawDownwards4x2_1to15or26: obj=%04X tiles=%zu size=%d",
603 obj.
id_, tiles.size(), size);
605 for (
int s = 0; s < size; s++) {
606 if (tiles.size() >= 8) {
619 }
else if (tiles.size() >= 4) {
634 std::span<const gfx::TileInfo> tiles) {
641 std::span<const gfx::TileInfo> tiles) {
643 int size = obj.
size_ & 0x0F;
645 for (
int s = 0; s < size; s++) {
646 if (tiles.size() >= 8) {
661 std::span<const gfx::TileInfo> tiles) {
663 int size = obj.
size_ & 0x0F;
665 for (
int s = 0; s < size; s++) {
666 if (tiles.size() >= 4) {
677 std::span<const gfx::TileInfo> tiles) {
679 int size = obj.
size_ & 0x0F;
681 for (
int s = 0; s < size; s++) {
682 if (tiles.size() >= 1) {
690 std::span<const gfx::TileInfo> tiles) {
692 int size = obj.
size_ & 0x0F;
694 for (
int s = 0; s < size; s++) {
695 if (tiles.size() >= 1) {
703 std::span<const gfx::TileInfo> tiles) {
705 int size = obj.
size_ & 0x0F;
707 for (
int s = 0; s < size; s++) {
708 if (tiles.size() >= 2) {
717 std::span<const gfx::TileInfo> tiles) {
719 int size = obj.
size_ & 0x0F;
721 for (
int s = 0; s < size; s++) {
722 if (tiles.size() >= 2) {
737 auto& bitmap = bg.
bitmap();
738 if (!bitmap.is_active() || bitmap.width() == 0) {
747 LOG_DEBUG(
"ObjectDrawer",
"ERROR: No graphics data available");
761 int pixel_x,
int pixel_y,
const uint8_t* tiledata) {
763 if (!tiledata)
return;
767 LOG_DEBUG(
"ObjectDrawer",
"ERROR: Invalid bitmap - active=%d, size=%dx%d",
773 int tile_sheet_x = (tile_info.
id_ % 16) * 8;
774 int tile_sheet_y = (tile_info.
id_ / 16) * 8;
777 uint8_t palette_offset = (tile_info.
palette_ & 0x0F) * 8;
780 static int debug_tile_count = 0;
781 if (debug_tile_count < 5) {
782 printf(
"[ObjectDrawer] DrawTile: id=0x%03X pos=(%d,%d) sheet=(%d,%d) pal=%d mirror=(h:%d,v:%d)\n",
783 tile_info.
id_, pixel_x, pixel_y, tile_sheet_x, tile_sheet_y,
789 int pixels_written = 0;
790 int pixels_transparent = 0;
791 for (
int py = 0; py < 8; py++) {
792 for (
int px = 0; px < 8; px++) {
798 int src_index = (tile_sheet_y + src_y) * 128 + (tile_sheet_x + src_x);
799 uint8_t pixel_index = tiledata[src_index];
800 if (pixel_index == 0) {
801 pixels_transparent++;
804 uint8_t final_color = pixel_index + palette_offset;
805 int dest_x = pixel_x + px;
806 int dest_y = pixel_y + py;
808 if (dest_x >= 0 && dest_x < bitmap.
width() && dest_y >= 0 && dest_y < bitmap.
height()) {
809 int dest_index = dest_y * bitmap.
width() + dest_x;
810 if (dest_index >= 0 && dest_index <
static_cast<int>(bitmap.
mutable_data().size())) {
819 if (pixels_written > 0) {
824 if (debug_tile_count < 5) {
825 printf(
"[ObjectDrawer] Tile 0x%03X: wrote %d pixels, %d transparent, src_index_range=[%d,%d]\n",
826 tile_info.
id_, pixels_written, pixels_transparent,
827 (tile_sheet_y * 128 + tile_sheet_x),
828 (tile_sheet_y + 7) * 128 + (tile_sheet_x + 7));
The Rom class is used to load, save, and modify Rom data.
Represents a bitmap image optimized for SNES ROM hacking.
void set_modified(bool modified)
std::vector< uint8_t > & mutable_data()
SNES 16-bit tile metadata container.
Draws dungeon objects to background buffers using game patterns.
int GetDrawRoutineId(int16_t object_id) const
Get draw routine ID for an object.
void WriteTile8(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info)
void DrawRightwardsPillar2x4spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawTileToBitmap(gfx::Bitmap &bitmap, const gfx::TileInfo &tile_info, int pixel_x, int pixel_y, const uint8_t *tiledata)
Draw a single tile directly to bitmap.
void InitializeDrawRoutines()
Initialize draw routine registry Must be called before drawing objects.
void DrawDiagonalAcute_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwards2x4spaced4_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
std::vector< DrawRoutine > draw_routines_
void DrawDownwardsRightCorners2x1_1to16_plus12(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwardsLeftCorners2x1_1to16_plus12(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwards2x4_1to15or26(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwards4x4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDiagonalGrave_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsHasEdge1x1_1to16_plus2(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsHasEdge1x1_1to16_plus3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
absl::Status DrawObjectList(const std::vector< RoomObject > &objects, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group)
Draw all objects in a room.
const uint8_t * room_gfx_buffer_
void DrawRightwards1x2_1to16_plus2(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwardsDecor4x2spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwardsEdge1x1_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
absl::Status DrawObject(const RoomObject &object, gfx::BackgroundBuffer &bg1, gfx::BackgroundBuffer &bg2, const gfx::PaletteGroup &palette_group)
Draw a room object to background buffers.
void DrawRightwards2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
ObjectDrawer(Rom *rom, const uint8_t *room_gfx_buffer=nullptr)
void DrawDiagonalAcute_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwards1x1Solid_1to16_plus3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwards2x2_1to15or32(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwardsHasEdge1x1_1to16_plus3(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
std::unordered_map< int16_t, int > object_to_routine_map_
void DrawDoorSwitcherer(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
static constexpr int kMaxTilesX
void DrawRightwardsStatue2x3spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwards4x2_1to16_BothBG(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsBottomCorners1x2_1to16_plus13(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDiagonalGrave_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
bool routines_initialized_
void DrawRightwards2x4spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsDecor4x4spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsDecor2x2spaced12_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawDownwards2x2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
static constexpr int kMaxTilesY
void DrawDownwards2x2_1to15or32(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsDecor4x3spaced4_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void CustomDraw(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
bool IsValidTilePosition(int tile_x, int tile_y) const
void DrawDownwards4x2_1to15or26(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsTopCorners1x2_1to16_plus13(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
void DrawRightwardsDoubled2x2spaced2_1to16(const RoomObject &obj, gfx::BackgroundBuffer &bg, std::span< const gfx::TileInfo > tiles)
const std::vector< gfx::TileInfo > & tiles() const
#define LOG_DEBUG(category, format,...)
Main namespace for the application.
Represents a group of palettes.