1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-04-21 17:16:44 +00:00

Accumulate union of all pixel-bearing scans.

This commit is contained in:
Thomas Harte
2025-10-06 20:26:15 -04:00
parent d7b5a45417
commit 2c0610fef8
3 changed files with 123 additions and 71 deletions
+89 -71
View File
@@ -197,7 +197,7 @@ void CRT::advance_cycles(
) {
number_of_cycles *= time_multiplier_;
const bool is_output_run = (type == Scan::Type::Level) || (type == Scan::Type::Data);
const bool is_output_run = type == Scan::Type::Level || type == Scan::Type::Data;
const auto total_cycles = number_of_cycles;
bool did_output = false;
const auto end_point = [&] {
@@ -226,6 +226,7 @@ void CRT::advance_cycles(
!horizontal_flywheel_.is_in_retrace() &&
!vertical_flywheel_.is_in_retrace();
Outputs::Display::ScanTarget::Scan *const next_scan = is_output_segment ? scan_target_->begin_scan() : nullptr;
frame_is_complete_ &= !is_output_segment || bool(next_scan);
did_output |= is_output_segment;
// If outputting, store the start location and scan constants.
@@ -244,15 +245,30 @@ void CRT::advance_cycles(
next_run_length,
next_run_length == horizontal_event.second ? horizontal_event.first : Flywheel::SyncEvent::None
);
vertical_flywheel_.apply_event(
next_run_length,
next_run_length == vertical_event.second ? vertical_event.first : Flywheel::SyncEvent::None
);
const auto active_vertical_event =
next_run_length == vertical_event.second ? vertical_event.first : Flywheel::SyncEvent::None;
vertical_flywheel_.apply_event(next_run_length, active_vertical_event);
if(active_vertical_event == Flywheel::SyncEvent::StartRetrace) {
// TODO: filter active rectangle.
if(frame_is_complete_) {
scan_target_modals_.visible_area = active_rect_ / 65536.0f;
scan_target_->set_modals(scan_target_modals_);
}
active_rect_ = Display::Rect(65536.0f, 65536.0f, 0.0f, 0.0f);
frame_is_complete_ = true;
}
// End the scan if necessary.
if(next_scan) {
next_scan->end_points[1] = end_point();
scan_target_->end_scan();
active_rect_.expand(
next_scan->end_points[0].x, next_scan->end_points[0].y,
next_scan->end_points[1].x, next_scan->end_points[1].y
);
}
using Event = Outputs::Display::ScanTarget::Event;
@@ -487,71 +503,73 @@ void CRT::output_data(int number_of_cycles, size_t number_of_samples) {
// MARK: - Getters.
Outputs::Display::Rect CRT::get_rect_for_area(
int first_line_after_sync,
int number_of_lines,
int first_cycle_after_sync,
int number_of_cycles,
const float aspect_ratio
[[maybe_unused]] int first_line_after_sync,
[[maybe_unused]] int number_of_lines,
[[maybe_unused]] int first_cycle_after_sync,
[[maybe_unused]] int number_of_cycles,
[[maybe_unused]] const float aspect_ratio
) const {
assert(number_of_cycles > 0);
assert(number_of_lines > 0);
assert(first_line_after_sync >= 0);
assert(first_cycle_after_sync >= 0);
return Outputs::Display::Rect();
// Scale up x coordinates and add a little extra leeway to y.
first_cycle_after_sync *= time_multiplier_;
number_of_cycles *= time_multiplier_;
first_line_after_sync -= 2;
number_of_lines += 4;
// Determine prima facie x extent.
const int horizontal_period = horizontal_flywheel_.standard_period();
const int horizontal_scan_period = horizontal_flywheel_.scan_period();
const int horizontal_retrace_period = horizontal_period - horizontal_scan_period;
// Ensure requested range is within visible region.
first_cycle_after_sync = std::max(horizontal_retrace_period, first_cycle_after_sync);
number_of_cycles = std::min(horizontal_period - first_cycle_after_sync, number_of_cycles);
float start_x = float(first_cycle_after_sync - horizontal_retrace_period) / float(horizontal_scan_period);
float width = float(number_of_cycles) / float(horizontal_scan_period);
// Determine prima facie y extent.
const int vertical_period = vertical_flywheel_.standard_period();
const int vertical_scan_period = vertical_flywheel_.scan_period();
const int vertical_retrace_period = vertical_period - vertical_scan_period;
// Ensure range is visible.
first_line_after_sync = std::max(
first_line_after_sync * horizontal_period,
vertical_retrace_period
) / horizontal_period;
number_of_lines = std::min(
vertical_period - first_line_after_sync * horizontal_period,
number_of_lines * horizontal_period
) / horizontal_period;
float start_y =
float(first_line_after_sync * horizontal_period - vertical_retrace_period) /
float(vertical_scan_period);
float height = float(number_of_lines * horizontal_period) / vertical_scan_period;
// Pick a zoom that includes the entire requested visible area given the aspect ratio constraints.
const float adjusted_aspect_ratio = (3.0f*aspect_ratio / 4.0f);
const float ideal_width = height * adjusted_aspect_ratio;
if(ideal_width > width) {
start_x -= (ideal_width - width) * 0.5f;
width = ideal_width;
} else {
float ideal_height = width / adjusted_aspect_ratio;
start_y -= (ideal_height - height) * 0.5f;
height = ideal_height;
}
// TODO: apply absolute clipping constraints now.
return Outputs::Display::Rect(start_x, start_y, width, height);
// assert(number_of_cycles > 0);
// assert(number_of_lines > 0);
// assert(first_line_after_sync >= 0);
// assert(first_cycle_after_sync >= 0);
//
// // Scale up x coordinates and add a little extra leeway to y.
// first_cycle_after_sync *= time_multiplier_;
// number_of_cycles *= time_multiplier_;
//
// first_line_after_sync -= 2;
// number_of_lines += 4;
//
// // Determine prima facie x extent.
// const int horizontal_period = horizontal_flywheel_.standard_period();
// const int horizontal_scan_period = horizontal_flywheel_.scan_period();
// const int horizontal_retrace_period = horizontal_period - horizontal_scan_period;
//
// // Ensure requested range is within visible region.
// first_cycle_after_sync = std::max(horizontal_retrace_period, first_cycle_after_sync);
// number_of_cycles = std::min(horizontal_period - first_cycle_after_sync, number_of_cycles);
//
// float start_x = float(first_cycle_after_sync - horizontal_retrace_period) / float(horizontal_scan_period);
// float width = float(number_of_cycles) / float(horizontal_scan_period);
//
// // Determine prima facie y extent.
// const int vertical_period = vertical_flywheel_.standard_period();
// const int vertical_scan_period = vertical_flywheel_.scan_period();
// const int vertical_retrace_period = vertical_period - vertical_scan_period;
//
// // Ensure range is visible.
// first_line_after_sync = std::max(
// first_line_after_sync * horizontal_period,
// vertical_retrace_period
// ) / horizontal_period;
// number_of_lines = std::min(
// vertical_period - first_line_after_sync * horizontal_period,
// number_of_lines * horizontal_period
// ) / horizontal_period;
//
// float start_y =
// float(first_line_after_sync * horizontal_period - vertical_retrace_period) /
// float(vertical_scan_period);
// float height = float(number_of_lines * horizontal_period) / vertical_scan_period;
//
// // Pick a zoom that includes the entire requested visible area given the aspect ratio constraints.
// const float adjusted_aspect_ratio = (3.0f*aspect_ratio / 4.0f);
// const float ideal_width = height * adjusted_aspect_ratio;
// if(ideal_width > width) {
// start_x -= (ideal_width - width) * 0.5f;
// width = ideal_width;
// } else {
// float ideal_height = width / adjusted_aspect_ratio;
// start_y -= (ideal_height - height) * 0.5f;
// height = ideal_height;
// }
//
// // TODO: apply absolute clipping constraints now.
//
// return Outputs::Display::Rect(start_x, start_y, width, height);
}
Outputs::Display::ScanStatus CRT::get_scaled_scan_status() const {
@@ -582,9 +600,9 @@ void CRT::set_aspect_ratio(const float aspect_ratio) {
scan_target_->set_modals(scan_target_modals_);
}
void CRT::set_visible_area(const Outputs::Display::Rect visible_area) {
scan_target_modals_.visible_area = visible_area;
scan_target_->set_modals(scan_target_modals_);
void CRT::set_visible_area([[maybe_unused]] const Outputs::Display::Rect visible_area) {
// scan_target_modals_.visible_area = visible_area;
// scan_target_->set_modals(scan_target_modals_);
}
void CRT::set_display_type(const Outputs::Display::DisplayType display_type) {
+4
View File
@@ -363,6 +363,10 @@ private:
// Based upon a black level to maximum excursion and positive burst peak of: NTSC: 882 & 143; PAL: 933 & 150.
static constexpr uint8_t DefaultAmplitude = 41;
// Accumulator for interesting detail from this frame.
Outputs::Display::Rect active_rect_;
bool frame_is_complete_ = false;
#ifndef NDEBUG
size_t allocated_data_length_ = std::numeric_limits<size_t>::min();
#endif
+30
View File
@@ -34,6 +34,36 @@ struct Rect {
constexpr Rect() : origin({0.0f, 0.0f}), size({1.0f, 1.0f}) {}
constexpr Rect(float x, float y, float width, float height) :
origin({x, y}), size({width, height}) {}
bool empty() const {
return size.width == 0.0f || size.height == 0.0f;
}
void expand(const float min_x, const float max_x, const float min_y, float max_y) {
origin.x = std::min(origin.x, min_x);
size.width = std::max(size.width, max_x - origin.x);
origin.y = std::min(origin.x, min_y);
size.height = std::max(size.height, max_y - origin.y);
}
Rect operator *(const float multiplier) const {
return Rect(
origin.x * multiplier,
origin.y * multiplier,
size.width * multiplier,
size.height * multiplier
);
}
Rect operator /(const float multiplier) const {
return Rect(
origin.x / multiplier,
origin.y / multiplier,
size.width / multiplier,
size.height / multiplier
);
}
};
enum class ColourSpace {