mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Overtly link line and sprite buffers.
This commit is contained in:
parent
e0a5d9f31c
commit
024b7960cb
@ -56,7 +56,6 @@ Base<personality>::Base() :
|
||||
fetch_line_buffer_ = line_buffers_.begin();
|
||||
draw_line_buffer_ = line_buffers_.begin();
|
||||
fetch_sprite_buffer_ = sprite_buffers_.begin();
|
||||
draw_sprite_buffer_ = sprite_buffers_.begin();
|
||||
}
|
||||
|
||||
template <Personality personality>
|
||||
@ -131,9 +130,8 @@ void Base<personality>::posit_sprite(int sprite_number, int sprite_position, uin
|
||||
// Evaluation of visibility of sprite 0 is always the first step in
|
||||
// populating a sprite buffer; so use it to uncork a new one.
|
||||
if(!sprite_number) {
|
||||
fetch_line_buffer_->fetched_sprites = true;
|
||||
|
||||
advance(fetch_sprite_buffer_);
|
||||
fetched_sprites_ = &*fetch_sprite_buffer_;
|
||||
fetch_sprite_buffer_->reset_sprite_collection();
|
||||
fetch_sprite_buffer_->sprite_terminator = mode_timing_.sprite_terminator(fetch_line_buffer_->screen_mode);
|
||||
|
||||
@ -349,6 +347,13 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
||||
}
|
||||
|
||||
this->advance(this->fetch_line_buffer_);
|
||||
if(this->fetched_sprites_->active_sprite_slot) {
|
||||
this->fetch_line_buffer_->sprites = this->fetched_sprites_;
|
||||
this->fetched_sprites_ = nullptr;
|
||||
} else {
|
||||
this->fetch_line_buffer_->sprites = nullptr;
|
||||
this->regress(this->fetch_sprite_buffer_);
|
||||
}
|
||||
|
||||
// Establish the current screen output mode, which will be captured as a
|
||||
// line mode momentarily.
|
||||
@ -367,7 +372,6 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
||||
this->fetch_line_buffer_->next_border_column = Timing<personality>::CyclesPerLine;
|
||||
this->fetch_line_buffer_->pixel_count = 256;
|
||||
this->fetch_line_buffer_->screen_mode = this->screen_mode_;
|
||||
this->fetch_line_buffer_->fetched_sprites = false;
|
||||
this->mode_timing_.maximum_visible_sprites = 4;
|
||||
switch(this->screen_mode_) {
|
||||
case ScreenMode::Text:
|
||||
@ -606,12 +610,6 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
||||
// -------------
|
||||
this->output_pointer_.column = end_column;
|
||||
if(end_column == Timing<personality>::CyclesPerLine) {
|
||||
// Clear all sprites from this sprite buffer.
|
||||
this->draw_sprite_buffer_->active_sprite_slot = 0;
|
||||
// Advance to the next sprite buffer only if this one was populated by this line.
|
||||
if(this->draw_line_buffer_->fetched_sprites) {
|
||||
this->advance(this->draw_sprite_buffer_);
|
||||
}
|
||||
// Advance line buffer.
|
||||
this->advance(this->draw_line_buffer_);
|
||||
}
|
||||
|
@ -217,13 +217,19 @@ template <Personality personality> struct Base: public Storage<personality> {
|
||||
using SpriteBufferArray = std::array<SpriteBuffer, 313>;
|
||||
SpriteBufferArray sprite_buffers_;
|
||||
SpriteBufferArray::iterator fetch_sprite_buffer_;
|
||||
SpriteBufferArray::iterator draw_sprite_buffer_;
|
||||
SpriteBuffer *fetched_sprites_ = nullptr;
|
||||
void advance(SpriteBufferArray::iterator &iterator) {
|
||||
++iterator;
|
||||
if(iterator == sprite_buffers_.end()) {
|
||||
iterator = sprite_buffers_.begin();
|
||||
}
|
||||
}
|
||||
void regress(SpriteBufferArray::iterator &iterator) {
|
||||
if(iterator == sprite_buffers_.begin()) {
|
||||
iterator = sprite_buffers_.end();
|
||||
}
|
||||
--iterator;
|
||||
}
|
||||
|
||||
AddressT tile_offset_ = 0;
|
||||
uint8_t name_[4]{};
|
||||
|
@ -14,7 +14,11 @@
|
||||
template <Personality personality>
|
||||
template <SpriteMode mode, bool double_width>
|
||||
void Base<personality>::draw_sprites(uint8_t y, int start, int end, const std::array<uint32_t, 16> &palette, int *colour_buffer) {
|
||||
auto &buffer = *draw_sprite_buffer_;
|
||||
if(!draw_line_buffer_->sprites) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &buffer = *draw_line_buffer_->sprites;
|
||||
if(!buffer.active_sprite_slot) {
|
||||
return;
|
||||
}
|
||||
|
@ -14,6 +14,54 @@
|
||||
namespace TI::TMS {
|
||||
|
||||
// Temporary buffers collect a representation of each line prior to pixel serialisation.
|
||||
|
||||
struct SpriteBuffer {
|
||||
// An active sprite is one that has been selected for composition onto
|
||||
// _this_ line.
|
||||
struct ActiveSprite {
|
||||
int index = 0; // The original in-table index of this sprite.
|
||||
int row = 0; // The row of the sprite that should be drawn.
|
||||
int x = 0; // The sprite's x position on screen.
|
||||
|
||||
uint8_t image[4]; // Up to four bytes of image information.
|
||||
//
|
||||
// In practice:
|
||||
//
|
||||
// Master System mode: the four bytes of this 8x8 sprite;
|
||||
// TMS and Yamaha: [0] = the left half of this sprite; [1] = the right side (if 16x16 sprites enabled); [2] = colour, early-clock bit, etc.
|
||||
int shift_position = 0; // An offset representing how much of the image information has already been drawn.
|
||||
|
||||
// Yamaha helpers.
|
||||
bool opaque() const {
|
||||
return !(image[2] & 0x40);
|
||||
}
|
||||
|
||||
/// @returns @c 0x20 if this sprite should generate collisions; @c 0x00 otherwise.
|
||||
int collision_bit() const {
|
||||
return ((image[2] & 0x20) | ((image[2] & 0x40) >> 1)) ^ 0x20;
|
||||
}
|
||||
|
||||
// Yamaha and TMS helpers.
|
||||
int early_clock() const {
|
||||
return (image[2] & 0x80) >> 2;
|
||||
}
|
||||
} active_sprites[8];
|
||||
|
||||
int active_sprite_slot = 0; // A pointer to the slot into which a new active sprite will be deposited, if required.
|
||||
bool sprites_stopped = false; // A special TMS feature is that a sentinel value can be used to prevent any further sprites
|
||||
// being evaluated for display. This flag determines whether the sentinel has yet been reached.
|
||||
uint8_t sprite_terminator = 0;
|
||||
|
||||
#ifndef NDEBUG
|
||||
static constexpr bool test_is_filling = true;
|
||||
#else
|
||||
static constexpr bool test_is_filling = false;
|
||||
#endif
|
||||
bool is_filling = false;
|
||||
|
||||
void reset_sprite_collection();
|
||||
};
|
||||
|
||||
struct LineBuffer {
|
||||
LineBuffer() {}
|
||||
|
||||
@ -22,7 +70,7 @@ struct LineBuffer {
|
||||
FetchMode fetch_mode = FetchMode::Text;
|
||||
ScreenMode screen_mode = ScreenMode::Text;
|
||||
VerticalState vertical_state = VerticalState::Blank;
|
||||
bool fetched_sprites = false;
|
||||
SpriteBuffer *sprites = nullptr;
|
||||
|
||||
// Holds the horizontal scroll position to apply to this line;
|
||||
// of those VDPs currently implemented, affects the Master System only.
|
||||
@ -75,53 +123,6 @@ struct LineBuffer {
|
||||
int pixel_count = 256;
|
||||
};
|
||||
|
||||
struct SpriteBuffer {
|
||||
// An active sprite is one that has been selected for composition onto
|
||||
// _this_ line.
|
||||
struct ActiveSprite {
|
||||
int index = 0; // The original in-table index of this sprite.
|
||||
int row = 0; // The row of the sprite that should be drawn.
|
||||
int x = 0; // The sprite's x position on screen.
|
||||
|
||||
uint8_t image[4]; // Up to four bytes of image information.
|
||||
//
|
||||
// In practice:
|
||||
//
|
||||
// Master System mode: the four bytes of this 8x8 sprite;
|
||||
// TMS and Yamaha: [0] = the left half of this sprite; [1] = the right side (if 16x16 sprites enabled); [2] = colour, early-clock bit, etc.
|
||||
int shift_position = 0; // An offset representing how much of the image information has already been drawn.
|
||||
|
||||
// Yamaha helpers.
|
||||
bool opaque() const {
|
||||
return !(image[2] & 0x40);
|
||||
}
|
||||
|
||||
/// @returns @c 0x20 if this sprite should generate collisions; @c 0x00 otherwise.
|
||||
int collision_bit() const {
|
||||
return ((image[2] & 0x20) | ((image[2] & 0x40) >> 1)) ^ 0x20;
|
||||
}
|
||||
|
||||
// Yamaha and TMS helpers.
|
||||
int early_clock() const {
|
||||
return (image[2] & 0x80) >> 2;
|
||||
}
|
||||
} active_sprites[8];
|
||||
|
||||
int active_sprite_slot = 0; // A pointer to the slot into which a new active sprite will be deposited, if required.
|
||||
bool sprites_stopped = false; // A special TMS feature is that a sentinel value can be used to prevent any further sprites
|
||||
// being evaluated for display. This flag determines whether the sentinel has yet been reached.
|
||||
uint8_t sprite_terminator = 0;
|
||||
|
||||
#ifndef NDEBUG
|
||||
static constexpr bool test_is_filling = true;
|
||||
#else
|
||||
static constexpr bool test_is_filling = false;
|
||||
#endif
|
||||
bool is_filling = false;
|
||||
|
||||
void reset_sprite_collection();
|
||||
};
|
||||
|
||||
struct LineBufferPointer {
|
||||
int row = 0, column = 0;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user