mirror of
https://github.com/TomHarte/CLK.git
synced 2025-03-24 14:32:39 +00:00
Simplifies in-Metal transform logic, loading responsibility for setup onto the CPU.
I think I've also finally excised whatever order-of-operations issue I was having with regard to non-4:3 displays.
This commit is contained in:
parent
d7b405c6f8
commit
bcaceff378
@ -113,9 +113,7 @@ struct Uniforms {
|
||||
float cyclesMultiplier;
|
||||
float lineWidth;
|
||||
|
||||
float aspectRatioMultiplier;
|
||||
float zoom;
|
||||
simd::float2 offset;
|
||||
simd::float3x3 sourcetoDisplay;
|
||||
|
||||
HalfConverter<simd::float3x3> toRGB;
|
||||
HalfConverter<simd::float3x3> fromRGB;
|
||||
@ -505,18 +503,49 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
||||
- (void)setAspectRatio {
|
||||
const auto modals = _scanTarget.modals();
|
||||
const auto viewAspectRatio = (_view.bounds.size.width / _view.bounds.size.height);
|
||||
simd::float3x3 sourceToDisplay{1.0f};
|
||||
|
||||
// Set the aspect ratio multiplier.
|
||||
uniforms()->aspectRatioMultiplier = float(modals.aspect_ratio / viewAspectRatio);
|
||||
// The starting coordinate space is [0, 1].
|
||||
|
||||
// Also work out the proper zoom.
|
||||
const double fitWidthZoom = (viewAspectRatio / modals.aspect_ratio) / modals.visible_area.size.width;
|
||||
const double fitHeightZoom = 1.0 / modals.visible_area.size.height;
|
||||
uniforms()->zoom = float(std::min(fitWidthZoom, fitHeightZoom));
|
||||
// Move the centre of the cropping rectangle to the centre of the display.
|
||||
{
|
||||
simd::float3x3 recentre{1.0f};
|
||||
recentre.columns[2][0] = 0.5f - (modals.visible_area.origin.x + modals.visible_area.size.width * 0.5f);
|
||||
recentre.columns[2][1] = 0.5f - (modals.visible_area.origin.y + modals.visible_area.size.height * 0.5f);
|
||||
sourceToDisplay = recentre * sourceToDisplay;
|
||||
}
|
||||
|
||||
// Store the offset.
|
||||
uniforms()->offset.x = -modals.visible_area.origin.x;
|
||||
uniforms()->offset.y = -modals.visible_area.origin.y;
|
||||
// Convert from the internal [0, 1] to centred [-1, 1] (i.e. Metal's eye coordinates, though also appropriate
|
||||
// for the zooming step that follows).
|
||||
{
|
||||
simd::float3x3 convertToEye;
|
||||
convertToEye.columns[0][0] = 2.0f;
|
||||
convertToEye.columns[1][1] = -2.0f;
|
||||
convertToEye.columns[2][0] = -1.0f;
|
||||
convertToEye.columns[2][1] = 1.0f;
|
||||
convertToEye.columns[2][2] = 1.0f;
|
||||
sourceToDisplay = convertToEye * sourceToDisplay;
|
||||
}
|
||||
|
||||
// Determine the correct zoom level. This is a combination of (i) the necessary horizontal stretch to produce a proper
|
||||
// aspect ratio; and (ii) the necessary zoom from there to either fit the visible area width or height as per a decision
|
||||
// on letterboxing or pillarboxing.
|
||||
const float aspectRatioStretch = float(modals.aspect_ratio / viewAspectRatio);
|
||||
const float fitWidthZoom = 1.0f / (float(modals.visible_area.size.width) * aspectRatioStretch);
|
||||
const float fitHeightZoom = 1.0f / float(modals.visible_area.size.height);
|
||||
const float zoom = std::min(fitWidthZoom, fitHeightZoom);
|
||||
|
||||
// Convert from there to the proper aspect ratio by stretching or compressing width.
|
||||
// After this the output is exactly centred, filling the vertical space and being as wide or slender as it likes.
|
||||
{
|
||||
simd::float3x3 applyAspectRatio{1.0f};
|
||||
applyAspectRatio.columns[0][0] = aspectRatioStretch * zoom;
|
||||
applyAspectRatio.columns[1][1] = zoom;
|
||||
sourceToDisplay = applyAspectRatio * sourceToDisplay;
|
||||
}
|
||||
|
||||
// Store.
|
||||
uniforms()->sourcetoDisplay = sourceToDisplay;
|
||||
}
|
||||
|
||||
- (void)setModals:(const Outputs::Display::ScanTarget::Modals &)modals {
|
||||
|
@ -21,12 +21,8 @@ struct Uniforms {
|
||||
// This provides the intended height of a scan, in eye-coordinate terms.
|
||||
float lineWidth;
|
||||
|
||||
// Provides a scaling factor in order to preserve 4:3 central content.
|
||||
float aspectRatioMultiplier;
|
||||
|
||||
// Provides zoom and offset to scale the source data.
|
||||
float zoom;
|
||||
float2 offset;
|
||||
float3x3 sourceToDisplay;
|
||||
|
||||
// Provides conversions to and from RGB for the active colour space.
|
||||
half3x3 toRGB;
|
||||
@ -152,13 +148,8 @@ template <typename Input> SourceInterpolator toDisplay(
|
||||
// Hence determine this quad's real shape, using vertexID to pick a corner.
|
||||
|
||||
// position2d is now in the range [0, 1].
|
||||
float2 position2d = start + (float(vertexID&2) * 0.5f) * tangent + (float(vertexID&1) - 0.5f) * normal * uniforms.lineWidth;
|
||||
|
||||
// Apply the requested offset and zoom, to map the desired area to the range [0, 1].
|
||||
position2d = (position2d + uniforms.offset) * uniforms.zoom;
|
||||
|
||||
// Remap from [0, 1] to Metal's [-1, 1] and then apply the aspect ratio correction.
|
||||
position2d = (position2d * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f)) * float2(uniforms.aspectRatioMultiplier, 1.0f);
|
||||
const float2 sourcePosition = start + (float(vertexID&2) * 0.5f) * tangent + (float(vertexID&1) - 0.5f) * normal * uniforms.lineWidth;
|
||||
const float2 position2d = (uniforms.sourceToDisplay * float3(sourcePosition, 1.0f)).xy;
|
||||
|
||||
output.position = float4(
|
||||
position2d,
|
||||
|
Loading…
x
Reference in New Issue
Block a user