123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- /*
- * maps.c
- * Duality
- *
- * Copyright (C) 2025 Thomas Buck <thomas@xythobuz.de>
- *
- * Based on examples from gbdk-2020:
- * https://github.com/gbdk-2020/gbdk-2020/blob/develop/gbdk-lib/examples/cross-platform/large_map
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * See <http://www.gnu.org/licenses/>.
- */
-
- #include <assert.h>
-
- #include "banks.h"
- #include "title_map.h"
- #include "bg_map.h"
- #include "util.h"
- #include "maps.h"
-
- // currently this assumption is hard-coded
- static_assert(bg_map_WIDTH == 256, "bg_map needs to be 256x256");
- static_assert(bg_map_HEIGHT == 256, "bg_map needs to be 256x256");
-
- #define POS_SCALE_BG 6
-
- // define this to disable mirrored map scaling support
- #define WRAP_BG // TODO
-
- #define bg_map_mapWidth (bg_map_WIDTH / bg_map_TILE_W)
- #define bg_map_mapHeight (bg_map_HEIGHT / bg_map_TILE_H)
-
- #define camera_max_x ((bg_map_mapWidth - DEVICE_SCREEN_WIDTH) * 8)
- #define camera_max_y ((bg_map_mapHeight - DEVICE_SCREEN_HEIGHT) * 8)
-
- #define MAP_FLIP_NONE 0x00
- #define MAP_FLIP_X (0x20 | 0x01)
- #define MAP_FLIP_Y (0x40 | 0x02)
- #define MAP_FLIP_XY (MAP_FLIP_X | MAP_FLIP_Y)
-
- // current unscaled ship position
- static uint16_t abs_x, abs_y;
-
- // current and old positions of the camera in pixels
- static uint16_t old_camera_x, old_camera_y;
-
- // current and old position of the map in tiles
- static uint8_t old_map_pos_x, old_map_pos_y;
-
- void map_title(void) NONBANKED {
- START_ROM_BANK(BANK(title_map)) {
- set_bkg_palette(OAMF_CGB_PAL0, title_map_PALETTE_COUNT, title_map_palettes);
- set_bkg_data(0, title_map_TILE_COUNT, title_map_tiles);
-
- if (title_map_MAP_ATTRIBUTES != NULL) {
- set_bkg_attributes(0, 0,
- title_map_WIDTH / title_map_TILE_W,
- title_map_HEIGHT / title_map_TILE_H,
- title_map_MAP_ATTRIBUTES);
- } else {
- VBK_REG = VBK_ATTRIBUTES;
- fill_bkg_rect(0, 0,
- title_map_WIDTH / title_map_TILE_W,
- title_map_HEIGHT / title_map_TILE_H,
- 0x00);
- VBK_REG = VBK_TILES;
- }
-
- set_bkg_tiles(0, 0,
- title_map_WIDTH / title_map_TILE_W,
- title_map_HEIGHT / title_map_TILE_H,
- title_map_map);
- } END_ROM_BANK
-
- move_bkg(0, 0);
- }
-
- static inline void set_bkg_sub_attr(uint8_t x, uint8_t y,
- uint8_t w, uint8_t h,
- const uint8_t *attr,
- uint8_t attr_val,
- uint8_t map_w) {
- if (attr) {
- set_bkg_submap_attributes(x, y, w, h, attr, map_w);
- } else {
- VBK_REG = VBK_ATTRIBUTES;
- fill_bkg_rect(x, y, w, h, attr_val);
- VBK_REG = VBK_TILES;
- }
- }
-
- static inline void set_bkg_sub(uint8_t x, uint8_t y,
- uint8_t w, uint8_t h,
- const uint8_t *map, const uint8_t *attr,
- uint8_t attr_val,
- uint8_t map_w) {
- START_ROM_BANK(BANK(bg_map)) {
- set_bkg_submap(x, y, w, h, map, map_w);
- set_bkg_sub_attr(x, y, w, h, attr, attr_val, map_w);
- } END_ROM_BANK
- }
-
- void map_game(void) NONBANKED {
- START_ROM_BANK(BANK(bg_map)) {
- set_bkg_palette(OAMF_CGB_PAL0, bg_map_PALETTE_COUNT, bg_map_palettes);
- set_bkg_data(0, bg_map_TILE_COUNT, bg_map_tiles);
- } END_ROM_BANK
-
- #ifdef WRAP_BG
-
- if (bg_map_MAP_ATTRIBUTES != NULL) {
- set_bkg_attributes(0, 0,
- bg_map_WIDTH / bg_map_TILE_W, bg_map_HEIGHT / bg_map_TILE_H,
- bg_map_MAP_ATTRIBUTES);
- } else {
- VBK_REG = VBK_ATTRIBUTES;
- fill_bkg_rect(0, 0,
- bg_map_WIDTH / bg_map_TILE_W, bg_map_HEIGHT / bg_map_TILE_H,
- 0x00);
- VBK_REG = VBK_TILES;
- }
- set_bkg_tiles(0, 0, bg_map_WIDTH / bg_map_TILE_W, bg_map_HEIGHT / bg_map_TILE_H, bg_map_map);
-
- #else // WRAP_BG
-
- abs_x = 0;
- abs_y = 0;
- old_camera_x = 0;
- old_camera_y = 0;
- old_map_pos_x = 0;
- old_map_pos_y = 0;
-
- move_bkg(0, 0);
-
- // Draw the initial map view for the whole screen
- set_bkg_sub(0, 0,
- MIN(DEVICE_SCREEN_WIDTH + 1u, bg_map_mapWidth),
- MIN(DEVICE_SCREEN_HEIGHT + 1u, bg_map_mapHeight),
- bg_map_map, bg_map_MAP_ATTRIBUTES, MAP_FLIP_NONE, bg_map_mapWidth);
-
- #endif // WRAP_BG
- }
-
- static inline void set(uint8_t dst_x, uint8_t dst_y,
- uint8_t src_x, uint8_t src_y,
- uint8_t attr) {
- START_ROM_BANK(BANK(bg_map)) {
- set_bkg_tile_xy(dst_x, dst_y, bg_map_map[src_x + (src_y * (bg_map_WIDTH / bg_map_TILE_W))]);
- set_bkg_attribute_xy(dst_x, dst_y, attr);
- } END_ROM_BANK
- }
-
- void map_dbg_reset(void) NONBANKED {
- #ifndef WRAP_BG
- uint16_t camera_x = abs_x >> POS_SCALE_BG;
- uint16_t camera_y = abs_y >> POS_SCALE_BG;
- uint8_t map_pos_x = camera_x >> 3;
- uint8_t map_pos_y = camera_y >> 3;
- for (uint8_t x = 0; x < DEVICE_SCREEN_WIDTH; x++) {
- for (uint8_t y = 0; y < DEVICE_SCREEN_HEIGHT; y++) {
- uint8_t is_flipped_x = ((camera_x >> 3) + x) & 0x10;
- uint8_t is_flipped_y = ((camera_y >> 3) + y) & 0x10;
- uint8_t attr = is_flipped_y ? (is_flipped_x ? MAP_FLIP_XY : MAP_FLIP_Y)
- : (is_flipped_x ? MAP_FLIP_X : MAP_FLIP_NONE);
- set(x, y,
- is_flipped_x ? bg_map_mapWidth - map_pos_x : map_pos_x,
- is_flipped_y ? bg_map_mapHeight - map_pos_y : map_pos_y,
- attr);
- }
- }
- #endif // ! WRAP_BG
- }
-
- void map_move(int16_t delta_x, int16_t delta_y) NONBANKED {
- abs_x += delta_x;
- abs_y += delta_y;
-
- uint16_t camera_x = abs_x >> POS_SCALE_BG;
- uint16_t camera_y = abs_y >> POS_SCALE_BG;
-
- move_bkg(camera_x, camera_y);
-
- #ifndef WRAP_BG
-
- uint8_t map_pos_x = camera_x >> 3;
- uint8_t map_pos_y = camera_y >> 3;
-
- uint8_t is_flipped_x_left = (camera_x >> 3) & 0x10;
- uint8_t is_flipped_x_right = ((camera_x >> 3) + DEVICE_SCREEN_WIDTH) & 0x10;
- uint8_t is_flipped_y_top = (camera_y >> 3) & 0x10;
- uint8_t is_flipped_y_bottom = ((camera_y >> 3) + DEVICE_SCREEN_HEIGHT) & 0x10;
-
- if (map_pos_x != old_map_pos_x) {
- old_map_pos_x = map_pos_x;
-
- if (camera_x < old_camera_x) {
- // moving left
- set_bkg_sub(map_pos_x, map_pos_y,
- 1, MIN(DEVICE_SCREEN_HEIGHT + 1, bg_map_mapHeight - map_pos_y),
- bg_map_map, bg_map_MAP_ATTRIBUTES, MAP_FLIP_X, bg_map_mapWidth);
- } else if ((bg_map_mapWidth - DEVICE_SCREEN_WIDTH) > map_pos_x) {
- // moving right
- /*
- set_bkg_sub(map_pos_x + DEVICE_SCREEN_WIDTH, map_pos_y,
- 1, MIN(DEVICE_SCREEN_HEIGHT + 1, bg_map_mapHeight - map_pos_y),
- bg_map_map, bg_map_MAP_ATTRIBUTES, MAP_FLIP_NONE, bg_map_mapWidth);
- */
- for (uint8_t i = 0; i < DEVICE_SCREEN_HEIGHT; i++) {
- uint8_t is_flipped_y = (map_pos_y + i) & 0x04;
- uint8_t attr = is_flipped_y ? (is_flipped_x_right ? MAP_FLIP_XY : MAP_FLIP_Y)
- : (is_flipped_x_right ? MAP_FLIP_X : MAP_FLIP_NONE);
- set(map_pos_x + DEVICE_SCREEN_WIDTH, map_pos_y + i,
- is_flipped_x_right ? bg_map_mapWidth - map_pos_x : map_pos_x,
- is_flipped_y ? bg_map_mapHeight - map_pos_y : map_pos_y,
- attr);
- }
- }
- }
-
- if (map_pos_y != old_map_pos_y) {
- old_map_pos_y = map_pos_y;
-
- if (camera_y < old_camera_y) {
- // moving up
- set_bkg_sub(map_pos_x, map_pos_y,
- MIN(DEVICE_SCREEN_WIDTH + 1, bg_map_mapWidth - map_pos_x), 1,
- bg_map_map, bg_map_MAP_ATTRIBUTES, MAP_FLIP_Y, bg_map_mapWidth);
- } else if ((bg_map_mapHeight - DEVICE_SCREEN_HEIGHT) > map_pos_y) {
- // moving down
- set_bkg_sub(map_pos_x, map_pos_y + DEVICE_SCREEN_HEIGHT,
- MIN(DEVICE_SCREEN_WIDTH + 1, bg_map_mapWidth - map_pos_x), 1,
- bg_map_map, bg_map_MAP_ATTRIBUTES, MAP_FLIP_NONE, bg_map_mapWidth);
- }
- }
-
- // set old camera position to current camera position
- old_camera_x = camera_x;
- old_camera_y = camera_y;
-
- #endif // ! WRAP_BG
- }
|