coordinates: rework map rendering
This also adds interactive player movement. I am much more satisfied with the coordinate space math in this commit compared to the previous commit.
This commit is contained in:
parent
9645b4b414
commit
e6cae1c242
4
Makefile
4
Makefile
@ -1,6 +1,6 @@
|
|||||||
CFLAGS = -Isaturn
|
CFLAGS = -Isaturn
|
||||||
|
|
||||||
OPT ?= -Og
|
OPT ?= -O3
|
||||||
LIB = ./saturn
|
LIB = ./saturn
|
||||||
|
|
||||||
GEN_PYTHON_SOURCE = $(wildcard tools/source/*.py) $(wildcard tools/generate/*.py)
|
GEN_PYTHON_SOURCE = $(wildcard tools/source/*.py) $(wildcard tools/generate/*.py)
|
||||||
@ -84,7 +84,7 @@ res/%.bst: pokered/%.bst
|
|||||||
|
|
||||||
%.o: | $(GFX_TILESETS)
|
%.o: | $(GFX_TILESETS)
|
||||||
|
|
||||||
main.elf: $(OBJ)
|
main.elf: $(OBJ) $(LIBGCC)
|
||||||
|
|
||||||
clean: clean-sh
|
clean: clean-sh
|
||||||
clean-sh:
|
clean-sh:
|
||||||
|
66
actor.hpp
Normal file
66
actor.hpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "coordinates.hpp"
|
||||||
|
|
||||||
|
struct actor_t
|
||||||
|
{
|
||||||
|
enum direction {
|
||||||
|
up,
|
||||||
|
down,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
};
|
||||||
|
|
||||||
|
world_t world;
|
||||||
|
enum direction facing;
|
||||||
|
bool moving;
|
||||||
|
uint8_t frame;
|
||||||
|
|
||||||
|
constexpr inline offset_t offset()
|
||||||
|
{
|
||||||
|
switch (facing) {
|
||||||
|
case left:
|
||||||
|
return {-frame, 0};
|
||||||
|
case right:
|
||||||
|
return {frame, 0};
|
||||||
|
case up:
|
||||||
|
return {0, -frame};
|
||||||
|
case down:
|
||||||
|
return {0, frame};
|
||||||
|
default:
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// call tick() before move()
|
||||||
|
constexpr inline void tick()
|
||||||
|
{
|
||||||
|
if (!moving) return;
|
||||||
|
|
||||||
|
if (++frame == 16) {
|
||||||
|
moving = false;
|
||||||
|
frame = 0;
|
||||||
|
switch (facing) {
|
||||||
|
case left: world.x--; break;
|
||||||
|
case right: world.x++; break;
|
||||||
|
case up: world.y--; break;
|
||||||
|
case down: world.y++; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline void move(enum direction dir)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
m 1 . 2 . 3 . 4 .
|
||||||
|
| - | - | - | - |
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (moving) return;
|
||||||
|
|
||||||
|
frame = 0;
|
||||||
|
facing = dir;
|
||||||
|
moving = true;
|
||||||
|
}
|
||||||
|
};
|
67
coordinates.hpp
Normal file
67
coordinates.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace screen_offset
|
||||||
|
{
|
||||||
|
// the origin is at this offset in screen space
|
||||||
|
constexpr int32_t x = 4;
|
||||||
|
constexpr int32_t y = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct offset_t { // in pixels
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct block_t {
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct world_t;
|
||||||
|
|
||||||
|
struct screen_t {
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
|
||||||
|
constexpr inline world_t to_world(const world_t& origin) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct world_t {
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
|
||||||
|
constexpr inline screen_t to_screen(const world_t& origin) const;
|
||||||
|
constexpr inline block_t to_block() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// screen_t
|
||||||
|
|
||||||
|
constexpr inline world_t screen_t::to_world(const world_t& origin) const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
(origin.x - screen_offset::x) + x,
|
||||||
|
(origin.y - screen_offset::y) + y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// world_t
|
||||||
|
|
||||||
|
constexpr inline screen_t world_t::to_screen(const world_t& origin) const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
-origin.x + screen_offset::x + x,
|
||||||
|
-origin.y + screen_offset::y + y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline block_t world_t::to_block() const
|
||||||
|
{
|
||||||
|
// division function must round towards negative infinity
|
||||||
|
// right shift provides that property
|
||||||
|
return {
|
||||||
|
x >> 1,
|
||||||
|
y >> 1,
|
||||||
|
};
|
||||||
|
}
|
10
input.hpp
10
input.hpp
@ -29,8 +29,8 @@ void digital_callback(uint8_t fsm_state, uint8_t data);
|
|||||||
|
|
||||||
extern input_t input;
|
extern input_t input;
|
||||||
|
|
||||||
constexpr int input_arr = 10;
|
constexpr int input_arr = 1;
|
||||||
constexpr int input_das = 20;
|
constexpr int input_das = 1;
|
||||||
constexpr int input_debounce = 2;
|
constexpr int input_debounce = 2;
|
||||||
|
|
||||||
static constexpr inline int32_t
|
static constexpr inline int32_t
|
||||||
@ -52,6 +52,8 @@ input_flopped(count_flop_t& button)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct event {
|
struct event {
|
||||||
static inline bool cursor_left() { return input_flopped(input.a) == 1; }
|
static inline bool cursor_left() { return input_flopped(input.left ) >= 1; }
|
||||||
static inline bool cursor_right() { return input_flopped(input.b) == 1; }
|
static inline bool cursor_right() { return input_flopped(input.right) >= 1; }
|
||||||
|
static inline bool cursor_up() { return input_flopped(input.up ) >= 1; }
|
||||||
|
static inline bool cursor_down() { return input_flopped(input.down ) >= 1; }
|
||||||
};
|
};
|
||||||
|
197
main.cpp
197
main.cpp
@ -16,6 +16,10 @@
|
|||||||
#include "gen/sprites.hpp"
|
#include "gen/sprites.hpp"
|
||||||
#include "map_objects.hpp"
|
#include "map_objects.hpp"
|
||||||
|
|
||||||
|
#include "coordinates.hpp"
|
||||||
|
#include "render_map.hpp"
|
||||||
|
#include "actor.hpp"
|
||||||
|
|
||||||
constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b)
|
constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b)
|
||||||
{
|
{
|
||||||
return ((b & 31) << 10) | ((g & 31) << 5) | ((r & 31) << 0);
|
return ((b & 31) << 10) | ((g & 31) << 5) | ((r & 31) << 0);
|
||||||
@ -75,28 +79,6 @@ uint32_t cell_data(const start_size_t& buf, const uint32_t top)
|
|||||||
return base_address;
|
return base_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline void render_block(const uint32_t base_pattern,
|
|
||||||
const tileset_t& tileset,
|
|
||||||
const int32_t map_x,
|
|
||||||
const int32_t map_y,
|
|
||||||
const uint8_t block)
|
|
||||||
{
|
|
||||||
for (int32_t block_y = 0; block_y < 4; block_y++) {
|
|
||||||
for (int32_t block_x = 0; block_x < 4; block_x++) {
|
|
||||||
const int32_t block_ix = 4 * block_y + block_x;
|
|
||||||
const uint8_t tile_ix = tileset.blockset.start[block * 4 * 4 + block_ix];
|
|
||||||
|
|
||||||
const uint32_t cell_y = map_y * 4 + block_y;
|
|
||||||
const uint32_t cell_x = map_x * 4 + block_x;
|
|
||||||
// assumes NBG0 map plane_a is at offset 0
|
|
||||||
vdp2.vram.u16[64 * (cell_y % 64) + (cell_x % 64)] = (base_pattern & 0xfff) + tile_ix;
|
|
||||||
//vdp2.vram.u32[64 * cell_y + cell_x] = base_pattern + tile_ix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr int32_t last_map = map_t::wardens_house;
|
|
||||||
|
|
||||||
struct draw_t {
|
struct draw_t {
|
||||||
struct {
|
struct {
|
||||||
uint16_t tilesets[tileset_t::count]; // div 32
|
uint16_t tilesets[tileset_t::count]; // div 32
|
||||||
@ -104,17 +86,10 @@ struct draw_t {
|
|||||||
} base_pattern;
|
} base_pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct player_t {
|
|
||||||
struct {
|
|
||||||
int32_t x;
|
|
||||||
int32_t y;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct state_t {
|
struct state_t {
|
||||||
enum map_t::map map;
|
enum map_t::map map;
|
||||||
draw_t draw;
|
draw_t draw;
|
||||||
player_t player;
|
actor_t player;
|
||||||
};
|
};
|
||||||
|
|
||||||
static state_t state = { map_t::pallet_town, 0 };
|
static state_t state = { map_t::pallet_town, 0 };
|
||||||
@ -157,17 +132,10 @@ void load_vram()
|
|||||||
vdp1_top = load_sprite(vdp1_top, static_cast<enum spritesheet_t::spritesheet>(i));
|
vdp1_top = load_sprite(vdp1_top, static_cast<enum spritesheet_t::spritesheet>(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// screen space
|
void render_sprite(const uint32_t ix, const uint32_t sprite_id, const screen_t& screen, const offset_t& offset)
|
||||||
constexpr int32_t origin_px_x = ((320 - 160) / 2);
|
|
||||||
constexpr int32_t origin_px_y = ((240 - 144) / 2);
|
|
||||||
constexpr int32_t origin_cell_x = origin_px_x / 8;
|
|
||||||
constexpr int32_t origin_cell_y = origin_px_y / 8;
|
|
||||||
|
|
||||||
void render_sprites()
|
|
||||||
{
|
{
|
||||||
uint32_t ix = 2;
|
|
||||||
constexpr uint32_t color_address = 0;
|
constexpr uint32_t color_address = 0;
|
||||||
const uint32_t character_address = (state.draw.base_pattern.spritesheets[spritesheet_t::oak] * 128) / 8;
|
const uint32_t character_address = (state.draw.base_pattern.spritesheets[sprite_id] * 128) / 8;
|
||||||
|
|
||||||
vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE;
|
vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE;
|
||||||
vdp1.vram.cmd[ix].LINK = 0;
|
vdp1.vram.cmd[ix].LINK = 0;
|
||||||
@ -181,11 +149,28 @@ void render_sprites()
|
|||||||
vdp1.vram.cmd[ix].COLR = color_address; // non-palettized (rgb15) color data
|
vdp1.vram.cmd[ix].COLR = color_address; // non-palettized (rgb15) color data
|
||||||
vdp1.vram.cmd[ix].SRCA = character_address;
|
vdp1.vram.cmd[ix].SRCA = character_address;
|
||||||
vdp1.vram.cmd[ix].SIZE = SIZE__X(16) | SIZE__Y(16);
|
vdp1.vram.cmd[ix].SIZE = SIZE__X(16) | SIZE__Y(16);
|
||||||
vdp1.vram.cmd[ix].XA = origin_px_x + 4 * 16;
|
vdp1.vram.cmd[ix].XA = (cell_offset::x * 8) + screen.x * 16 - offset.x;
|
||||||
vdp1.vram.cmd[ix].YA = origin_px_y + 4 * 16 - 4;
|
vdp1.vram.cmd[ix].YA = (cell_offset::y * 8) + screen.y * 16 - 4 - offset.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_sprites(const offset_t& offset)
|
||||||
|
{
|
||||||
|
uint32_t ix = 2;
|
||||||
|
|
||||||
|
render_sprite(ix, spritesheet_t::red, {4, 4}, {0, 0});
|
||||||
ix++;
|
ix++;
|
||||||
|
|
||||||
|
const object_t& obj = map_objects[state.map];
|
||||||
|
for (uint32_t i = 0; i < obj.object_length; i++) {
|
||||||
|
const object_event_t& event = obj.object_events[i];
|
||||||
|
const world_t world = { event.position.x, event.position.y };
|
||||||
|
render_sprite(ix,
|
||||||
|
event.sprite_id,
|
||||||
|
world.to_screen(state.player.world),
|
||||||
|
offset);
|
||||||
|
ix++;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr uint16_t top_x = 80 - 1;
|
constexpr uint16_t top_x = 80 - 1;
|
||||||
constexpr uint16_t top_y = 48 - 1;
|
constexpr uint16_t top_y = 48 - 1;
|
||||||
constexpr uint16_t bot_x = 239 + 1;
|
constexpr uint16_t bot_x = 239 + 1;
|
||||||
@ -216,116 +201,54 @@ void render_sprites()
|
|||||||
vdp1.vram.cmd[ix].CTRL = CTRL__END;
|
vdp1.vram.cmd[ix].CTRL = CTRL__END;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t scroll = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
in block units:
|
|
||||||
|
|
||||||
world screen
|
|
||||||
-----------|---------
|
|
||||||
player 0,0 | map 4,4
|
|
||||||
|
|
||||||
scrolled 16,16
|
|
||||||
player 1,1 |
|
|
||||||
|
|
||||||
world | screen
|
|
||||||
--------------------------|---------
|
|
||||||
top left = player x - 5 | (add 4)
|
|
||||||
top right = player x - 5 | (add 4)
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
screen scroll
|
|
||||||
|
|
||||||
0,0 -> screen 0,0
|
|
||||||
1,1 -> screen 16,16
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// there are 16 pixels per block
|
|
||||||
|
|
||||||
static inline uint8_t get_block(const map_t& map, int32_t block_x, int32_t block_y)
|
|
||||||
{
|
|
||||||
const uint8_t border_block = map_objects[state.map].border_block;
|
|
||||||
|
|
||||||
const bool x_lt = block_x < static_cast<int32_t>(map.width);
|
|
||||||
const bool y_lt = block_y < static_cast<int32_t>(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);
|
|
||||||
const uint32_t north_y = north_map.height + block_y;
|
|
||||||
const uint32_t north_x = block_x - _offset(north);
|
|
||||||
return get_block(north_map, north_x, north_y);
|
|
||||||
} else {
|
|
||||||
return border_block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef _offset
|
|
||||||
#undef _get
|
|
||||||
#undef _has
|
|
||||||
}
|
|
||||||
|
|
||||||
void render_map()
|
void render_map()
|
||||||
{
|
{
|
||||||
state.player.x = 8 * 16;
|
|
||||||
if (++scroll > 1) {
|
|
||||||
scroll = 0;
|
|
||||||
//state.player.x += 1;
|
|
||||||
state.player.y -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
vdp2.reg.SCXIN0 = state.player.x - 16;
|
|
||||||
vdp2.reg.SCYIN0 = state.player.y - 16;
|
|
||||||
/*
|
|
||||||
vdp2.reg.WPSX0 = 80 << 1;
|
|
||||||
vdp2.reg.WPSY0 = 48;
|
|
||||||
vdp2.reg.WPEX0 = 239 << 1;
|
|
||||||
vdp2.reg.WPEY0 = 191;
|
|
||||||
vdp2.reg.WCTLA = WCTLA__N0W0E | WCTLA__N0W0A__OUTSIDE;
|
|
||||||
*/
|
|
||||||
|
|
||||||
const map_t& map = maps[state.map];
|
const map_t& map = maps[state.map];
|
||||||
const uint32_t base_pattern = state.draw.base_pattern.tilesets[map.tileset];
|
const uint32_t base_pattern = state.draw.base_pattern.tilesets[map.tileset];
|
||||||
vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((base_pattern >> 10) & 0x1f);
|
vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((base_pattern >> 10) & 0x1f);
|
||||||
|
|
||||||
int32_t origin_x = state.player.x / 32;
|
for (int32_t y = (0 - 1); y < (9 + 1); y++) {
|
||||||
int32_t origin_y = state.player.y / 32;
|
for (int32_t x = (0 - 1); x < (10 + 1); x++) {
|
||||||
|
render_screen(base_pattern,
|
||||||
fill<uint32_t>(vdp2.vram.u32, 0, 64 * 64 * 2);
|
map,
|
||||||
|
state.player.world,
|
||||||
for (int32_t y = origin_y - 3; y <= (origin_y + 3); y++) {
|
{x, y}
|
||||||
for (int32_t x = origin_x - 3; x <= (origin_x + 3); x++) {
|
);
|
||||||
const uint8_t block = get_block(map, x, y);
|
|
||||||
|
|
||||||
render_block(base_pattern,
|
|
||||||
tilesets[map.tileset],
|
|
||||||
x + 4,
|
|
||||||
y + 3,
|
|
||||||
block);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vdp2.reg.BGON = BGON__N0ON | BGON__N0TPON;
|
vdp2.reg.BGON = BGON__N0ON | BGON__N0TPON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update()
|
||||||
|
{
|
||||||
|
state.player.tick();
|
||||||
|
|
||||||
|
if (event::cursor_left()) {
|
||||||
|
state.player.move(actor_t::left);
|
||||||
|
//state.player.world.x--;
|
||||||
|
} else if (event::cursor_right()) {
|
||||||
|
state.player.move(actor_t::right);
|
||||||
|
//state.player.world.x++;
|
||||||
|
} else if (event::cursor_up()) {
|
||||||
|
state.player.move(actor_t::up);
|
||||||
|
//state.player.world.y--;
|
||||||
|
} else if (event::cursor_down()) {
|
||||||
|
state.player.move(actor_t::down);
|
||||||
|
//state.player.world.y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void render()
|
void render()
|
||||||
{
|
{
|
||||||
|
const offset_t offset = state.player.offset();
|
||||||
|
|
||||||
|
render_sprites(offset);
|
||||||
|
|
||||||
|
vdp2.reg.SCXIN0 = offset.x;
|
||||||
|
vdp2.reg.SCYIN0 = offset.y;
|
||||||
|
|
||||||
render_map();
|
render_map();
|
||||||
render_sprites();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -339,6 +262,7 @@ void v_blank_in_int()
|
|||||||
sh2.reg.FRC.L = 0;
|
sh2.reg.FRC.L = 0;
|
||||||
sh2.reg.FTCSR = 0; // clear flags
|
sh2.reg.FTCSR = 0; // clear flags
|
||||||
|
|
||||||
|
update();
|
||||||
render();
|
render();
|
||||||
|
|
||||||
// wait at least 300us, as specified in the SMPC manual.
|
// wait at least 300us, as specified in the SMPC manual.
|
||||||
@ -476,7 +400,6 @@ void init_vdp2()
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
state.map = map_t::pallet_town;
|
state.map = map_t::pallet_town;
|
||||||
state.player.y = 16 * 8;
|
|
||||||
|
|
||||||
load_vram();
|
load_vram();
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ struct object_event_t {
|
|||||||
pokemon,
|
pokemon,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum struct movement {
|
enum struct movement { // or 2-byte boulder movement?
|
||||||
stay,
|
stay,
|
||||||
walk,
|
walk,
|
||||||
};
|
};
|
||||||
@ -50,7 +50,7 @@ struct object_event_t {
|
|||||||
|
|
||||||
enum type type;
|
enum type type;
|
||||||
position_t position;
|
position_t position;
|
||||||
enum spritesheet_t::spritesheet sprite_id; // fixme
|
enum spritesheet_t::spritesheet sprite_id;
|
||||||
enum movement movement;
|
enum movement movement;
|
||||||
enum range_or_direction range_or_direction;
|
enum range_or_direction range_or_direction;
|
||||||
uint8_t text_id; // fixme
|
uint8_t text_id; // fixme
|
||||||
|
75
render_map.hpp
Normal file
75
render_map.hpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "coordinates.hpp"
|
||||||
|
#include "gen/maps.hpp"
|
||||||
|
#include "map_objects.hpp"
|
||||||
|
#include "vdp2.h"
|
||||||
|
|
||||||
|
static 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<int32_t>(map.width);
|
||||||
|
const bool y_lt = block.y < static_cast<int32_t>(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)) {
|
||||||
|
map_t north_map = _get(north);
|
||||||
|
return get_block(north_map, {
|
||||||
|
.x = block.x - _offset(north),
|
||||||
|
.y = static_cast<int32_t>(north_map.height + block.y),
|
||||||
|
});
|
||||||
|
} 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);
|
||||||
|
const block_t block = world.to_block();
|
||||||
|
|
||||||
|
const uint8_t block_ix = get_block(map, block);
|
||||||
|
const uint8_t * block_start = &(tilesets[map.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -97,10 +97,11 @@ def struct_map_t():
|
|||||||
*struct_connection_t(),
|
*struct_connection_t(),
|
||||||
"",
|
"",
|
||||||
"start_size_t blocks;",
|
"start_size_t blocks;",
|
||||||
"enum tileset_t::tileset tileset;",
|
|
||||||
"uint32_t width;",
|
"uint32_t width;",
|
||||||
"uint32_t height;",
|
"uint32_t height;",
|
||||||
"connection_t connections[4];",
|
"connection_t connections[4];",
|
||||||
|
"enum tileset_t::tileset tileset;",
|
||||||
|
"enum map id;",
|
||||||
"",
|
"",
|
||||||
f"static constexpr int32_t count = {len(_sorted_map_headers)};",
|
f"static constexpr int32_t count = {len(_sorted_map_headers)};",
|
||||||
"};",
|
"};",
|
||||||
@ -172,12 +173,13 @@ def map(map_header):
|
|||||||
".blocks = {",
|
".blocks = {",
|
||||||
*start_size_value(block_path),
|
*start_size_value(block_path),
|
||||||
"},",
|
"},",
|
||||||
f".tileset = tileset_t::{map_header.tileset.lower()},",
|
|
||||||
f".width = {map_constant.width},",
|
f".width = {map_constant.width},",
|
||||||
f".height = {map_constant.height},",
|
f".height = {map_constant.height},",
|
||||||
".connections = {",
|
".connections = {",
|
||||||
*connections(map_header),
|
*connections(map_header),
|
||||||
"},",
|
"},",
|
||||||
|
f".tileset = tileset_t::{map_header.tileset.lower()},",
|
||||||
|
f".id = map_t::{map_header.name2.lower()},",
|
||||||
"},",
|
"},",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user