mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 20:29:42 +00:00
Achieves a return of composite colour for RGB-producing machines.
This commit is contained in:
parent
d54b937ab6
commit
bf6a0c9fc4
@ -25,7 +25,7 @@ struct Uniforms {
|
||||
simd::float3x3 fromRGB;
|
||||
float zoom;
|
||||
simd::float2 offset;
|
||||
float firCoefficients[8];
|
||||
simd::float3 firCoefficients[8];
|
||||
};
|
||||
|
||||
constexpr size_t NumBufferedScans = 2048;
|
||||
@ -373,16 +373,33 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
||||
_compositionRenderPass.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
_compositionRenderPass.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
|
||||
// TODO: set proper clear colour for S-Video.
|
||||
// TODO: set proper clear colour for S-Video (and fragment function, below).
|
||||
|
||||
// TODO: work out fir coefficients, for real.
|
||||
simd::float3 *const firCoefficients = uniforms()->firCoefficients;
|
||||
const float cyclesPerLine = float(modals.cycles_per_line);
|
||||
const float colourCyclesPerLine = float(modals.colour_cycle_numerator) / float(modals.colour_cycle_denominator);
|
||||
SignalProcessing::FIRFilter filter(15, cyclesPerLine, 0.0f, 16.0f * cyclesPerLine / colourCyclesPerLine);
|
||||
|
||||
float *const firCoefficients = uniforms()->firCoefficients;
|
||||
const auto calculatedCoefficients = filter.get_coefficients();
|
||||
memcpy(firCoefficients, calculatedCoefficients.data(), calculatedCoefficients.size() * sizeof(float));
|
||||
if(isSVideoOutput) {
|
||||
// In S-Video, don't filter luminance.
|
||||
for(size_t c = 0; c < 7; ++c) {
|
||||
firCoefficients[c].x = 0.0f;
|
||||
}
|
||||
firCoefficients[7].x = 1.0f;
|
||||
} else {
|
||||
// In composite, filter luminance gently.
|
||||
SignalProcessing::FIRFilter luminancefilter(15, cyclesPerLine, 0.0f, colourCyclesPerLine * 0.75f);
|
||||
const auto calculatedCoefficients = luminancefilter.get_coefficients();
|
||||
for(size_t c = 0; c < 8; ++c) {
|
||||
firCoefficients[c].x = calculatedCoefficients[c];
|
||||
}
|
||||
}
|
||||
|
||||
// Whether S-Video or composite, apply the same relatively strong filter to colour channels.
|
||||
SignalProcessing::FIRFilter chrominancefilter(15, cyclesPerLine, 0.0f, colourCyclesPerLine * 0.125f);
|
||||
const auto calculatedCoefficients = chrominancefilter.get_coefficients();
|
||||
for(size_t c = 0; c < 8; ++c) {
|
||||
firCoefficients[c].y = firCoefficients[c].z = calculatedCoefficients[c];
|
||||
}
|
||||
}
|
||||
|
||||
// Build the output pipeline.
|
||||
@ -390,8 +407,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget;
|
||||
pipelineDescriptor.vertexFunction = [library newFunctionWithName:_isUsingCompositionPipeline ? @"lineToDisplay" : @"scanToDisplay"];
|
||||
|
||||
if(_isUsingCompositionPipeline) {
|
||||
// TODO!
|
||||
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"convertComposite"];
|
||||
pipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"filterFragment"];
|
||||
} else {
|
||||
const bool isRGBOutput = modals.display_type == Outputs::Display::DisplayType::RGB;
|
||||
pipelineDescriptor.fragmentFunction =
|
||||
|
@ -33,7 +33,7 @@ struct Uniforms {
|
||||
|
||||
// Describes the FIR filter in use; it'll be 15 coefficients but they're
|
||||
// symmetrical around the centre.
|
||||
float firCoefficients[8];
|
||||
float3 firCoefficients[8];
|
||||
};
|
||||
|
||||
namespace {
|
||||
@ -270,8 +270,11 @@ float3 convertRed1Green1Blue1(SourceInterpolator vert, texture2d<ushort> texture
|
||||
fragment float4 compositeSample##name(SourceInterpolator vert [[stage_in]], texture2d<pixelType> texture [[texture(0)]], constant Uniforms &uniforms [[buffer(0)]]) { \
|
||||
const auto colour = uniforms.fromRGB * convert##name(vert, texture); \
|
||||
const float2 colourSubcarrier = float2(sin(vert.colourPhase), cos(vert.colourPhase)); \
|
||||
const float level = mix(colour.r, dot(colour.gb, colourSubcarrier), vert.colourAmplitude); \
|
||||
return float4( \
|
||||
float3(mix(colour.r, dot(colour.gb, colourSubcarrier), vert.colourAmplitude)), \
|
||||
level, \
|
||||
0.5 + 0.5*level*sin(vert.colourPhase),\
|
||||
0.5 + 0.5*level*cos(vert.colourPhase),\
|
||||
1.0 \
|
||||
); \
|
||||
}
|
||||
@ -318,7 +321,7 @@ fragment float4 clearFragment() {
|
||||
|
||||
// MARK: - Conversion fragment shaders
|
||||
|
||||
fragment float4 convertComposite(CopyInterpolator vert [[stage_in]], texture2d<float> texture [[texture(0)]], constant Uniforms &uniforms [[buffer(0)]]) {
|
||||
fragment float4 filterFragment(SourceInterpolator vert [[stage_in]], texture2d<float> texture [[texture(0)]], constant Uniforms &uniforms [[buffer(0)]]) {
|
||||
const float3 colour =
|
||||
uniforms.firCoefficients[0] * texture.sample(standardSampler, vert.textureCoordinates - float2(7.0, 0.0)).rgb +
|
||||
uniforms.firCoefficients[1] * texture.sample(standardSampler, vert.textureCoordinates - float2(6.0, 0.0)).rgb +
|
||||
@ -336,5 +339,5 @@ fragment float4 convertComposite(CopyInterpolator vert [[stage_in]], texture2d<f
|
||||
uniforms.firCoefficients[1] * texture.sample(standardSampler, vert.textureCoordinates + float2(6.0, 0.0)).rgb +
|
||||
uniforms.firCoefficients[0] * texture.sample(standardSampler, vert.textureCoordinates + float2(7.0, 0.0)).rgb;
|
||||
|
||||
return float4(colour, 1.0);
|
||||
return float4(uniforms.toRGB * ((colour - float3(0.0, 0.5, 0.5)) * float3(1.0, 2.0 / vert.colourAmplitude, 2.0 / vert.colourAmplitude)), 1.0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user