1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 01:31:42 +00:00

Simplified relationship between Objects and the usage-specific components through inheritance.

This commit is contained in:
Thomas Harte 2017-02-21 07:37:20 -05:00
parent 7ab2358bba
commit 1bde0fed6f
2 changed files with 64 additions and 66 deletions

View File

@ -328,12 +328,12 @@ void TIA::set_player_position(int player)
// one behind its real hardware value, creating the extra delay; and (ii) the player
// code is written to start a draw upon wraparound from 159 to 0, so -1 is the
// correct option rather than 159.
object_[(int)MotionIndex::Player0 + player].position = -1;
player_[player].position = -1;
}
void TIA::set_player_motion(int player, uint8_t motion)
{
object_[(int)MotionIndex::Player0 + player].motion = (motion >> 4)&0xf;
player_[player].motion = (motion >> 4)&0xf;
}
void TIA::set_player_missile_colour(int player, uint8_t colour)
@ -348,18 +348,18 @@ void TIA::set_missile_enable(int missile, bool enabled)
void TIA::set_missile_position(int missile)
{
object_[(int)MotionIndex::Missile0 + missile].position = 0;
missile_[missile].position = 0;
}
void TIA::set_missile_position_to_player(int missile)
{
// TODO: implement this correctly; should be triggered by player counter hitting the appropriate point
object_[(int)MotionIndex::Missile0 + missile].position = object_[(int)MotionIndex::Player0 + missile].position + 5;
missile_[missile].position = player_[missile].position + 5;
}
void TIA::set_missile_motion(int missile, uint8_t motion)
{
object_[(int)MotionIndex::Missile0 + missile].motion = (motion >> 4)&0xf;
missile_[missile].motion = (motion >> 4)&0xf;
}
void TIA::set_ball_enable(bool enabled)
@ -374,7 +374,7 @@ void TIA::set_ball_delay(bool delay)
void TIA::set_ball_position()
{
object_[(int)MotionIndex::Ball].position = 0;
ball_.position = 0;
// setting the ball position also triggers a draw
ball_.reset_pixels();
@ -382,20 +382,20 @@ void TIA::set_ball_position()
void TIA::set_ball_motion(uint8_t motion)
{
object_[(int)MotionIndex::Ball].motion = (motion >> 4) & 0xf;
ball_.motion = (motion >> 4) & 0xf;
}
void TIA::move()
{
horizontal_blank_extend_ = true;
object_[0].is_moving = object_[1].is_moving = object_[2].is_moving = object_[3].is_moving = object_[4].is_moving = true;
object_[0].motion_step = object_[1].motion_step = object_[2].motion_step = object_[3].motion_step = object_[4].motion_step = 15;
object_[0].motion_time = object_[1].motion_time = object_[2].motion_time = object_[3].motion_time = object_[4].motion_time = (horizontal_counter_ + 3) & ~3;
player_[0].is_moving = player_[1].is_moving = missile_[0].is_moving = missile_[1].is_moving = ball_.is_moving = true;
player_[0].motion_step = player_[1].motion_step = missile_[0].motion_step = missile_[1].motion_step = ball_.motion_step = 15;
player_[0].motion_time = player_[1].motion_time = missile_[0].motion_time = missile_[1].motion_time = ball_.motion_time = (horizontal_counter_ + 3) & ~3;
}
void TIA::clear_motion()
{
object_[0].motion = object_[1].motion = object_[2].motion = object_[3].motion = object_[4].motion = 0;
player_[0].motion = player_[1].motion = missile_[0].motion = missile_[1].motion = ball_.motion = 0;
}
uint8_t TIA::get_collision_flags(int offset)
@ -432,18 +432,23 @@ void TIA::output_for_cycles(int number_of_cycles)
if(line_end_function_) line_end_function_(collision_buffer_.data());
memset(collision_buffer_.data(), 0, 160); // sizeof(collision_buffer_)
horizontal_blank_extend_ = false;
for(int c = 0; c < 5; c++) object_[c].motion_time %= 228;
ball_.motion_time %= 228;
player_[0].motion_time %= 228;
player_[1].motion_time %= 228;
missile_[0].motion_time %= 228;
missile_[1].motion_time %= 228;
}
// accumulate an OR'd version of the output into the collision buffer
int latent_start = output_cursor + 4;
int latent_end = horizontal_counter_ + 4;
draw_playfield(latent_start, latent_end);
draw_player(player_[0], object_[(int)MotionIndex::Player0], CollisionType::Player0, output_cursor, horizontal_counter_);
draw_player(player_[1], object_[(int)MotionIndex::Player1], CollisionType::Player1, output_cursor, horizontal_counter_);
draw_missile(missile_[0], object_[(int)MotionIndex::Missile0], CollisionType::Missile0, output_cursor, horizontal_counter_);
draw_missile(missile_[1], object_[(int)MotionIndex::Missile1], CollisionType::Missile1, output_cursor, horizontal_counter_);
draw_ball(object_[(int)MotionIndex::Ball], output_cursor, horizontal_counter_);
draw_player(player_[0], CollisionType::Player0, output_cursor, horizontal_counter_);
draw_player(player_[1], CollisionType::Player1, output_cursor, horizontal_counter_);
draw_missile(missile_[0], CollisionType::Missile0, output_cursor, horizontal_counter_);
draw_missile(missile_[1], CollisionType::Missile1, output_cursor, horizontal_counter_);
draw_ball(output_cursor, horizontal_counter_);
// convert to television signals
@ -649,14 +654,14 @@ int TIA::perform_border_motion(Object &object, int start, int end)
return steps_taken;
}
template<class T> void TIA::draw_object(T &target, Object &object, const uint8_t collision_identity, int start, int end)
template<class T> void TIA::draw_object(T &object, const uint8_t collision_identity, int start, int end)
{
int first_pixel = first_pixel_cycle - 4 + (horizontal_blank_extend_ ? 8 : 0);
// movement works across the entire screen, so do work that falls outside of the pixel area
if(start < first_pixel)
{
target.skip_pixels(perform_border_motion(object, start, std::max(end, first_pixel)));
object.skip_pixels(perform_border_motion(object, start, std::max(end, first_pixel)));
}
// don't continue to do any drawing if this window ends too early
@ -667,18 +672,18 @@ template<class T> void TIA::draw_object(T &target, Object &object, const uint8_t
// perform the visible part of the line, if any
if(start < 224)
{
draw_object_visible<T>(target, object, collision_identity, start - first_pixel_cycle + 4, std::min(end - first_pixel_cycle + 4, 160));
draw_object_visible<T>(object, collision_identity, start - first_pixel_cycle + 4, std::min(end - first_pixel_cycle + 4, 160));
}
// move further if required
if(object.is_moving && end >= 224 && object.motion_time < end)
{
perform_motion_step(object);
target.skip_pixels(1);
object.skip_pixels(1);
}
}
template<class T> void TIA::draw_object_visible(T &target, Object &object, const uint8_t collision_identity, int start, int end)
template<class T> void TIA::draw_object_visible(T &object, const uint8_t collision_identity, int start, int end)
{
// perform a miniature event loop on (i) triggering draws; (ii) drawing; and (iii) motion
int next_motion_time = object.motion_time - first_pixel_cycle + 4;
@ -694,15 +699,15 @@ template<class T> void TIA::draw_object_visible(T &target, Object &object, const
// is the next event a graphics trigger?
int next_copy = 160;
if(target.copy_flags)
if(object.copy_flags)
{
if(object.position < 16 && target.copy_flags&1)
if(object.position < 16 && object.copy_flags&1)
{
next_copy = 16;
} else if(object.position < 32 && target.copy_flags&2)
} else if(object.position < 32 && object.copy_flags&2)
{
next_copy = 32;
} else if(object.position < 64 && target.copy_flags&4)
} else if(object.position < 64 && object.copy_flags&4)
{
next_copy = 64;
}
@ -714,7 +719,7 @@ template<class T> void TIA::draw_object_visible(T &target, Object &object, const
// the decision is to progress by length
const int length = next_event_time - start;
target.draw_pixels(&collision_buffer_[start], length, collision_identity);
object.draw_pixels(&collision_buffer_[start], length, collision_identity);
// the next interesting event is after next_event_time cycles, so progress
object.position = (object.position + length) % 160;
@ -730,24 +735,24 @@ template<class T> void TIA::draw_object_visible(T &target, Object &object, const
// if it's a draw trigger, trigger a draw
if(start == next_copy_time)
{
target.reset_pixels();
object.reset_pixels();
}
}
}
#pragma mark - Player output
void TIA::draw_player(Player &player, Object &object, CollisionType collision_identity, int start, int end)
void TIA::draw_player(Player &player, CollisionType collision_identity, int start, int end)
{
draw_object<Player>(player, object, (uint8_t)collision_identity, start, end);
draw_object<Player>(player, (uint8_t)collision_identity, start, end);
}
void TIA::draw_missile(Missile &missile, Object &object, CollisionType collision_identity, int start, int end)
void TIA::draw_missile(Missile &missile, CollisionType collision_identity, int start, int end)
{
draw_object<Missile>(missile, object, (uint8_t)collision_identity, start, end);
draw_object<Missile>(missile, (uint8_t)collision_identity, start, end);
}
void TIA::draw_ball(Object &object, int start, int end)
void TIA::draw_ball(int start, int end)
{
draw_object<Ball>(ball_, object, (uint8_t)CollisionType::Ball, start, end);
draw_object<Ball>(ball_, (uint8_t)CollisionType::Ball, start, end);
}

View File

@ -135,8 +135,24 @@ class TIA {
// background_[1] on the right; otherwise background_[0] will be
// output twice.
// objects
struct Object {
// the two programmer-set values
int position;
int motion;
// motion_step_ is the current motion counter value; motion_time_ is the next time it will fire
int motion_step;
int motion_time;
// indicates whether this object is currently undergoing motion
bool is_moving;
Object() : is_moving(false) {};
};
// player state
struct Player {
struct Player: public Object {
int adder;
int copy_flags; // a bit field, corresponding to the first few values of NUSIZ
uint8_t graphic[2]; // the player graphic; 1 = new, 0 = current
@ -179,7 +195,7 @@ class TIA {
} player_[2];
// missile state
struct Missile {
struct Missile: public Object {
bool enabled;
int size;
int copy_flags;
@ -217,7 +233,7 @@ class TIA {
} missile_[2];
// ball state
struct Ball {
struct Ball: public Object {
bool enabled[2];
int enabled_index;
int size;
@ -257,45 +273,22 @@ class TIA {
Ball() : pixel_position(0), size(1), enabled_index(0) {}
} ball_;
// movement
bool horizontal_blank_extend_;
struct Object {
// the two programmer-set values
int position;
int motion;
// motion_step_ is the current motion counter value; motion_time_ is the next time it will fire
int motion_step;
int motion_time;
// indicates whether this object is currently undergoing motion
bool is_moving;
Object() : is_moving(false) {};
} object_[5];
enum class MotionIndex : uint8_t {
Ball,
Player0,
Player1,
Missile0,
Missile1
};
// motion
bool horizontal_blank_extend_;
inline int perform_border_motion(Object &object, int start, int end);
inline void perform_motion_step(Object &object);
// drawing methods and state
template<class T> void draw_object(T &, Object &, const uint8_t collision_identity, int start, int end);
template<class T> void draw_object_visible(T &, Object &, const uint8_t collision_identity, int start, int end);
template<class T> void draw_object(T &, const uint8_t collision_identity, int start, int end);
template<class T> void draw_object_visible(T &, const uint8_t collision_identity, int start, int end);
inline void output_for_cycles(int number_of_cycles);
inline void output_line();
inline void draw_playfield(int start, int end);
inline void draw_player(Player &player, Object &object, CollisionType collision_identity, int start, int end);
inline void draw_missile(Missile &missile, Object &object, CollisionType collision_identity, int start, int end);
inline void draw_ball(Object &object, int start, int end);
inline void draw_player(Player &player, CollisionType collision_identity, int start, int end);
inline void draw_missile(Missile &missile, CollisionType collision_identity, int start, int end);
inline void draw_ball(int start, int end);
int pixels_start_location_;
uint8_t *pixel_target_;