mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 23:32:28 +00:00
Switches to real SMS line output composition.
Including setting the sprite collision bit.
This commit is contained in:
parent
bca2161a05
commit
e410302237
@ -95,6 +95,10 @@ void Base::reset_sprite_collection() {
|
||||
sprite_set_.sprites_stopped = false;
|
||||
sprite_set_.fetched_sprite_slot = sprite_set_.active_sprite_slot;
|
||||
sprite_set_.active_sprite_slot = 0;
|
||||
|
||||
for(int c = 0; c < sprite_set_.fetched_sprite_slot; ++c) {
|
||||
sprite_set_.active_sprites[c].shift_position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Base::posit_sprite(int sprite_number, int sprite_position, int screen_row) {
|
||||
@ -710,108 +714,135 @@ void Base::draw_tms_text(int start, int end) {
|
||||
}
|
||||
|
||||
void Base::draw_sms(int start, int end) {
|
||||
int colour_buffer[256];
|
||||
const bool is_end = end == 256;
|
||||
|
||||
// If this is the very start of the line, clear the background
|
||||
// priority mask — it will be a bitfield in which 1s indicate locations
|
||||
// where the background should take priority over the sprites.
|
||||
if(!start) {
|
||||
memset(master_system_.background_priority_mask, 0, sizeof(master_system_.background_priority_mask));
|
||||
}
|
||||
|
||||
// Shift the output window by the fine scroll amount, and fill in
|
||||
// any border pixels that leaves on the left-hand side.
|
||||
/*
|
||||
Add extra border for any pixels that fall before the fine scroll.
|
||||
*/
|
||||
int tile_start = start, tile_end = end;
|
||||
if(row_ >= 16 || !master_system_.horizontal_scroll_lock) {
|
||||
start -= master_system_.horizontal_scroll & 7;
|
||||
end -= master_system_.horizontal_scroll & 7;
|
||||
if(start < 0) {
|
||||
while(start < end && start < 0) {
|
||||
*pixel_target_ = master_system_.colour_ram[16 + background_colour_];
|
||||
++pixel_target_;
|
||||
++start;
|
||||
}
|
||||
if(start == end) return;
|
||||
for(int c = start; c < (master_system_.horizontal_scroll & 7); ++c) {
|
||||
colour_buffer[c] = 16 + background_colour_;
|
||||
}
|
||||
tile_start -= master_system_.horizontal_scroll & 7;
|
||||
tile_end -= master_system_.horizontal_scroll & 7;
|
||||
}
|
||||
|
||||
const int shift = start & 7;
|
||||
int byte_column = start >> 3;
|
||||
int pixels_left = end - start;
|
||||
int length = std::min(pixels_left, 8 - shift);
|
||||
|
||||
uint32_t pattern = *reinterpret_cast<uint32_t *>(master_system_.tile_graphics[byte_column]);
|
||||
uint32_t pattern;
|
||||
uint8_t *const pattern_index = reinterpret_cast<uint8_t *>(&pattern);
|
||||
|
||||
if(master_system_.names[byte_column].flags&2)
|
||||
pattern >>= shift;
|
||||
else
|
||||
pattern <<= shift;
|
||||
/*
|
||||
Add background tiles; these will fill the colour_buffer with values in which
|
||||
the low five bits are a palette index, and bit six is set if this tile has
|
||||
priority over sprites.
|
||||
*/
|
||||
if(tile_start < end) {
|
||||
int offset = (master_system_.horizontal_scroll & 7) + tile_start;
|
||||
const int shift = tile_start & 7;
|
||||
int byte_column = tile_start >> 3;
|
||||
int pixels_left = tile_end - tile_start;
|
||||
int length = std::min(pixels_left, 8 - shift);
|
||||
|
||||
while(true) {
|
||||
pixels_left -= length;
|
||||
const int palette_offset = (master_system_.names[byte_column].flags&0x08) << 1;
|
||||
if(master_system_.names[byte_column].flags&2) {
|
||||
for(int c = 0; c < length; ++c) {
|
||||
const int value =
|
||||
((pattern_index[3] & 0x01) << 3) |
|
||||
((pattern_index[2] & 0x01) << 2) |
|
||||
((pattern_index[1] & 0x01) << 1) |
|
||||
((pattern_index[0] & 0x01) << 0) |
|
||||
palette_offset;
|
||||
pixel_target_[c] = master_system_.colour_ram[value];
|
||||
pattern >>= 1;
|
||||
pattern = *reinterpret_cast<uint32_t *>(master_system_.tile_graphics[byte_column]);
|
||||
if(master_system_.names[byte_column].flags&2)
|
||||
pattern >>= shift;
|
||||
else
|
||||
pattern <<= shift;
|
||||
|
||||
while(true) {
|
||||
pixels_left -= length;
|
||||
const int palette_offset = (master_system_.names[byte_column].flags&0x18) << 1;
|
||||
if(master_system_.names[byte_column].flags&2) {
|
||||
for(int c = 0; c < length; ++c) {
|
||||
colour_buffer[offset] =
|
||||
((pattern_index[3] & 0x01) << 3) |
|
||||
((pattern_index[2] & 0x01) << 2) |
|
||||
((pattern_index[1] & 0x01) << 1) |
|
||||
((pattern_index[0] & 0x01) << 0) |
|
||||
palette_offset;
|
||||
++offset;
|
||||
pattern >>= 1;
|
||||
}
|
||||
} else {
|
||||
for(int c = 0; c < length; ++c) {
|
||||
colour_buffer[offset] =
|
||||
((pattern_index[3] & 0x80) >> 4) |
|
||||
((pattern_index[2] & 0x80) >> 5) |
|
||||
((pattern_index[1] & 0x80) >> 6) |
|
||||
((pattern_index[0] & 0x80) >> 7) |
|
||||
palette_offset;
|
||||
++offset;
|
||||
pattern <<= 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int c = 0; c < length; ++c) {
|
||||
const int value =
|
||||
((pattern_index[3] & 0x80) >> 4) |
|
||||
((pattern_index[2] & 0x80) >> 5) |
|
||||
((pattern_index[1] & 0x80) >> 6) |
|
||||
((pattern_index[0] & 0x80) >> 7) |
|
||||
palette_offset;
|
||||
pixel_target_[c] = master_system_.colour_ram[value];
|
||||
pattern <<= 1;
|
||||
|
||||
if(!pixels_left) break;
|
||||
length = std::min(8, pixels_left);
|
||||
byte_column++;
|
||||
pattern = *reinterpret_cast<uint32_t *>(master_system_.tile_graphics[byte_column]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Apply sprites (if any).
|
||||
*/
|
||||
if(sprite_set_.fetched_sprite_slot) {
|
||||
int sprite_buffer[256];
|
||||
int sprite_collision = 0;
|
||||
memset(&sprite_buffer[start], 0, size_t(end - start)*sizeof(int));
|
||||
|
||||
// Draw all sprites into the sprite buffer.
|
||||
for(int index = sprite_set_.fetched_sprite_slot - 1; index >= 0; --index) {
|
||||
SpriteSet::ActiveSprite &sprite = sprite_set_.active_sprites[index];
|
||||
if(sprite.shift_position < 16) {
|
||||
int pixel_start = std::max(start, sprite.x);
|
||||
|
||||
// TODO: it feels like the work below should be simplifiable;
|
||||
// the double shift in particular, and hopefully the variable shift.
|
||||
for(int c = pixel_start; c < end && sprite.shift_position < 16; ++c) {
|
||||
const int shift = (sprite.shift_position >> 1);
|
||||
const int sprite_colour =
|
||||
(((sprite.image[3] << shift) & 0x80) >> 4) |
|
||||
(((sprite.image[2] << shift) & 0x80) >> 5) |
|
||||
(((sprite.image[1] << shift) & 0x80) >> 6) |
|
||||
(((sprite.image[0] << shift) & 0x80) >> 7);
|
||||
|
||||
if(sprite_colour) {
|
||||
sprite_collision |= sprite_buffer[c];
|
||||
sprite_buffer[c] = sprite_colour | 0x10;
|
||||
}
|
||||
|
||||
sprite.shift_position += sprites_magnified_ ? 1 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
pixel_target_ += length;
|
||||
|
||||
if(!pixels_left) break;
|
||||
length = std::min(8, pixels_left);
|
||||
byte_column++;
|
||||
pattern = *reinterpret_cast<uint32_t *>(master_system_.tile_graphics[byte_column]);
|
||||
// Draw the sprite buffer onto the colour buffer, wherever the tile map doesn't have
|
||||
// priority (or is transparent).
|
||||
for(int c = start; c < end; ++c) {
|
||||
if(
|
||||
sprite_buffer[c] &&
|
||||
(!(colour_buffer[c]&0x20) || !(colour_buffer[c]&0xf))
|
||||
) colour_buffer[c] = sprite_buffer[c];
|
||||
}
|
||||
|
||||
if(sprite_collision) status_ |= StatusSpriteCollision;
|
||||
}
|
||||
|
||||
// Map from the 32-colour buffer to real output pixels.
|
||||
for(int c = start; c < end; ++c) {
|
||||
pixel_target_[c] = master_system_.colour_ram[colour_buffer[c] & 0x1f];
|
||||
}
|
||||
|
||||
// If the VDP is set to hide the left column and this is the final call that'll come
|
||||
// this line, hide it.
|
||||
if(is_end && master_system_.hide_left_column) {
|
||||
pixel_origin_[0] = pixel_origin_[1] = pixel_origin_[2] = pixel_origin_[3] =
|
||||
pixel_origin_[4] = pixel_origin_[5] = pixel_origin_[6] = pixel_origin_[7] =
|
||||
master_system_.colour_ram[16 + background_colour_];
|
||||
|
||||
// EXPERIMENTAL: chuck sprite outlines on as a post-fix.
|
||||
for(int c = sprite_set_.fetched_sprite_slot - 1; c >= 0; --c) {
|
||||
int x = -sprite_set_.active_sprites[c].shift_position;
|
||||
pattern = *reinterpret_cast<uint32_t *>(sprite_set_.active_sprites[c].image);
|
||||
for(int ox = x; ox < x+8; ox++) {
|
||||
if(ox >= 0 && ox < 256) {
|
||||
if(
|
||||
((pattern_index[3] & 0x80) >> 4) |
|
||||
((pattern_index[2] & 0x80) >> 5) |
|
||||
((pattern_index[1] & 0x80) >> 6) |
|
||||
((pattern_index[0] & 0x80) >> 7)
|
||||
) {
|
||||
pixel_origin_[ox] =
|
||||
master_system_.colour_ram[
|
||||
((pattern_index[3] & 0x80) >> 4) |
|
||||
((pattern_index[2] & 0x80) >> 5) |
|
||||
((pattern_index[1] & 0x80) >> 6) |
|
||||
((pattern_index[0] & 0x80) >> 7) |
|
||||
0x10
|
||||
];
|
||||
}
|
||||
}
|
||||
pattern <<= 1;
|
||||
}
|
||||
if(is_end) {
|
||||
if(master_system_.hide_left_column) {
|
||||
pixel_origin_[0] = pixel_origin_[1] = pixel_origin_[2] = pixel_origin_[3] =
|
||||
pixel_origin_[4] = pixel_origin_[5] = pixel_origin_[6] = pixel_origin_[7] =
|
||||
master_system_.colour_ram[16 + background_colour_];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,6 @@ class Base {
|
||||
} names[32];
|
||||
uint8_t tile_graphics[32][4];
|
||||
size_t next_column = 0;
|
||||
uint32_t background_priority_mask[9];
|
||||
} master_system_;
|
||||
|
||||
// Holds results of sprite data fetches that occur on this
|
||||
@ -218,6 +217,7 @@ class Base {
|
||||
int row = 0;
|
||||
|
||||
uint8_t image[4];
|
||||
int x = 0;
|
||||
int shift_position = 0;
|
||||
} active_sprites[8];
|
||||
|
||||
@ -459,6 +459,7 @@ class Base {
|
||||
#undef fetch_columns_4
|
||||
#undef fetch_columns_2
|
||||
#undef fetch_column
|
||||
#undef fetch_tile_pattern
|
||||
#undef fetch_tile_name
|
||||
}
|
||||
|
||||
@ -583,10 +584,10 @@ class Base {
|
||||
|
||||
template<bool use_end> void fetch_sms(int start, int end) {
|
||||
#define sprite_fetch(sprite) {\
|
||||
sprite_set_.active_sprites[sprite].shift_position = \
|
||||
-ram_[\
|
||||
sprite_set_.active_sprites[sprite].x = \
|
||||
ram_[\
|
||||
sprite_attribute_table_address_ & size_t(0x3f80 | (sprite_set_.active_sprites[sprite].index << 1))\
|
||||
] + (master_system_.shift_sprites_8px_left ? size_t(8) : size_t(0)); \
|
||||
] - (master_system_.shift_sprites_8px_left ? size_t(8) : size_t(0)); \
|
||||
const uint8_t name = ram_[\
|
||||
sprite_attribute_table_address_ & size_t(0x3f81 | (sprite_set_.active_sprites[sprite].index << 1))\
|
||||
];\
|
||||
|
Loading…
Reference in New Issue
Block a user