mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-01 11:49:58 +00:00
Removes dead files.
This commit is contained in:
parent
76656fab23
commit
dd4af4f0df
@ -1369,10 +1369,6 @@
|
|||||||
4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Oric.hpp; path = Oric/Oric.hpp; sourceTree = "<group>"; };
|
4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Oric.hpp; path = Oric/Oric.hpp; sourceTree = "<group>"; };
|
||||||
4BD060A51FE49D3C006E14BE /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Speaker.hpp; sourceTree = "<group>"; };
|
4BD060A51FE49D3C006E14BE /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Speaker.hpp; sourceTree = "<group>"; };
|
||||||
4BD191D9219113B80042E144 /* OpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OpenGL.hpp; sourceTree = "<group>"; };
|
4BD191D9219113B80042E144 /* OpenGL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OpenGL.hpp; sourceTree = "<group>"; };
|
||||||
4BD191E0219113B80042E144 /* IntermediateShader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IntermediateShader.hpp; sourceTree = "<group>"; };
|
|
||||||
4BD191E1219113B80042E144 /* OutputShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OutputShader.cpp; sourceTree = "<group>"; };
|
|
||||||
4BD191E3219113B80042E144 /* IntermediateShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermediateShader.cpp; sourceTree = "<group>"; };
|
|
||||||
4BD191E4219113B80042E144 /* OutputShader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OutputShader.hpp; sourceTree = "<group>"; };
|
|
||||||
4BD191F22191180E0042E144 /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; };
|
4BD191F22191180E0042E144 /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; };
|
||||||
4BD191F32191180E0042E144 /* ScanTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ScanTarget.hpp; sourceTree = "<group>"; };
|
4BD191F32191180E0042E144 /* ScanTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ScanTarget.hpp; sourceTree = "<group>"; };
|
||||||
4BD388411FE34E010042B588 /* 9918Base.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 9918Base.hpp; path = 9918/Implementation/9918Base.hpp; sourceTree = "<group>"; };
|
4BD388411FE34E010042B588 /* 9918Base.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 9918Base.hpp; path = 9918/Implementation/9918Base.hpp; sourceTree = "<group>"; };
|
||||||
@ -3031,23 +3027,11 @@
|
|||||||
4BD191D9219113B80042E144 /* OpenGL.hpp */,
|
4BD191D9219113B80042E144 /* OpenGL.hpp */,
|
||||||
4BD191F32191180E0042E144 /* ScanTarget.hpp */,
|
4BD191F32191180E0042E144 /* ScanTarget.hpp */,
|
||||||
4BD424DC2193B5340097291A /* Primitives */,
|
4BD424DC2193B5340097291A /* Primitives */,
|
||||||
4BD191DF219113B80042E144 /* Shaders */,
|
|
||||||
);
|
);
|
||||||
name = OpenGL;
|
name = OpenGL;
|
||||||
path = ../../Outputs/OpenGL;
|
path = ../../Outputs/OpenGL;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
4BD191DF219113B80042E144 /* Shaders */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
4BD191E3219113B80042E144 /* IntermediateShader.cpp */,
|
|
||||||
4BD191E1219113B80042E144 /* OutputShader.cpp */,
|
|
||||||
4BD191E0219113B80042E144 /* IntermediateShader.hpp */,
|
|
||||||
4BD191E4219113B80042E144 /* OutputShader.hpp */,
|
|
||||||
);
|
|
||||||
path = Shaders;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
4BD388431FE34E060042B588 /* Implementation */ = {
|
4BD388431FE34E060042B588 /* Implementation */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1,435 +0,0 @@
|
|||||||
//
|
|
||||||
// IntermediateShader.cpp
|
|
||||||
// Clock Signal
|
|
||||||
//
|
|
||||||
// Created by Thomas Harte on 28/04/2016.
|
|
||||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "IntermediateShader.hpp"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstring>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "../../../SignalProcessing/FIRFilter.hpp"
|
|
||||||
|
|
||||||
using namespace OpenGL;
|
|
||||||
|
|
||||||
std::string IntermediateShader::get_input_name(Input input) {
|
|
||||||
switch(input) {
|
|
||||||
case Input::InputStart: return "inputStart";
|
|
||||||
case Input::OutputStart: return "outputStart";
|
|
||||||
case Input::Ends: return "ends";
|
|
||||||
case Input::PhaseTimeAndAmplitude: return "phaseTimeAndAmplitude";
|
|
||||||
|
|
||||||
// Intended to be unreachable.
|
|
||||||
default: assert(false); return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const std::string &fragment_shader, bool use_usampler, bool input_is_inputPosition) {
|
|
||||||
std::ostringstream vertex_shader;
|
|
||||||
vertex_shader <<
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec2 " << get_input_name(Input::InputStart) << ";"
|
|
||||||
"in vec2 " << get_input_name(Input::OutputStart) << ";"
|
|
||||||
"in vec2 " << get_input_name(Input::Ends) << ";"
|
|
||||||
"in vec3 " << get_input_name(Input::PhaseTimeAndAmplitude) << ";"
|
|
||||||
|
|
||||||
"uniform ivec2 outputTextureSize;"
|
|
||||||
"uniform float extension;"
|
|
||||||
"uniform " << (use_usampler ? "usampler2D" : "sampler2D") << " texID;"
|
|
||||||
"uniform float offsets[5];"
|
|
||||||
"uniform vec2 widthScalers;"
|
|
||||||
"uniform float inputVerticalOffset;"
|
|
||||||
"uniform float outputVerticalOffset;"
|
|
||||||
"uniform float textureHeightDivisor;"
|
|
||||||
|
|
||||||
"out vec3 phaseAndAmplitudeVarying;"
|
|
||||||
"out vec2 inputPositionsVarying[11];"
|
|
||||||
"out vec2 delayLinePositionVarying;"
|
|
||||||
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
// odd vertices are on the left, even on the right
|
|
||||||
"float extent = float(gl_VertexID & 1);"
|
|
||||||
"float longitudinal = float((gl_VertexID & 2) >> 1);"
|
|
||||||
|
|
||||||
// inputPosition.x is either inputStart.x or ends.x, depending on whether it is on the left or the right;
|
|
||||||
// outputPosition.x is either outputStart.x or ends.y;
|
|
||||||
// .ys are inputStart.y and outputStart.y respectively
|
|
||||||
"vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent)*widthScalers[0], inputStart.y + inputVerticalOffset);"
|
|
||||||
"vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent)*widthScalers[1], outputStart.y + outputVerticalOffset);"
|
|
||||||
|
|
||||||
"inputPosition.y += longitudinal;"
|
|
||||||
"outputPosition.y += longitudinal;"
|
|
||||||
|
|
||||||
// extension is the amount to extend both the input and output by to add a full colour cycle at each end
|
|
||||||
"vec2 extensionVector = vec2(extension, 0.0) * 2.0 * (extent - 0.5);"
|
|
||||||
|
|
||||||
// extended[Input/Output]Position are [input/output]Position with the necessary applied extension
|
|
||||||
"vec2 extendedInputPosition = " << (input_is_inputPosition ? "inputPosition" : "outputPosition") << " + extensionVector;"
|
|
||||||
"vec2 extendedOutputPosition = outputPosition + extensionVector;"
|
|
||||||
|
|
||||||
// scale mappedInputPosition to the ordinary normalised range
|
|
||||||
"vec2 textureSize = vec2(textureSize(texID, 0));"
|
|
||||||
"vec2 mappedInputPosition = extendedInputPosition / textureSize;"
|
|
||||||
|
|
||||||
// setup input positions spaced as per the supplied offsets; these are for filtering where required
|
|
||||||
"inputPositionsVarying[0] = mappedInputPosition - (vec2(5.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[1] = mappedInputPosition - (vec2(4.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[2] = mappedInputPosition - (vec2(3.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[3] = mappedInputPosition - (vec2(2.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[4] = mappedInputPosition - (vec2(1.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[5] = mappedInputPosition;"
|
|
||||||
"inputPositionsVarying[6] = mappedInputPosition + (vec2(1.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[7] = mappedInputPosition + (vec2(2.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[8] = mappedInputPosition + (vec2(3.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[9] = mappedInputPosition + (vec2(4.0, 0.0) / textureSize);"
|
|
||||||
"inputPositionsVarying[10] = mappedInputPosition + (vec2(5.0, 0.0) / textureSize);"
|
|
||||||
"delayLinePositionVarying = mappedInputPosition - vec2(0.0, 1.0);"
|
|
||||||
|
|
||||||
// setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians;
|
|
||||||
// setup phaseAndAmplitudeVarying.y as colour burst amplitude;
|
|
||||||
// setup phaseAndAmplitudeVarying.z as 1 / abs(colour burst amplitude), or 0.0 if amplitude is 0.0;
|
|
||||||
"phaseAndAmplitudeVarying.x = (extendedOutputPosition.x + (phaseTimeAndAmplitude.x / 64.0)) * 0.5 * 3.141592654;"
|
|
||||||
"phaseAndAmplitudeVarying.y = (phaseTimeAndAmplitude.y - 128) / 127.0;"
|
|
||||||
"phaseAndAmplitudeVarying.z = (abs(phaseAndAmplitudeVarying.y) > 0.05) ? 1.0 / abs(phaseAndAmplitudeVarying.y) : 0.0;"
|
|
||||||
|
|
||||||
// determine output position by scaling the output position according to the texture size
|
|
||||||
"vec2 eyePosition = 2.0*(extendedOutputPosition / outputTextureSize) - vec2(1.0);"
|
|
||||||
"gl_Position = vec4(eyePosition, 0.0, 1.0);"
|
|
||||||
"}";
|
|
||||||
|
|
||||||
return std::unique_ptr<IntermediateShader>(new IntermediateShader(vertex_shader.str(), fragment_shader, {
|
|
||||||
{get_input_name(Input::InputStart), 0},
|
|
||||||
{get_input_name(Input::OutputStart), 1},
|
|
||||||
{get_input_name(Input::Ends), 2},
|
|
||||||
{get_input_name(Input::PhaseTimeAndAmplitude), 3}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IntermediateShader> IntermediateShader::make_composite_source_shader(const std::string &composite_shader, const std::string &svideo_shader, const std::string &rgb_shader) {
|
|
||||||
std::ostringstream fragment_shader;
|
|
||||||
fragment_shader <<
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec2 inputPositionsVarying[11];"
|
|
||||||
"in vec3 phaseAndAmplitudeVarying;"
|
|
||||||
|
|
||||||
"out vec4 fragColour;"
|
|
||||||
|
|
||||||
"uniform usampler2D texID;"
|
|
||||||
<< composite_shader;
|
|
||||||
|
|
||||||
if(composite_shader.empty()) {
|
|
||||||
if(!svideo_shader.empty()) {
|
|
||||||
fragment_shader <<
|
|
||||||
svideo_shader <<
|
|
||||||
"float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
|
|
||||||
"{"
|
|
||||||
"vec2 svideoColour = svideo_sample(texID, coordinate, phase, amplitude);"
|
|
||||||
"return mix(svideoColour.x, svideoColour.y, abs(amplitude));"
|
|
||||||
"}";
|
|
||||||
} else {
|
|
||||||
fragment_shader <<
|
|
||||||
rgb_shader <<
|
|
||||||
"uniform mat3 rgbToLumaChroma;"
|
|
||||||
"float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
|
|
||||||
"{"
|
|
||||||
"vec3 rgbColour = clamp(rgb_sample(texID, coordinate), vec3(0.0), vec3(1.0));"
|
|
||||||
"vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;"
|
|
||||||
"vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(abs(amplitude), amplitude);"
|
|
||||||
"return dot(lumaChromaColour, vec3(1.0 - abs(amplitude), quadrature));"
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment_shader <<
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"fragColour = vec4(composite_sample(texID, inputPositionsVarying[5], phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y));"
|
|
||||||
"}";
|
|
||||||
|
|
||||||
return make_shader(fragment_shader.str(), true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IntermediateShader> IntermediateShader::make_svideo_source_shader(const std::string &svideo_shader, const std::string &rgb_shader) {
|
|
||||||
std::ostringstream fragment_shader;
|
|
||||||
fragment_shader <<
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec2 inputPositionsVarying[11];"
|
|
||||||
"in vec3 phaseAndAmplitudeVarying;"
|
|
||||||
|
|
||||||
"out vec3 fragColour;"
|
|
||||||
|
|
||||||
"uniform usampler2D texID;"
|
|
||||||
<< svideo_shader;
|
|
||||||
|
|
||||||
if(svideo_shader.empty()) {
|
|
||||||
fragment_shader
|
|
||||||
<< rgb_shader <<
|
|
||||||
"uniform mat3 rgbToLumaChroma;"
|
|
||||||
"vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
|
|
||||||
"{"
|
|
||||||
"vec3 rgbColour = clamp(rgb_sample(texID, coordinate), vec3(0.0), vec3(1.0));"
|
|
||||||
"vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;"
|
|
||||||
"vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(1.0, sign(amplitude));"
|
|
||||||
"return vec2(lumaChromaColour.x, 0.5 + dot(quadrature, lumaChromaColour.yz) * 0.5);"
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment_shader <<
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"vec2 sample = svideo_sample(texID, inputPositionsVarying[5], phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y);"
|
|
||||||
"vec2 quadrature = vec2(cos(phaseAndAmplitudeVarying.x), sin(phaseAndAmplitudeVarying.x)) * vec2(1.0, sign(phaseAndAmplitudeVarying.y)) * 0.5 * phaseAndAmplitudeVarying.z;"
|
|
||||||
"fragColour = vec3(sample.x, vec2(0.5) + (sample.y * quadrature));"
|
|
||||||
"}";
|
|
||||||
|
|
||||||
return make_shader(fragment_shader.str(), true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IntermediateShader> IntermediateShader::make_rgb_source_shader(const std::string &rgb_shader) {
|
|
||||||
std::ostringstream fragment_shader;
|
|
||||||
fragment_shader <<
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec2 inputPositionsVarying[11];"
|
|
||||||
"in vec3 phaseAndAmplitudeVarying;"
|
|
||||||
|
|
||||||
"out vec3 fragColour;"
|
|
||||||
|
|
||||||
"uniform usampler2D texID;"
|
|
||||||
|
|
||||||
<< rgb_shader <<
|
|
||||||
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"fragColour = rgb_sample(texID, inputPositionsVarying[5]);"
|
|
||||||
"}";
|
|
||||||
|
|
||||||
return make_shader(fragment_shader.str(), true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IntermediateShader> IntermediateShader::make_chroma_luma_separation_shader() {
|
|
||||||
return make_shader(
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec3 phaseAndAmplitudeVarying;"
|
|
||||||
"in vec2 inputPositionsVarying[11];"
|
|
||||||
|
|
||||||
"out vec3 fragColour;"
|
|
||||||
|
|
||||||
"uniform sampler2D texID;"
|
|
||||||
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"vec4 samples = vec4("
|
|
||||||
"texture(texID, inputPositionsVarying[3]).r,"
|
|
||||||
"texture(texID, inputPositionsVarying[4]).r,"
|
|
||||||
"texture(texID, inputPositionsVarying[5]).r,"
|
|
||||||
"texture(texID, inputPositionsVarying[6]).r"
|
|
||||||
");"
|
|
||||||
// calculate luminance as either the straight average of the samples, if a colour subcarrier
|
|
||||||
// was present, or else a weighted sample around the third sample if not.
|
|
||||||
"float luminance = mix(dot(samples, vec4(0.25)), dot(samples, vec4(0.0, 0.16, 0.66, 0.16)), step(phaseAndAmplitudeVarying.z, 0.0));"
|
|
||||||
|
|
||||||
// define chroma to be whatever was here, minus luma
|
|
||||||
"float chrominance = 0.5 * (samples.z - luminance) * phaseAndAmplitudeVarying.z;"
|
|
||||||
|
|
||||||
// scale luminance up to the range [0, 1)
|
|
||||||
"luminance /= (1.0 - abs(phaseAndAmplitudeVarying.y));"
|
|
||||||
|
|
||||||
// split choma colours here, as the most direct place, writing out
|
|
||||||
// RGB = (luma, chroma.x, chroma.y)
|
|
||||||
"vec2 quadrature = vec2(cos(phaseAndAmplitudeVarying.x), sin(phaseAndAmplitudeVarying.x)) * vec2(1.0, sign(phaseAndAmplitudeVarying.y));"
|
|
||||||
"fragColour = vec3(luminance, vec2(0.5) + (chrominance * quadrature));"
|
|
||||||
"}",false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IntermediateShader> IntermediateShader::make_chroma_filter_shader() {
|
|
||||||
return make_shader(
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec2 inputPositionsVarying[11];"
|
|
||||||
"uniform vec4 weights[3];"
|
|
||||||
|
|
||||||
"out vec3 fragColour;"
|
|
||||||
|
|
||||||
"uniform sampler2D texID;"
|
|
||||||
"uniform mat3 lumaChromaToRGB;"
|
|
||||||
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"vec3 samples[] = vec3[]("
|
|
||||||
"texture(texID, inputPositionsVarying[3]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[4]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[5]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[6]).rgb"
|
|
||||||
");"
|
|
||||||
|
|
||||||
"vec4 chromaChannel1 = vec4(samples[0].g, samples[1].g, samples[2].g, samples[3].g);"
|
|
||||||
"vec4 chromaChannel2 = vec4(samples[0].b, samples[1].b, samples[2].b, samples[3].b);"
|
|
||||||
|
|
||||||
"vec3 lumaChromaColour = vec3(samples[2].r,"
|
|
||||||
"dot(chromaChannel1, vec4(0.25)),"
|
|
||||||
"dot(chromaChannel2, vec4(0.25))"
|
|
||||||
");"
|
|
||||||
|
|
||||||
"vec3 lumaChromaColourInRange = (lumaChromaColour - vec3(0.0, 0.5, 0.5)) * vec3(1.0, 2.0, 2.0);"
|
|
||||||
"fragColour = lumaChromaToRGB * lumaChromaColourInRange;"
|
|
||||||
"}", false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IntermediateShader> IntermediateShader::make_rgb_filter_shader() {
|
|
||||||
return make_shader(
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec2 inputPositionsVarying[11];"
|
|
||||||
"uniform vec4 weights[3];"
|
|
||||||
|
|
||||||
"out vec3 fragColour;"
|
|
||||||
|
|
||||||
"uniform sampler2D texID;"
|
|
||||||
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"vec3 samples[] = vec3[]("
|
|
||||||
"texture(texID, inputPositionsVarying[0]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[1]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[2]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[3]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[4]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[5]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[6]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[7]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[8]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[9]).rgb,"
|
|
||||||
"texture(texID, inputPositionsVarying[10]).rgb"
|
|
||||||
");"
|
|
||||||
|
|
||||||
"vec4 channel1[] = vec4[]("
|
|
||||||
"vec4(samples[0].r, samples[1].r, samples[2].r, samples[3].r),"
|
|
||||||
"vec4(samples[4].r, samples[5].r, samples[6].r, samples[7].r),"
|
|
||||||
"vec4(samples[8].r, samples[9].r, samples[10].r, 0.0)"
|
|
||||||
");"
|
|
||||||
"vec4 channel2[] = vec4[]("
|
|
||||||
"vec4(samples[0].g, samples[1].g, samples[2].g, samples[3].g),"
|
|
||||||
"vec4(samples[4].g, samples[5].g, samples[6].g, samples[7].g),"
|
|
||||||
"vec4(samples[8].g, samples[9].g, samples[10].g, 0.0)"
|
|
||||||
");"
|
|
||||||
"vec4 channel3[] = vec4[]("
|
|
||||||
"vec4(samples[0].b, samples[1].b, samples[2].b, samples[3].b),"
|
|
||||||
"vec4(samples[4].b, samples[5].b, samples[6].b, samples[7].b),"
|
|
||||||
"vec4(samples[8].b, samples[9].b, samples[10].b, 0.0)"
|
|
||||||
");"
|
|
||||||
|
|
||||||
"fragColour = vec3("
|
|
||||||
"dot(vec3("
|
|
||||||
"dot(channel1[0], weights[0]),"
|
|
||||||
"dot(channel1[1], weights[1]),"
|
|
||||||
"dot(channel1[2], weights[2])"
|
|
||||||
"), vec3(1.0)),"
|
|
||||||
"dot(vec3("
|
|
||||||
"dot(channel2[0], weights[0]),"
|
|
||||||
"dot(channel2[1], weights[1]),"
|
|
||||||
"dot(channel2[2], weights[2])"
|
|
||||||
"), vec3(1.0)),"
|
|
||||||
"dot(vec3("
|
|
||||||
"dot(channel3[0], weights[0]),"
|
|
||||||
"dot(channel3[1], weights[1]),"
|
|
||||||
"dot(channel3[2], weights[2])"
|
|
||||||
"), vec3(1.0))"
|
|
||||||
");"
|
|
||||||
"}", false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_output_size(unsigned int output_width, unsigned int output_height) {
|
|
||||||
set_uniform("outputTextureSize", (GLint)output_width, (GLint)output_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_source_texture_unit(GLenum unit) {
|
|
||||||
set_uniform("texID", (GLint)(unit - GL_TEXTURE0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_filter_coefficients(float sampling_rate, float cutoff_frequency) {
|
|
||||||
// The process below: the source texture will have bilinear filtering enabled; so by
|
|
||||||
// sampling at non-integral offsets from the centre the shader can get a weighted sum
|
|
||||||
// of two source pixels, then scale that once, to do two taps per sample. However
|
|
||||||
// that works only if the two coefficients being joined have the same sign. So the
|
|
||||||
// number of usable taps is between 11 and 21 depending on the values that come out.
|
|
||||||
// Perform a linear search for the highest number of taps we can use with 11 samples.
|
|
||||||
GLfloat weights[12];
|
|
||||||
GLfloat offsets[5];
|
|
||||||
unsigned int taps = 11;
|
|
||||||
// unsigned int taps = 21;
|
|
||||||
// while(1) {
|
|
||||||
// float coefficients[21];
|
|
||||||
SignalProcessing::FIRFilter luminance_filter(taps, sampling_rate, 0.0f, cutoff_frequency, SignalProcessing::FIRFilter::DefaultAttenuation);
|
|
||||||
std::vector<float> coefficients = luminance_filter.get_coefficients();
|
|
||||||
|
|
||||||
// int sample = 0;
|
|
||||||
// int c = 0;
|
|
||||||
std::memset(weights, 0, sizeof(float)*12);
|
|
||||||
std::memset(offsets, 0, sizeof(float)*5);
|
|
||||||
|
|
||||||
unsigned int half_size = (taps >> 1);
|
|
||||||
for(unsigned int c = 0; c < taps; c++) {
|
|
||||||
if(c < 5) offsets[c] = (half_size - c);
|
|
||||||
weights[c] = coefficients[c];
|
|
||||||
}
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// int halfSize = (taps >> 1);
|
|
||||||
// while(c < halfSize && sample < 5) {
|
|
||||||
// offsets[sample] = static_cast<float>(halfSize - c);
|
|
||||||
// if((coefficients[c] < 0.0f) == (coefficients[c+1] < 0.0f) && c+1 < (taps >> 1)) {
|
|
||||||
// weights[sample] = coefficients[c] + coefficients[c+1];
|
|
||||||
// offsets[sample] -= (coefficients[c+1] / weights[sample]);
|
|
||||||
// c += 2;
|
|
||||||
// } else {
|
|
||||||
// weights[sample] = coefficients[c];
|
|
||||||
// c++;
|
|
||||||
// }
|
|
||||||
// sample ++;
|
|
||||||
// }
|
|
||||||
// if(c == halfSize) { // i.e. we finished combining inputs before we ran out of space
|
|
||||||
// weights[sample] = coefficients[c];
|
|
||||||
// for(int c = 0; c < sample; c++) {
|
|
||||||
// weights[sample+c+1] = weights[sample-c-1];
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// taps -= 2;
|
|
||||||
// }
|
|
||||||
|
|
||||||
set_uniform("weights", 4, 3, weights);
|
|
||||||
set_uniform("offsets", 1, 5, offsets);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_separation_frequency(float sampling_rate, float colour_burst_frequency) {
|
|
||||||
set_filter_coefficients(sampling_rate, colour_burst_frequency);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_extension(float extension) {
|
|
||||||
set_uniform("extension", extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_colour_conversion_matrices(float *fromRGB, float *toRGB) {
|
|
||||||
set_uniform_matrix("lumaChromaToRGB", 3, false, toRGB);
|
|
||||||
set_uniform_matrix("rgbToLumaChroma", 3, false, fromRGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_width_scalers(float input_scaler, float output_scaler) {
|
|
||||||
set_uniform("widthScalers", input_scaler, output_scaler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntermediateShader::set_is_double_height(bool is_double_height, float input_offset, float output_offset) {
|
|
||||||
set_uniform("textureHeightDivisor", is_double_height ? 2.0f : 1.0f);
|
|
||||||
set_uniform("inputVerticalOffset", input_offset);
|
|
||||||
set_uniform("outputVerticalOffset", output_offset);
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
//
|
|
||||||
// IntermediateShader.hpp
|
|
||||||
// Clock Signal
|
|
||||||
//
|
|
||||||
// Created by Thomas Harte on 28/04/2016.
|
|
||||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef IntermediateShader_hpp
|
|
||||||
#define IntermediateShader_hpp
|
|
||||||
|
|
||||||
#include "Shader.hpp"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace OpenGL {
|
|
||||||
|
|
||||||
class IntermediateShader: public Shader {
|
|
||||||
public:
|
|
||||||
using Shader::Shader;
|
|
||||||
|
|
||||||
enum class Input {
|
|
||||||
/// Contains the 2d start position of this run's input data.
|
|
||||||
InputStart,
|
|
||||||
/// Contains the 2d start position of this run's output position.
|
|
||||||
OutputStart,
|
|
||||||
/// A 2d vector comprised of (the final x position for input, the final x position for output).
|
|
||||||
Ends,
|
|
||||||
/// A 3d vector recording the colour subcarrier's (phase, time, amplitude) at the start of this span of data.
|
|
||||||
PhaseTimeAndAmplitude
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Obtains the name of a designated input. Designated inputs are guaranteed to have the same attribute location
|
|
||||||
across multiple instances of IntermediateShader. So binding a vertex array to these inputs for any instance of
|
|
||||||
IntermediateShader allows that array to work with all instances of IntermediateShader.
|
|
||||||
|
|
||||||
@param input The input to query.
|
|
||||||
@returns The name used in this shader's source for the nominated input.
|
|
||||||
*/
|
|
||||||
static std::string get_input_name(Input input);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs and returns an intermediate shader that will take runs from the inputPositions,
|
|
||||||
converting them to single-channel composite values using @c composite_shader if non-empty
|
|
||||||
or a reference composite conversion of @c svideo_shader (first preference) or
|
|
||||||
@c rgb_shader (second preference) otherwise.
|
|
||||||
|
|
||||||
[input format] => one-channel composite.
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<IntermediateShader> make_composite_source_shader(const std::string &composite_shader, const std::string &svideo_shader, const std::string &rgb_shader);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs and returns an intermediate shader that will take runs from the inputPositions,
|
|
||||||
converting them to two-channel svideo values using @c svideo_shader if non-empty
|
|
||||||
or a reference svideo conversion of @c rgb_shader otherwise.
|
|
||||||
|
|
||||||
[input format] => three-channel Y, noisy (m, n).
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<IntermediateShader> make_svideo_source_shader(const std::string &svideo_shader, const std::string &rgb_shader);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs and returns an intermediate shader that will take runs from the inputPositions,
|
|
||||||
converting them to RGB values using @c rgb_shader.
|
|
||||||
|
|
||||||
[input format] => three-channel RGB.
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<IntermediateShader> make_rgb_source_shader(const std::string &rgb_shader);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs and returns an intermediate shader that will read composite samples from the R channel,
|
|
||||||
filter then to obtain luminance, stored to R, and to separate out unfiltered chrominance, store to G and B.
|
|
||||||
|
|
||||||
one-channel composite => three-channel Y, noisy (m, n).
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<IntermediateShader> make_chroma_luma_separation_shader();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs and returns an intermediate shader that will pass R through unchanged while filtering G and B.
|
|
||||||
|
|
||||||
three-channel Y, noisy (m, n) => three-channel RGB.
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<IntermediateShader> make_chroma_filter_shader();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs and returns an intermediate shader that will filter R, G and B.
|
|
||||||
|
|
||||||
three-channel RGB => frequency-limited three-channel RGB.
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<IntermediateShader> make_rgb_filter_shader();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues the configuration of this shader for output to an area of `output_width` and `output_height` pixels
|
|
||||||
to occur upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_output_size(unsigned int output_width, unsigned int output_height);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues setting the texture unit (as an enum, e.g. `GL_TEXTURE0`) for source data to occur upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_source_texture_unit(GLenum unit);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues setting filtering coefficients for a lowpass filter based on the cutoff frequency to occur upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_filter_coefficients(float sampling_rate, float cutoff_frequency);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues configuration of filtering to separate luminance and chrominance based on a colour
|
|
||||||
subcarrier of the given frequency to occur upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_separation_frequency(float sampling_rate, float colour_burst_frequency);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues setting of the number of colour phase cycles per sample, indicating whether output
|
|
||||||
geometry should be extended so that a complete colour cycle is included at both the beginning and end,
|
|
||||||
to occur upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_extension(float extension);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues setting the matrices that convert between RGB and chrominance/luminance to occur on the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_colour_conversion_matrices(float *fromRGB, float *toRGB);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the proportions of the input and output areas that should be considered the whole width: 1.0 means use all available
|
|
||||||
space, 0.5 means use half, etc.
|
|
||||||
*/
|
|
||||||
void set_width_scalers(float input_scaler, float output_scaler);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets source and target vertical offsets.
|
|
||||||
*/
|
|
||||||
void set_is_double_height(bool is_double_height, float input_offset = 0.0f, float output_offset = 0.0f);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::unique_ptr<IntermediateShader> make_shader(const std::string &fragment_shader, bool use_usampler, bool input_is_inputPosition);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* IntermediateShader_hpp */
|
|
@ -1,142 +0,0 @@
|
|||||||
//
|
|
||||||
// OutputShader.cpp
|
|
||||||
// Clock Signal
|
|
||||||
//
|
|
||||||
// Created by Thomas Harte on 27/04/2016.
|
|
||||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "OutputShader.hpp"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cmath>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using namespace OpenGL;
|
|
||||||
|
|
||||||
std::string OutputShader::get_input_name(Input input) {
|
|
||||||
switch(input) {
|
|
||||||
case Input::Horizontal: return "horizontal";
|
|
||||||
case Input::Vertical: return "vertical";
|
|
||||||
|
|
||||||
// Intended to be unreachable.
|
|
||||||
default: assert(false); return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<OutputShader> OutputShader::make_shader(const char *fragment_methods, const char *colour_expression, bool use_usampler) {
|
|
||||||
const std::string sampler_type = use_usampler ? "usampler2D" : "sampler2D";
|
|
||||||
|
|
||||||
std::ostringstream vertex_shader;
|
|
||||||
vertex_shader <<
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in vec2 " << get_input_name(Input::Horizontal) << ";"
|
|
||||||
"in vec2 " << get_input_name(Input::Vertical) << ";"
|
|
||||||
|
|
||||||
"uniform vec2 boundsOrigin;"
|
|
||||||
"uniform vec2 boundsSize;"
|
|
||||||
"uniform vec2 positionConversion;"
|
|
||||||
"uniform vec2 scanNormal;"
|
|
||||||
"uniform " << sampler_type << " texID;"
|
|
||||||
"uniform float inputScaler;"
|
|
||||||
"uniform int textureHeightDivisor;"
|
|
||||||
|
|
||||||
"out float lateralVarying;"
|
|
||||||
"out vec2 srcCoordinatesVarying;"
|
|
||||||
"out vec2 iSrcCoordinatesVarying;"
|
|
||||||
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"float lateral = float(gl_VertexID & 1);"
|
|
||||||
"float longitudinal = float((gl_VertexID & 2) >> 1);"
|
|
||||||
"float x = mix(horizontal.x, horizontal.y, longitudinal);"
|
|
||||||
|
|
||||||
"lateralVarying = lateral - 0.5;"
|
|
||||||
|
|
||||||
"vec2 vSrcCoordinates = vec2(x, vertical.y);"
|
|
||||||
"ivec2 textureSize = textureSize(texID, 0) * ivec2(1, textureHeightDivisor);"
|
|
||||||
"iSrcCoordinatesVarying = vSrcCoordinates;"
|
|
||||||
"srcCoordinatesVarying = vec2(inputScaler * vSrcCoordinates.x / textureSize.x, (vSrcCoordinates.y + 0.5) / textureSize.y);"
|
|
||||||
"srcCoordinatesVarying.x = srcCoordinatesVarying.x - mod(srcCoordinatesVarying.x, 1.0 / textureSize.x);"
|
|
||||||
|
|
||||||
"vec2 vPosition = vec2(x, vertical.x);"
|
|
||||||
"vec2 floatingPosition = (vPosition / positionConversion) + lateral * scanNormal;"
|
|
||||||
"vec2 mappedPosition = (floatingPosition - boundsOrigin) / boundsSize;"
|
|
||||||
"gl_Position = vec4(mappedPosition.x * 2.0 - 1.0, 1.0 - mappedPosition.y * 2.0, 0.0, 1.0);"
|
|
||||||
"}";
|
|
||||||
|
|
||||||
std::ostringstream fragment_shader;
|
|
||||||
fragment_shader <<
|
|
||||||
"#version 150\n"
|
|
||||||
|
|
||||||
"in float lateralVarying;"
|
|
||||||
"in vec2 srcCoordinatesVarying;"
|
|
||||||
"in vec2 iSrcCoordinatesVarying;"
|
|
||||||
|
|
||||||
"out vec4 fragColour;"
|
|
||||||
|
|
||||||
"uniform " << sampler_type << " texID;"
|
|
||||||
"uniform float gamma;"
|
|
||||||
|
|
||||||
<< fragment_methods <<
|
|
||||||
|
|
||||||
"void main(void)"
|
|
||||||
"{"
|
|
||||||
"fragColour = vec4(pow(" << colour_expression << ", vec3(gamma)), 0.64);"//*cos(lateralVarying)
|
|
||||||
"}";
|
|
||||||
|
|
||||||
return std::unique_ptr<OutputShader>(new OutputShader(vertex_shader.str(), fragment_shader.str(), {
|
|
||||||
{get_input_name(Input::Horizontal), 0},
|
|
||||||
{get_input_name(Input::Vertical), 1}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OutputShader::set_output_size(unsigned int output_width, unsigned int output_height, Outputs::Display::Rect visible_area) {
|
|
||||||
GLfloat outputAspectRatioMultiplier = (static_cast<float>(output_width) / static_cast<float>(output_height)) / (4.0f / 3.0f);
|
|
||||||
GLfloat bonusWidth = (outputAspectRatioMultiplier - 1.0f) * visible_area.size.width;
|
|
||||||
|
|
||||||
left_extent_ = (-1.0f / outputAspectRatioMultiplier) / visible_area.size.width;
|
|
||||||
right_extent_ = (1.0f / outputAspectRatioMultiplier) / visible_area.size.width;
|
|
||||||
|
|
||||||
visible_area.origin.x -= bonusWidth * 0.5f;
|
|
||||||
visible_area.size.width *= outputAspectRatioMultiplier;
|
|
||||||
|
|
||||||
set_uniform("boundsOrigin", (GLfloat)visible_area.origin.x, (GLfloat)visible_area.origin.y);
|
|
||||||
set_uniform("boundsSize", (GLfloat)visible_area.size.width, (GLfloat)visible_area.size.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
float OutputShader::get_left_extent() {
|
|
||||||
return left_extent_;
|
|
||||||
}
|
|
||||||
|
|
||||||
float OutputShader::get_right_extent() {
|
|
||||||
return right_extent_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OutputShader::set_source_texture_unit(GLenum unit) {
|
|
||||||
set_uniform("texID", (GLint)(unit - GL_TEXTURE0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OutputShader::set_timing(unsigned int height_of_display, unsigned int cycles_per_line, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider) {
|
|
||||||
GLfloat scan_angle = atan2f(1.0f / static_cast<float>(height_of_display), 1.0f);
|
|
||||||
GLfloat scan_normal[] = { -sinf(scan_angle), cosf(scan_angle)};
|
|
||||||
GLfloat multiplier = static_cast<float>(cycles_per_line) / (static_cast<float>(height_of_display) * static_cast<float>(horizontal_scan_period));
|
|
||||||
scan_normal[0] *= multiplier;
|
|
||||||
scan_normal[1] *= multiplier;
|
|
||||||
|
|
||||||
set_uniform("scanNormal", scan_normal[0], scan_normal[1]);
|
|
||||||
set_uniform("positionConversion", (GLfloat)horizontal_scan_period, (GLfloat)vertical_scan_period / (GLfloat)vertical_period_divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OutputShader::set_gamma_ratio(float ratio) {
|
|
||||||
set_uniform("gamma", ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OutputShader::set_input_width_scaler(float input_scaler) {
|
|
||||||
set_uniform("inputScaler", input_scaler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OutputShader::set_origin_is_double_height(bool is_double_height) {
|
|
||||||
set_uniform("textureHeightDivisor", is_double_height ? 2 : 1);
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
//
|
|
||||||
// OutputShader.hpp
|
|
||||||
// Clock Signal
|
|
||||||
//
|
|
||||||
// Created by Thomas Harte on 27/04/2016.
|
|
||||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef OutputShader_hpp
|
|
||||||
#define OutputShader_hpp
|
|
||||||
|
|
||||||
#include "Shader.hpp"
|
|
||||||
#include "../../ScanTarget.hpp"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace OpenGL {
|
|
||||||
|
|
||||||
class OutputShader: public Shader {
|
|
||||||
public:
|
|
||||||
enum class Input {
|
|
||||||
/// A 2d vector; the first element is the horizontal start of this scan, the second element is the end.
|
|
||||||
Horizontal,
|
|
||||||
/// A 2d vector; the first element is the vertical start of this scan, the second element is the end.
|
|
||||||
Vertical
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Obtains the name of a designated input. Designated inputs are guaranteed to have the same attribute location
|
|
||||||
across multiple instances of OutputShader. So binding a vertex array to these inputs for any instance of
|
|
||||||
OutputShader allows that array to work with all instances of OutputShader.
|
|
||||||
|
|
||||||
@param input The input to query.
|
|
||||||
@returns The name used in this shader's source for the nominated input.
|
|
||||||
*/
|
|
||||||
static std::string get_input_name(Input input);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Constructs and returns an instance of OutputShader. OutputShaders are intended to read source data
|
|
||||||
from a texture and draw a single raster scan containing that data as output.
|
|
||||||
|
|
||||||
Does not catch any of the exceptions potentially thrown by `Shader::Shader`.
|
|
||||||
|
|
||||||
All instances of OutputShader are guaranteed to use the same attribute locations for their inputs.
|
|
||||||
|
|
||||||
@param fragment_methods A block of code that will appear within the global area of the fragment shader.
|
|
||||||
|
|
||||||
@param colour_expression An expression that should evaluate to a `vec3` indicating the colour at the current location. The
|
|
||||||
decision should be a function of the uniform `texID`, which will be either a `usampler2D` or a `sampler2D` as per the
|
|
||||||
`use_usampler` parameter, and the inputs `srcCoordinatesVarying` which is a location within the texture from which to
|
|
||||||
take the source value, and `iSrcCoordinatesVarying` which is a value proportional to `srcCoordinatesVarying` but scaled
|
|
||||||
so that one unit equals one source sample.
|
|
||||||
|
|
||||||
@param use_usampler Dictates the type of the `texID` uniform; will be a `usampler2D` if this parameter is `true`, a
|
|
||||||
`sampler2D` otherwise.
|
|
||||||
|
|
||||||
@returns an instance of OutputShader.
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<OutputShader> make_shader(const char *fragment_methods, const char *colour_expression, bool use_usampler);
|
|
||||||
using Shader::Shader;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues configuration for output to an area of `output_width` and `output_height` pixels, ensuring
|
|
||||||
the largest possible drawing size that allows everything within `visible_area` to be visible, to
|
|
||||||
occur upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_output_size(unsigned int output_width, unsigned int output_height, Outputs::Display::Rect visible_area);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues setting of the texture unit (as an enum, e.g. `GL_TEXTURE0`) for source data upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_source_texture_unit(GLenum unit);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Queues configuring this shader's understanding of how to map from the source vertex stream to screen coordinates,
|
|
||||||
to occur upon the next `bind`.
|
|
||||||
*/
|
|
||||||
void set_timing(unsigned int height_of_display, unsigned int cycles_per_line, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
*/
|
|
||||||
void set_origin_is_double_height(bool is_double_height);
|
|
||||||
|
|
||||||
void set_gamma_ratio(float ratio);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the proportion of the input area that should be considered the whole width: 1.0 means use all available
|
|
||||||
space, 0.5 means use half, etc.
|
|
||||||
*/
|
|
||||||
void set_input_width_scaler(float input_scaler);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@returns The location, in eye coordinates, of the left edge of the output area.
|
|
||||||
*/
|
|
||||||
float get_left_extent();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@returns The location, in eye coordinates, of the right edge of the output area.
|
|
||||||
*/
|
|
||||||
float get_right_extent();
|
|
||||||
|
|
||||||
private:
|
|
||||||
float left_extent_ = 0.0f;
|
|
||||||
float right_extent_ = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OutputShader_hpp */
|
|
Loading…
Reference in New Issue
Block a user