#pragma once #include "coordinates.hpp" #include "gen/maps.hpp" #include "map_objects.hpp" #include "vdp2.h" constexpr inline uint8_t get_block(const map_t& map, block_t block) { const uint8_t border_block = map_objects[map.id].border_block; const bool x_lt = block.x < static_cast(map.width); const bool y_lt = block.y < static_cast(map.height); const bool x_gt = block.x >= 0; const bool y_gt = block.y >= 0; const bool inside_map = x_lt && y_lt && x_gt && y_gt; const bool north = x_lt && x_gt && !y_gt; const bool south = x_lt && x_gt && !y_lt; const bool west = y_lt && y_gt && !x_gt; const bool east = y_lt && y_gt && !x_lt; #define _has(_dir_) (map.connections[map_t::connection_t::_dir_].map != map_t::unconnected) #define _get(_dir_) (maps[map.connections[map_t::connection_t::_dir_].map]) #define _offset(_dir_) (map.connections[map_t::connection_t::_dir_].offset) if (inside_map) { return map.blocks.start[map.width * block.y + block.x]; } else if (north && _has(north)) { const map_t& north_map = _get(north); return get_block(north_map, { .x = block.x - _offset(north), .y = static_cast(north_map.height + block.y), }); } else if (south && _has(south)) { const map_t& south_map = _get(south); return get_block(south_map, { .x = block.x - _offset(south), .y = static_cast(block.y - map.height), }); } else if (west && _has(west)) { const map_t& west_map = _get(west); return get_block(west_map, { .x = static_cast(west_map.width + block.x), .y = block.y - _offset(west), }); } else if (east && _has(east)) { const map_t& east_map = _get(east); return get_block(east_map, { .x = static_cast(block.x - map.width), .y = block.y - _offset(east), }); } else { return border_block; } #undef _offset #undef _get #undef _has } namespace cell_offset { int32_t x = (320 - 160) / (2 * 8); int32_t y = (240 - 144) / (2 * 8); } static inline void render_screen(const uint32_t base_pattern, const map_t& map, const world_t& origin, const screen_t& screen) { const world_t world = screen.to_world(origin); // keep this synchronized with collision() const uint8_t block_ix = get_block(map, world.to_block()); const tileset_t& tileset = tilesets[map.tileset]; const uint8_t * block_start = &(tileset.blockset.start)[block_ix * 4 * 4]; const int32_t quadrant_x = 2 * (world.x & 1); const int32_t quadrant_y = 2 * (world.y & 1); for (int32_t tile_y = quadrant_y; tile_y < quadrant_y + 2; tile_y++) { const int32_t block_row = 4 * tile_y; for (int32_t tile_x = quadrant_x; tile_x < quadrant_x + 2; tile_x++) { const uint8_t tile_ix = block_start[block_row + tile_x]; const uint32_t cell_y = cell_offset::y + screen.y * 2 + tile_y - quadrant_y; const uint32_t cell_x = cell_offset::x + screen.x * 2 + tile_x - quadrant_x; vdp2.vram.u16[64 * (cell_y % 64) + (cell_x % 64)] = (base_pattern & 0xfff) + tile_ix; } } }