main: rework sprite and tileset loading
All sprites and tilesets can fit at the same time. Load everything all at once to avoid flickering during drawing.
This commit is contained in:
parent
1b71c6cfb6
commit
485b2f8dd5
158
main.cpp
158
main.cpp
@ -15,6 +15,8 @@
|
||||
#include "gen/maps.hpp"
|
||||
#include "gen/sprites.hpp"
|
||||
#include "map_objects.hpp"
|
||||
#include "maps.hpp" // hack?
|
||||
#include "sprites.hpp"
|
||||
|
||||
constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b)
|
||||
{
|
||||
@ -100,52 +102,111 @@ constexpr inline void render_block(const uint32_t base_pattern,
|
||||
|
||||
constexpr int32_t last_map = map_t::wardens_house;
|
||||
|
||||
struct state_t {
|
||||
int32_t map_ix;
|
||||
enum tileset_t::tileset tileset;
|
||||
uint32_t base_pattern;
|
||||
struct draw_state_t {
|
||||
struct {
|
||||
uint16_t tilesets[tilesets_ix_last]; // div 32
|
||||
uint16_t spritesheets[spritesheets_ix_last]; // div 128
|
||||
} base_pattern;
|
||||
};
|
||||
|
||||
static state_t state = { 0, tileset_t::cavern, 0 };
|
||||
struct state_t {
|
||||
int32_t map_ix;
|
||||
draw_state_t draw;
|
||||
};
|
||||
|
||||
enum tileset_t::tileset load_tileset(enum tileset_t::tileset tileset)
|
||||
static state_t state = { 0 };
|
||||
|
||||
uint32_t load_tileset(uint32_t top, enum tileset_t::tileset tileset)
|
||||
{
|
||||
uint32_t top = (sizeof (union vdp2_vram));
|
||||
uint32_t base_address = top = cell_data(tilesets[tileset].tileset, top);
|
||||
state.base_pattern = base_address / 32;
|
||||
state.draw.base_pattern.tilesets[tileset] = base_address / 32;
|
||||
|
||||
/* use 1-word (16-bit) pattern names */
|
||||
/* update N0SCN in the event base_pattern moves (it usually does not) */
|
||||
vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((state.base_pattern >> 10) & 0x1f);
|
||||
|
||||
return tileset;
|
||||
return top;
|
||||
}
|
||||
|
||||
// fixme: remove hack
|
||||
#include "map.hpp"
|
||||
uint32_t load_sprite(uint32_t top, enum spritesheet_t::spritesheet spritesheet)
|
||||
{
|
||||
const spritesheet_t& s = spritesheets[spritesheet];
|
||||
uint32_t base_address = top = character_pattern_table(s.spritesheet, top);
|
||||
state.draw.base_pattern.spritesheets[spritesheet] = base_address / 128;
|
||||
|
||||
void render()
|
||||
return top;
|
||||
}
|
||||
|
||||
void load_vram()
|
||||
{
|
||||
vdp2.reg.CYCA0 = 0xeeee'eeee;
|
||||
vdp2.reg.CYCA1 = 0xeeee'eeee;
|
||||
vdp2.reg.CYCB0 = 0xeeee'eeee;
|
||||
vdp2.reg.CYCB1 = 0xeeee'eeee;
|
||||
|
||||
uint32_t vdp2_top = (sizeof (union vdp2_vram));
|
||||
for (uint32_t i = 0; i < tilesets_ix_last; i++)
|
||||
vdp2_top = load_tileset(vdp2_top, tilesets_ix[i]);
|
||||
|
||||
vdp2.reg.CYCA0 = 0x0fff'ffff;
|
||||
vdp2.reg.CYCA1 = 0xffff'ffff;
|
||||
vdp2.reg.CYCB0 = 0xffff'ffff;
|
||||
vdp2.reg.CYCB1 = 0x4fff'ffff;
|
||||
|
||||
uint32_t vdp1_top = (sizeof (union vdp1_vram));
|
||||
for (uint32_t i = 0; i < spritesheets_ix_last; i++)
|
||||
vdp1_top = load_sprite(vdp1_top, spritesheets_ix[i]);
|
||||
}
|
||||
|
||||
void render_sprites()
|
||||
{
|
||||
uint32_t ix = 2;
|
||||
constexpr uint32_t color_address = 0;
|
||||
const uint32_t character_address = (state.draw.base_pattern.spritesheets[spritesheet_t::oak] * 128) / 8;
|
||||
|
||||
vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE;
|
||||
vdp1.vram.cmd[ix].LINK = 0;
|
||||
// The "end code" is 0xf, which is being used in the mai sprite palette. If
|
||||
// both transparency and end codes are enabled, it seems there are only 14
|
||||
// usable colors in the 4-bit color mode.
|
||||
vdp1.vram.cmd[ix].PMOD = PMOD__ECD | PMOD__COLOR_MODE__COLOR_BANK_16;
|
||||
// It appears Kronos does not correctly calculate the color address in the
|
||||
// VDP1 debugger. Kronos will report FFFC when the actual color table address
|
||||
// in this example is 7FFE0.
|
||||
vdp1.vram.cmd[ix].COLR = color_address; // non-palettized (rgb15) color data
|
||||
vdp1.vram.cmd[ix].SRCA = character_address;
|
||||
vdp1.vram.cmd[ix].SIZE = SIZE__X(16) | SIZE__Y(16);
|
||||
vdp1.vram.cmd[ix].XA = 5 * 16;
|
||||
vdp1.vram.cmd[ix].YA = 5 * 16;
|
||||
|
||||
ix++;
|
||||
}
|
||||
|
||||
void render_map()
|
||||
{
|
||||
const map_t& map = maps[maps_ix[state.map_ix]];
|
||||
|
||||
if (map.tileset != state.tileset)
|
||||
state.tileset = load_tileset(map.tileset);
|
||||
|
||||
const uint8_t border_block = map_objects[maps_ix[state.map_ix]].border_block;
|
||||
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);
|
||||
|
||||
for (uint32_t map_y = 0; map_y < 16; map_y++) {
|
||||
for (uint32_t map_x = 0; map_x < 16; map_x++) {
|
||||
const uint8_t block =
|
||||
(map_x < map.width && map_y < map.height)
|
||||
? map.blocks.start[map.width * map_y + map_x]
|
||||
: border_block;
|
||||
render_block(state.base_pattern,
|
||||
? map.blocks.start[map.width * map_y + map_x]
|
||||
: border_block;
|
||||
|
||||
render_block(base_pattern,
|
||||
tilesets[map.tileset],
|
||||
map_x,
|
||||
map_y,
|
||||
block);
|
||||
}
|
||||
}
|
||||
|
||||
vdp2.reg.BGON = BGON__N0ON | BGON__N0TPON;
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
render_map();
|
||||
render_sprites();
|
||||
}
|
||||
|
||||
void update()
|
||||
@ -206,13 +267,8 @@ void smpc_int(void)
|
||||
intback::fsm(digital_callback, nullptr);
|
||||
}
|
||||
|
||||
void sprite()
|
||||
void init_vdp1()
|
||||
{
|
||||
uint32_t top = (sizeof (union vdp1_vram));
|
||||
const spritesheet_t& spritesheet = spritesheets[spritesheet_t::oak];
|
||||
uint32_t character_address = top = character_pattern_table(spritesheet.spritesheet, top);
|
||||
uint32_t color_address = 0;
|
||||
|
||||
/* TVM settings must be performed from the second H-blank IN interrupt after the
|
||||
V-blank IN interrupt to the H-blank IN interrupt immediately after the V-blank
|
||||
OUT interrupt. */
|
||||
@ -243,35 +299,14 @@ void sprite()
|
||||
vdp1.vram.cmd[1].XA = 0;
|
||||
vdp1.vram.cmd[1].YA = 0;
|
||||
|
||||
vdp1.vram.cmd[2].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE;
|
||||
vdp1.vram.cmd[2].LINK = 0;
|
||||
// The "end code" is 0xf, which is being used in the mai sprite palette. If
|
||||
// both transparency and end codes are enabled, it seems there are only 14
|
||||
// usable colors in the 4-bit color mode.
|
||||
vdp1.vram.cmd[2].PMOD = PMOD__ECD | PMOD__COLOR_MODE__COLOR_BANK_16;
|
||||
// It appears Kronos does not correctly calculate the color address in the
|
||||
// VDP1 debugger. Kronos will report FFFC when the actual color table address
|
||||
// in this example is 7FFE0.
|
||||
vdp1.vram.cmd[2].COLR = color_address; // non-palettized (rgb15) color data
|
||||
vdp1.vram.cmd[2].SRCA = character_address >> 3;
|
||||
vdp1.vram.cmd[2].SIZE = SIZE__X(16) | SIZE__Y(16);
|
||||
vdp1.vram.cmd[2].XA = 5 * 16;
|
||||
vdp1.vram.cmd[2].YA = 5 * 16;
|
||||
|
||||
vdp1.vram.cmd[3].CTRL = CTRL__END;
|
||||
vdp1.vram.cmd[2].CTRL = CTRL__END;
|
||||
|
||||
// start drawing (execute the command list) on every frame
|
||||
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
||||
}
|
||||
|
||||
void main()
|
||||
void init_vdp2()
|
||||
{
|
||||
state.map_ix = map_t::celadon_city;
|
||||
|
||||
v_blank_in();
|
||||
|
||||
sprite();
|
||||
|
||||
vdp2.reg.PRISA = PRISA__S0PRIN(7); // Sprite register 0 PRIority Number
|
||||
|
||||
// DISP: Please make sure to change this bit from 0 to 1 during V blank.
|
||||
@ -281,8 +316,8 @@ void main()
|
||||
/* set the color mode to 5bits per channel, 1024 colors */
|
||||
vdp2.reg.RAMCTL = RAMCTL__CRKTE | RAMCTL__CRMD__RGB_5BIT_1024 | RAMCTL__VRAMD | RAMCTL__VRBMD;
|
||||
|
||||
/* enable display of NBG0 */
|
||||
vdp2.reg.BGON = BGON__N0ON | BGON__N0TPON;
|
||||
/* disable display of NBG0 */
|
||||
vdp2.reg.BGON = 0;
|
||||
|
||||
/* set character format for NBG0 to palettized 16 color
|
||||
set enable "cell format" for NBG0
|
||||
@ -309,11 +344,18 @@ void main()
|
||||
vdp2.reg.MPCDN0 = MPABN0__N0MPD(0) | MPABN0__N0MPC(0); // bits 5~0
|
||||
|
||||
palette_data();
|
||||
}
|
||||
|
||||
vdp2.reg.CYCA0 = 0x0fff'ffff;
|
||||
vdp2.reg.CYCA1 = 0xffff'ffff;
|
||||
vdp2.reg.CYCB0 = 0xffff'ffff;
|
||||
vdp2.reg.CYCB1 = 0x4fff'ffff;
|
||||
void main()
|
||||
{
|
||||
state.map_ix = map_t::celadon_city;
|
||||
|
||||
load_vram();
|
||||
|
||||
v_blank_in();
|
||||
|
||||
init_vdp1();
|
||||
init_vdp2();
|
||||
|
||||
// free-running timer
|
||||
sh2.reg.TCR = TCR__CKS__INTERNAL_DIV128;
|
||||
|
@ -224,3 +224,32 @@ enum map_t::map maps_ix[] = {
|
||||
};
|
||||
|
||||
constexpr int map_ix_last = (sizeof (maps_ix)) / (sizeof (enum map_t::map));
|
||||
|
||||
enum tileset_t::tileset tilesets_ix[] = {
|
||||
tileset_t::cavern,
|
||||
tileset_t::cemetery,
|
||||
tileset_t::club,
|
||||
tileset_t::dojo,
|
||||
tileset_t::facility,
|
||||
tileset_t::forest,
|
||||
tileset_t::forest_gate,
|
||||
tileset_t::gate,
|
||||
tileset_t::gym,
|
||||
tileset_t::house,
|
||||
tileset_t::interior,
|
||||
tileset_t::lab,
|
||||
tileset_t::lobby,
|
||||
tileset_t::mansion,
|
||||
tileset_t::mart,
|
||||
tileset_t::museum,
|
||||
tileset_t::overworld,
|
||||
tileset_t::plateau,
|
||||
tileset_t::pokecenter,
|
||||
tileset_t::reds_house_1,
|
||||
tileset_t::reds_house_2,
|
||||
tileset_t::ship,
|
||||
tileset_t::ship_port,
|
||||
tileset_t::underground,
|
||||
};
|
||||
|
||||
constexpr int tilesets_ix_last = (sizeof (tilesets_ix)) / (sizeof (enum tileset_t::tileset));
|
77
sprites.hpp
Normal file
77
sprites.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
enum spritesheet_t::spritesheet spritesheets_ix[] = {
|
||||
spritesheet_t::agatha,
|
||||
spritesheet_t::balding_guy,
|
||||
spritesheet_t::beauty,
|
||||
spritesheet_t::biker,
|
||||
spritesheet_t::bike_shop_clerk,
|
||||
spritesheet_t::bird,
|
||||
spritesheet_t::blue,
|
||||
spritesheet_t::boulder,
|
||||
spritesheet_t::brunette_girl,
|
||||
spritesheet_t::bruno,
|
||||
spritesheet_t::captain,
|
||||
spritesheet_t::channeler,
|
||||
spritesheet_t::clerk,
|
||||
spritesheet_t::clipboard,
|
||||
spritesheet_t::cook,
|
||||
spritesheet_t::cooltrainer_f,
|
||||
spritesheet_t::cooltrainer_m,
|
||||
spritesheet_t::daisy,
|
||||
spritesheet_t::fairy,
|
||||
spritesheet_t::fisher,
|
||||
spritesheet_t::fishing_guru,
|
||||
spritesheet_t::fossil,
|
||||
spritesheet_t::gambler,
|
||||
spritesheet_t::gambler_asleep,
|
||||
spritesheet_t::gameboy_kid,
|
||||
spritesheet_t::gentleman,
|
||||
spritesheet_t::giovanni,
|
||||
spritesheet_t::girl,
|
||||
spritesheet_t::gramps,
|
||||
spritesheet_t::granny,
|
||||
spritesheet_t::guard,
|
||||
spritesheet_t::gym_guide,
|
||||
spritesheet_t::hiker,
|
||||
spritesheet_t::koga,
|
||||
spritesheet_t::lance,
|
||||
spritesheet_t::link_receptionist,
|
||||
spritesheet_t::little_boy,
|
||||
spritesheet_t::little_girl,
|
||||
spritesheet_t::lorelei,
|
||||
spritesheet_t::middle_aged_man,
|
||||
spritesheet_t::middle_aged_woman,
|
||||
spritesheet_t::mom,
|
||||
spritesheet_t::monster,
|
||||
spritesheet_t::mr_fuji,
|
||||
spritesheet_t::none,
|
||||
spritesheet_t::nurse,
|
||||
spritesheet_t::oak,
|
||||
spritesheet_t::old_amber,
|
||||
spritesheet_t::paper,
|
||||
spritesheet_t::pokedex,
|
||||
spritesheet_t::poke_ball,
|
||||
spritesheet_t::red,
|
||||
spritesheet_t::rocker,
|
||||
spritesheet_t::rocket,
|
||||
spritesheet_t::safari_zone_worker,
|
||||
spritesheet_t::sailor,
|
||||
spritesheet_t::scientist,
|
||||
spritesheet_t::seel,
|
||||
spritesheet_t::silph_president,
|
||||
spritesheet_t::silph_worker_f,
|
||||
spritesheet_t::silph_worker_m,
|
||||
spritesheet_t::snorlax,
|
||||
spritesheet_t::super_nerd,
|
||||
spritesheet_t::swimmer,
|
||||
spritesheet_t::unused_gambler_asleep_1,
|
||||
spritesheet_t::unused_gambler_asleep_2,
|
||||
spritesheet_t::unused_gameboy_kid,
|
||||
spritesheet_t::unused_guard,
|
||||
spritesheet_t::unused_old_amber,
|
||||
spritesheet_t::unused_scientist,
|
||||
spritesheet_t::waiter,
|
||||
spritesheet_t::warden,
|
||||
spritesheet_t::youngster,
|
||||
};
|
||||
|
||||
constexpr int spritesheets_ix_last = (sizeof (spritesheets_ix)) / (sizeof (enum spritesheet_t::spritesheet));
|
@ -49,7 +49,7 @@ def struct_spritesheet_t():
|
||||
"start_size_t spritesheet;",
|
||||
"uint8_t sprite_count;",
|
||||
"",
|
||||
"enum sprite {",
|
||||
"enum spritesheet {",
|
||||
*sprite_names,
|
||||
"};",
|
||||
"};",
|
||||
|
Loading…
x
Reference in New Issue
Block a user