diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm index 292be240d..31f82e7aa 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm +++ b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm @@ -20,6 +20,8 @@ struct Uniforms { float aspectRatioMultiplier; simd::float3x3 toRGB; simd::float3x3 fromRGB; + float zoom; + simd::float2 offset; }; constexpr size_t NumBufferedScans = 2048; @@ -186,7 +188,20 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; } - (void)setAspectRatio { - uniforms()->aspectRatioMultiplier = float(_scanTarget.modals().aspect_ratio / (_view.bounds.size.width / _view.bounds.size.height)); + const auto modals = _scanTarget.modals(); + const auto viewAspectRatio = (_view.bounds.size.width / _view.bounds.size.height); + + // Set the aspect ratio multiplier. + uniforms()->aspectRatioMultiplier = float(modals.aspect_ratio / viewAspectRatio); + + // Also work out the proper zoom. Somehow? + const double fitWidthZoom = (viewAspectRatio / modals.aspect_ratio) / modals.visible_area.size.width; + const double fitHeightZoom = 1.0 / modals.visible_area.size.height; + + // The differing signs for offset below reflect the inverted coordinate system in Metal. + uniforms()->zoom = float(std::min(fitWidthZoom, fitHeightZoom)); + uniforms()->offset.x = -modals.visible_area.origin.x; + uniforms()->offset.y = -modals.visible_area.origin.y; } - (void)setModals:(const Outputs::Display::ScanTarget::Modals &)modals { diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal b/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal index fa780d6c2..32faf8b6c 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal +++ b/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal @@ -26,6 +26,10 @@ struct Uniforms { // Provides conversions to and from RGB for the active colour space. float3x3 toRGB; float3x3 fromRGB; + + // Provides zoom and offset to scale the source data. + float zoom; + float2 offset; }; // MARK: - Structs used for receiving data from the emulation. @@ -97,8 +101,11 @@ vertex SourceInterpolator scanToDisplay( constant Uniforms &uniforms [[buffer(1) ) / 32.0; // Hence determine this quad's real shape, using vertexID to pick a corner. + float2 position2d = start + (float(vertexID&2) * 0.5) * tangent + (float(vertexID&1) - 0.5) * normal * uniforms.lineWidth; + position2d = (position2d + uniforms.offset) * uniforms.zoom * float2(uniforms.aspectRatioMultiplier, 1.0); + position2d = position2d * float2(2.0, -2.0) + float2(-1.0, 1.0); output.position = float4( - ((start + (float(vertexID&2) * 0.5) * tangent + (float(vertexID&1) - 0.5) * normal * uniforms.lineWidth) * float2(2.0, -2.0) + float2(-1.0, 1.0)) * float2(uniforms.aspectRatioMultiplier, 1.0), + position2d, 0.0, 1.0 );