From 7038b30381ca37f63e001a66ef2989ab19212641 Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Tue, 9 Dec 2025 23:51:39 +0100 Subject: [PATCH] Migrate all shaders to compiled qsb files. --- app/main.cpp | 13 +- app/qml/BurnInEffect.qml | 72 ++- app/qml/PreprocessedTerminal.qml | 2 +- app/qml/ShaderTerminal.qml | 631 +++++++------------------- app/qml/TerminalFrame.qml | 87 ++-- app/qml/resources.qrc | 6 + app/shaders/burn_in.frag | 63 +++ app/shaders/burn_in.frag.qsb | Bin 0 -> 3599 bytes app/shaders/passthrough.vert | 46 ++ app/shaders/passthrough.vert.qsb | Bin 0 -> 2521 bytes app/shaders/terminal_dynamic.frag | 163 +++++++ app/shaders/terminal_dynamic.frag.qsb | Bin 0 -> 9450 bytes app/shaders/terminal_dynamic.vert | 61 +++ app/shaders/terminal_dynamic.vert.qsb | Bin 0 -> 3618 bytes app/shaders/terminal_frame.frag | 77 ++++ app/shaders/terminal_frame.frag.qsb | Bin 0 -> 4757 bytes app/shaders/terminal_static.frag | 104 +++++ app/shaders/terminal_static.frag.qsb | Bin 0 -> 6371 bytes 18 files changed, 756 insertions(+), 569 deletions(-) create mode 100644 app/shaders/burn_in.frag create mode 100644 app/shaders/burn_in.frag.qsb create mode 100644 app/shaders/passthrough.vert create mode 100644 app/shaders/passthrough.vert.qsb create mode 100644 app/shaders/terminal_dynamic.frag create mode 100644 app/shaders/terminal_dynamic.frag.qsb create mode 100644 app/shaders/terminal_dynamic.vert create mode 100644 app/shaders/terminal_dynamic.vert.qsb create mode 100644 app/shaders/terminal_frame.frag create mode 100644 app/shaders/terminal_frame.frag.qsb create mode 100644 app/shaders/terminal_static.frag create mode 100644 app/shaders/terminal_static.frag.qsb diff --git a/app/main.cpp b/app/main.cpp index 347c0f4..d0f3ff2 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -31,16 +31,15 @@ QString getNamedArgument(QStringList args, QString name) int main(int argc, char *argv[]) { // Some environmental variable are necessary on certain platforms. - - // This disables QT appmenu under Ubuntu, which is not working with QML apps. - setenv("QT_QPA_PLATFORMTHEME", "", 1); - // Disable Connections slot warnings QLoggingCategory::setFilterRules("qt.qml.connections.warning=false"); -#if defined (Q_OS_LINUX) - setenv("QSG_RENDER_LOOP", "threaded", 0); -#endif + // TODO FILIPPO... This should not be hardcoded but handled as a fallback of sort! + QQuickStyle::setStyle("Material"); + +// #if defined (Q_OS_LINUX) +// setenv("QSG_RENDER_LOOP", "threaded", 0); +// #endif #if defined(Q_OS_MAC) // This allows UTF-8 characters usage in OSX. diff --git a/app/qml/BurnInEffect.qml b/app/qml/BurnInEffect.qml index 6016e25..464ca21 100644 --- a/app/qml/BurnInEffect.qml +++ b/app/qml/BurnInEffect.qml @@ -102,58 +102,50 @@ Loader { } } - ShaderLibrary { - id: shaderLibrary - } - ShaderEffect { id: burnInShaderEffect property variant txt_source: kterminalSource property variant burnInSource: burnInEffectSource property real burnInTime: burnInFadeTime - property real lastUpdate: burnInEffect.lastUpdate + property real burnInLastUpdate: burnInEffect.lastUpdate property real prevLastUpdate: burnInEffect.prevLastUpdate anchors.fill: parent blending: false - fragmentShader: - "#ifdef GL_ES - precision mediump float; - #endif\n" + + // Extra uniforms required by shared block + property real qt_Opacity: 1.0 + property real time: timeManager.time + property color fontColor: appSettings.fontColor + property color backgroundColor: appSettings.backgroundColor + property real shadowLength: 0 + property size virtualResolution: Qt.size(width, height) + property real rasterizationIntensity: 0 + property int rasterizationMode: 0 + property real burnIn: appSettings.burnIn + property real staticNoise: 0 + property real screenCurvature: 0 + property real glowingLine: 0 + property real chromaColor: 0 + property size jitterDisplacement: Qt.size(0, 0) + property real ambientLight: 0 + property real jitter: 0 + property real horizontalSync: 0 + property real horizontalSyncStrength: 0 + property real flickering: 0 + property real displayTerminalFrame: 0 + property size scaleNoiseSize: Qt.size(0, 0) + property real screen_brightness: 1.0 + property real bloom: 0 + property real rbgShift: 0 + property real screenShadowCoeff: 0 + property real frameShadowCoeff: 0 + property color frameColor: backgroundColor + property size margin: Qt.size(0, 0) - "uniform lowp float qt_Opacity;" + - "uniform lowp sampler2D txt_source;" + - - "varying highp vec2 qt_TexCoord0; - - uniform lowp sampler2D burnInSource; - uniform highp float burnInTime; - - uniform highp float lastUpdate; - - uniform highp float prevLastUpdate;" + - - shaderLibrary.rgb2grey + - - "void main() { - vec2 coords = qt_TexCoord0; - - vec3 txtColor = texture2D(txt_source, coords).rgb; - vec4 accColor = texture2D(burnInSource, coords); - - float prevMask = accColor.a; - float currMask = rgb2grey(txtColor); - - highp float blurDecay = clamp((lastUpdate - prevLastUpdate) * burnInTime, 0.0, 1.0); - blurDecay = max(0.0, blurDecay - prevMask); - vec3 blurColor = accColor.rgb - vec3(blurDecay); - vec3 color = max(blurColor, txtColor); - - gl_FragColor = vec4(color, currMask); - } - " + fragmentShader: "qrc:/shaders/burn_in.frag.qsb" + vertexShader: "qrc:/shaders/passthrough.vert.qsb" onStatusChanged: if (log) console.log(log) //Print warning messages } diff --git a/app/qml/PreprocessedTerminal.qml b/app/qml/PreprocessedTerminal.qml index 916ae5b..5c23e48 100644 --- a/app/qml/PreprocessedTerminal.qml +++ b/app/qml/PreprocessedTerminal.qml @@ -251,7 +251,7 @@ Item{ ShaderEffectSource{ id: kterminalSource sourceItem: kterminal - hideSource: true + hideSource: false wrapMode: ShaderEffectSource.Repeat visible: false textureSize: Qt.size(kterminal.totalWidth * scaleTexture, kterminal.totalHeight * scaleTexture) diff --git a/app/qml/ShaderTerminal.qml b/app/qml/ShaderTerminal.qml index d0ba4c9..73fb4dc 100644 --- a/app/qml/ShaderTerminal.qml +++ b/app/qml/ShaderTerminal.qml @@ -44,469 +44,174 @@ Item { screenResolution.height / virtualResolution.height ) - ShaderEffect { - id: dynamicShader - - property ShaderLibrary shaderLibrary: ShaderLibrary { } - - property ShaderEffectSource screenBuffer: frameBuffer - property ShaderEffectSource burnInSource: burnInEffect.source - property ShaderEffectSource frameSource: terminalFrameLoader.item - - property color fontColor: parent.fontColor - property color backgroundColor: parent.backgroundColor - property real screenCurvature: parent.screenCurvature - property real chromaColor: parent.chromaColor - property real ambientLight: parent.ambientLight - - property real flickering: appSettings.flickering - property real horizontalSync: appSettings.horizontalSync - property real horizontalSyncStrength: Utils.lint(0.05, 0.35, horizontalSync) - property real glowingLine: appSettings.glowingLine * 0.2 - - // Fast burnin properties - property real burnIn: appSettings.burnIn - property real burnInLastUpdate: burnInEffect.lastUpdate - property real burnInTime: burnInEffect.burnInFadeTime - - property real jitter: appSettings.jitter - property size jitterDisplacement: Qt.size(0.007 * jitter, 0.002 * jitter) - property real shadowLength: 0.25 * screenCurvature * Utils.lint(0.50, 1.5, ambientLight) - property real staticNoise: appSettings.staticNoise - property size scaleNoiseSize: Qt.size((width * 0.75) / (noiseTexture.width * appSettings.windowScaling * appSettings.totalFontScaling), - (height * 0.75) / (noiseTexture.height * appSettings.windowScaling * appSettings.totalFontScaling)) - - property size virtualResolution: parent.virtualResolution - - // Rasterization might display oversamping issues if virtual resolution is close to physical display resolution. - // We progressively disable rasterization from 4x up to 2x resolution. - property real rasterizationIntensity: Utils.smoothstep(2.0, 4.0, _screenDensity) - - property real displayTerminalFrame: appSettings._frameMargin > 0 || appSettings.screenCurvature > 0 - - property real time: timeManager.time - property ShaderEffectSource noiseSource: noiseShaderSource - - // If something goes wrong activate the fallback version of the shader. - property bool fallBack: false - - anchors.fill: parent - blending: false - - //Smooth random texture used for flickering effect. - Image { - id: noiseTexture - source: "images/allNoise512.png" - width: 512 - height: 512 - fillMode: Image.Tile - visible: false - } - ShaderEffectSource { - id: noiseShaderSource - sourceItem: noiseTexture - wrapMode: ShaderEffectSource.Repeat - visible: false - smooth: true - } - - //Print the number with a reasonable precision for the shader. - function str(num){ - return num.toFixed(8); - } - - vertexShader: " - uniform highp mat4 qt_Matrix; - uniform highp float time; - - attribute highp vec4 qt_Vertex; - attribute highp vec2 qt_MultiTexCoord0; - - varying highp vec2 qt_TexCoord0;" + - - (!fallBack ? " - uniform sampler2D noiseSource;" : "") + - - (!fallBack && flickering !== 0.0 ?" - varying lowp float brightness; - uniform lowp float flickering;" : "") + - - (!fallBack && horizontalSync !== 0.0 ?" - uniform lowp float horizontalSyncStrength; - varying lowp float distortionScale; - varying lowp float distortionFreq;" : "") + - - " - void main() { - qt_TexCoord0 = qt_MultiTexCoord0; - vec2 coords = vec2(fract(time/(1024.0*2.0)), fract(time/(1024.0*1024.0)));" + - - (!fallBack && (flickering !== 0.0 || horizontalSync !== 0.0) ? - "vec4 initialNoiseTexel = texture2D(noiseSource, coords);" - : "") + - - (!fallBack && flickering !== 0.0 ? " - brightness = 1.0 + (initialNoiseTexel.g - 0.5) * flickering;" - : "") + - - (!fallBack && horizontalSync !== 0.0 ? " - float randval = horizontalSyncStrength - initialNoiseTexel.r; - distortionScale = step(0.0, randval) * randval * horizontalSyncStrength; - distortionFreq = mix(4.0, 40.0, initialNoiseTexel.g);" - : "") + - - "gl_Position = qt_Matrix * qt_Vertex; - }" - - fragmentShader: " - #ifdef GL_ES - precision mediump float; - #endif - - uniform sampler2D screenBuffer; - uniform highp float qt_Opacity; - uniform highp float time; - varying highp vec2 qt_TexCoord0; - - uniform highp vec4 fontColor; - uniform highp vec4 backgroundColor; - uniform lowp float shadowLength; - - uniform highp vec2 virtualResolution; - uniform lowp float rasterizationIntensity;\n" + - - (burnIn !== 0 ? " - uniform sampler2D burnInSource; - uniform highp float burnInLastUpdate; - uniform highp float burnInTime;" : "") + - (staticNoise !== 0 ? " - uniform highp float staticNoise;" : "") + - (((staticNoise !== 0 || jitter !== 0) ||(fallBack && (flickering || horizontalSync))) ? " - uniform lowp sampler2D noiseSource; - uniform highp vec2 scaleNoiseSize;" : "") + - (displayTerminalFrame ? " - uniform lowp sampler2D frameSource;" : "") + - (screenCurvature !== 0 ? " - uniform highp float screenCurvature;" : "") + - (glowingLine !== 0 ? " - uniform highp float glowingLine;" : "") + - (chromaColor !== 0 ? " - uniform lowp float chromaColor;" : "") + - (jitter !== 0 ? " - uniform lowp vec2 jitterDisplacement;" : "") + - (ambientLight !== 0 ? " - uniform lowp float ambientLight;" : "") + - - (fallBack && horizontalSync !== 0 ? " - uniform lowp float horizontalSyncStrength;" : "") + - (fallBack && flickering !== 0.0 ?" - uniform lowp float flickering;" : "") + - (!fallBack && flickering !== 0 ? " - varying lowp float brightness;" - : "") + - (!fallBack && horizontalSync !== 0 ? " - varying lowp float distortionScale; - varying lowp float distortionFreq;" : "") + - - (glowingLine !== 0 ? " - float randomPass(vec2 coords){ - return fract(smoothstep(-120.0, 0.0, coords.y - (virtualResolution.y + 120.0) * fract(time * 0.00015))); - }" : "") + - - shaderLibrary.min2 + - shaderLibrary.rgb2grey + - shaderLibrary.rasterizationShader + - - " - float isInScreen(vec2 v) { - return min2(step(0.0, v) - step(1.0, v)); - } - - vec2 barrel(vec2 v, vec2 cc) {" + - - (screenCurvature !== 0 ? " - float distortion = dot(cc, cc) * screenCurvature; - return (v - cc * (1.0 + distortion) * distortion);" - : - "return v;") + - "}" + - - "vec3 convertWithChroma(vec3 inColor) { - vec3 outColor = inColor;" + - - (chromaColor !== 0 ? - "outColor = fontColor.rgb * mix(vec3(rgb2grey(inColor)), inColor, chromaColor);" - : - "outColor = fontColor.rgb * rgb2grey(inColor);") + - - " return outColor; - }" + - - "void main() {" + - "vec2 cc = vec2(0.5) - qt_TexCoord0;" + - "float distance = length(cc);" + - - //FallBack if there are problems - (fallBack && (flickering !== 0.0 || horizontalSync !== 0.0) ? - "vec2 initialCoords = vec2(fract(time/(1024.0*2.0)), fract(time/(1024.0*1024.0))); - vec4 initialNoiseTexel = texture2D(noiseSource, initialCoords);" - : "") + - (fallBack && flickering !== 0.0 ? " - float brightness = 1.0 + (initialNoiseTexel.g - 0.5) * flickering;" - : "") + - (fallBack && horizontalSync !== 0.0 ? " - float randval = horizontalSyncStrength - initialNoiseTexel.r; - float distortionScale = step(0.0, randval) * randval * horizontalSyncStrength; - float distortionFreq = mix(4.0, 40.0, initialNoiseTexel.g);" - : "") + - - (staticNoise ? " - float noise = staticNoise;" : "") + - - (screenCurvature !== 0 ? " - vec2 staticCoords = barrel(qt_TexCoord0, cc);" - :" - vec2 staticCoords = qt_TexCoord0;") + - - "vec2 coords = qt_TexCoord0;" + - - (horizontalSync !== 0 ? " - float dst = sin((coords.y + time * 0.001) * distortionFreq); - coords.x += dst * distortionScale;" + - - (staticNoise ? " - noise += distortionScale * 7.0;" : "") - - : "") + - - (jitter !== 0 || staticNoise !== 0 ? - "vec4 noiseTexel = texture2D(noiseSource, scaleNoiseSize * coords + vec2(fract(time / 51.0), fract(time / 237.0)));" - : "") + - - (jitter !== 0 ? " - vec2 offset = vec2(noiseTexel.b, noiseTexel.a) - vec2(0.5); - vec2 txt_coords = coords + offset * jitterDisplacement;" - : "vec2 txt_coords = coords;") + + ShaderEffect { + id: dynamicShader + + property ShaderEffectSource screenBuffer: frameBuffer + property ShaderEffectSource burnInSource: burnInEffect.source + property ShaderEffectSource frameSource: terminalFrameLoader.item + + property color fontColor: parent.fontColor + property color backgroundColor: parent.backgroundColor + property real screenCurvature: parent.screenCurvature + property real chromaColor: parent.chromaColor + property real ambientLight: parent.ambientLight + + property real flickering: appSettings.flickering + property real horizontalSync: appSettings.horizontalSync + property real horizontalSyncStrength: Utils.lint(0.05, 0.35, horizontalSync) + property real glowingLine: appSettings.glowingLine * 0.2 + + // Fast burnin properties + property real burnIn: appSettings.burnIn + property real burnInLastUpdate: burnInEffect.lastUpdate + property real burnInTime: burnInEffect.burnInFadeTime + + property real jitter: appSettings.jitter + property size jitterDisplacement: Qt.size(0.007 * jitter, 0.002 * jitter) + property real shadowLength: 0.25 * screenCurvature * Utils.lint(0.50, 1.5, ambientLight) + property real staticNoise: appSettings.staticNoise + property size scaleNoiseSize: Qt.size((width * 0.75) / (noiseTexture.width * appSettings.windowScaling * appSettings.totalFontScaling), + (height * 0.75) / (noiseTexture.height * appSettings.windowScaling * appSettings.totalFontScaling)) - "float color = 0.0001;" + + property size virtualResolution: parent.virtualResolution - (staticNoise !== 0 ? " - float noiseVal = noiseTexel.a; - color += noiseVal * noise * (1.0 - distance * 1.3);" : "") + - - (glowingLine !== 0 ? " - color += randomPass(coords * virtualResolution) * glowingLine;" : "") + - - "vec3 txt_color = texture2D(screenBuffer, txt_coords).rgb;" + - - (burnIn !== 0 ? " - vec4 txt_blur = texture2D(burnInSource, staticCoords); - float blurDecay = clamp((time - burnInLastUpdate) * burnInTime, 0.0, 1.0); - vec3 burnInColor = 0.65 * (txt_blur.rgb - vec3(blurDecay)); - txt_color = max(txt_color, convertWithChroma(burnInColor));" - : "") + - - "txt_color += fontColor.rgb * vec3(color);" + - - "txt_color = applyRasterization(staticCoords, txt_color, virtualResolution, rasterizationIntensity);\n" + - - "vec3 finalColor = txt_color;" + - - (flickering !== 0 ? " - finalColor *= brightness;" : "") + - - (ambientLight !== 0 ? " - finalColor += vec3(ambientLight) * (1.0 - distance) * (1.0 - distance);" : "") + - - (displayTerminalFrame ? - "vec4 frameColor = texture2D(frameSource, qt_TexCoord0); - finalColor = mix(finalColor, frameColor.rgb, frameColor.a);" - : "") + - - "gl_FragColor = vec4(finalColor, qt_Opacity);" + - "}" - - onStatusChanged: { - // Print warning messages - if (log) - console.log(log); - - // Activate fallback mode - if (status == ShaderEffect.Error) { - fallBack = true; - } - } - } - - Loader { - id: terminalFrameLoader - - active: dynamicShader.displayTerminalFrame - - width: staticShader.width - height: staticShader.height - - sourceComponent: ShaderEffectSource { - - sourceItem: terminalFrame - hideSource: true - visible: false - format: ShaderEffectSource.RGBA - - TerminalFrame { - id: terminalFrame - blending: false - anchors.fill: parent - } - } - } - - ShaderLibrary { - id: shaderLibrary - } - - ShaderEffect { - id: staticShader - - width: parent.width * appSettings.windowScaling - height: parent.height * appSettings.windowScaling - - property ShaderEffectSource source: parent.source - property ShaderEffectSource bloomSource: parent.bloomSource - - property color fontColor: parent.fontColor - property color backgroundColor: parent.backgroundColor - property real bloom: bloomSource ? appSettings.bloom * 2.5 : 0 - - property real screenCurvature: parent.screenCurvature - - property real chromaColor: appSettings.chromaColor; - - property real rbgShift: (appSettings.rbgShift / width) * appSettings.totalFontScaling // TODO FILIPPO width here is wrong. - - property int rasterization: appSettings.rasterization - - property real screen_brightness: Utils.lint(0.5, 1.5, appSettings.brightness) - - property real ambientLight: parent.ambientLight - - property size virtualResolution: parent.virtualResolution - - blending: false - visible: false - - //Print the number with a reasonable precision for the shader. - function str(num){ - return num.toFixed(8); - } - - fragmentShader: " - #ifdef GL_ES - precision mediump float; - #endif - - uniform sampler2D source; - uniform highp float qt_Opacity; - varying highp vec2 qt_TexCoord0; - - uniform highp vec4 fontColor; - uniform highp vec4 backgroundColor; - uniform lowp float screen_brightness; - - uniform highp vec2 virtualResolution;" + - - (bloom !== 0 ? " - uniform highp sampler2D bloomSource; - uniform lowp float bloom;" : "") + - - (screenCurvature !== 0 ? " - uniform highp float screenCurvature;" : "") + - - (chromaColor !== 0 ? " - uniform lowp float chromaColor;" : "") + - - (rbgShift !== 0 ? " - uniform lowp float rbgShift;" : "") + - - (ambientLight !== 0 ? " - uniform lowp float ambientLight;" : "") + - - shaderLibrary.min2 + - shaderLibrary.sum2 + - shaderLibrary.rgb2grey + - - "vec3 convertWithChroma(vec3 inColor) { - vec3 outColor = inColor;" + - - (chromaColor !== 0 ? - "outColor = fontColor.rgb * mix(vec3(rgb2grey(inColor)), inColor, chromaColor);" - : - "outColor = fontColor.rgb * rgb2grey(inColor);") + - - " return outColor; - }" + - - shaderLibrary.rasterizationShader + - - "void main() {" + - "vec2 cc = vec2(0.5) - qt_TexCoord0;" + - - (screenCurvature !== 0 ? " - float distortion = dot(cc, cc) * screenCurvature; - vec2 curvatureCoords = (qt_TexCoord0 - cc * (1.0 + distortion) * distortion); - vec2 txt_coords = - 2.0 * curvatureCoords + 3.0 * step(vec2(0.0), curvatureCoords) * curvatureCoords - 3.0 * step(vec2(1.0), curvatureCoords) * curvatureCoords;" - :" - vec2 txt_coords = qt_TexCoord0;") + - - "vec3 txt_color = texture2D(source, txt_coords).rgb;" + - - (rbgShift !== 0 ? " - vec2 displacement = vec2(12.0, 0.0) * rbgShift; - vec3 rightColor = texture2D(source, txt_coords + displacement).rgb; - vec3 leftColor = texture2D(source, txt_coords - displacement).rgb; - txt_color.r = leftColor.r * 0.10 + rightColor.r * 0.30 + txt_color.r * 0.60; - txt_color.g = leftColor.g * 0.20 + rightColor.g * 0.20 + txt_color.g * 0.60; - txt_color.b = leftColor.b * 0.30 + rightColor.b * 0.10 + txt_color.b * 0.60; - " : "") + - - "txt_color += vec3(0.0001);" + - "float greyscale_color = rgb2grey(txt_color);" + - - (screenCurvature !== 0 ? " - float reflectionMask = sum2(step(vec2(0.0), curvatureCoords) - step(vec2(1.0), curvatureCoords)); - reflectionMask = clamp(reflectionMask, 0.0, 1.0);" - : - "float reflectionMask = 1.0;") + - - (chromaColor !== 0 ? - "vec3 foregroundColor = mix(fontColor.rgb, txt_color * fontColor.rgb / greyscale_color, chromaColor); - vec3 finalColor = mix(backgroundColor.rgb, foregroundColor, greyscale_color * reflectionMask);" - : - "vec3 finalColor = mix(backgroundColor.rgb, fontColor.rgb, greyscale_color * reflectionMask);") + - - (bloom !== 0 ? - "vec4 bloomFullColor = texture2D(bloomSource, txt_coords); - vec3 bloomColor = bloomFullColor.rgb; - float bloomAlpha = bloomFullColor.a; - bloomColor = convertWithChroma(bloomColor); - finalColor += clamp(bloomColor * bloom * bloomAlpha, 0.0, 0.5);" - : "") + - - "finalColor *= screen_brightness;" + - - "gl_FragColor = vec4(finalColor, qt_Opacity);" + - "}" - - onStatusChanged: { - // Print warning messages - if (log) console.log(log); - } - } - - ShaderEffectSource { - id: frameBuffer - visible: false - sourceItem: staticShader - hideSource: true - } + // Rasterization might display oversamping issues if virtual resolution is close to physical display resolution. + // We progressively disable rasterization from 4x up to 2x resolution. + property real rasterizationIntensity: Utils.smoothstep(2.0, 4.0, _screenDensity) + property int rasterizationMode: appSettings.rasterization + + property real displayTerminalFrame: appSettings._frameMargin > 0 || appSettings.screenCurvature > 0 + + property real time: timeManager.time + property ShaderEffectSource noiseSource: noiseShaderSource + + // Extra uniforms expected by the shared uniform block + property real screenShadowCoeff: 0 + property real frameShadowCoeff: 0 + property color frameColor: backgroundColor + property size margin: Qt.size(0, 0) + property real prevLastUpdate: burnInEffect.prevLastUpdate + property real screen_brightness: Utils.lint(0.5, 1.5, appSettings.brightness) + property real bloom: appSettings.bloom + property real rbgShift: (appSettings.rbgShift / Math.max(width, 1)) * appSettings.totalFontScaling + + anchors.fill: parent + blending: false + + Image { + id: noiseTexture + source: "images/allNoise512.png" + width: 512 + height: 512 + fillMode: Image.Tile + visible: false + } + ShaderEffectSource { + id: noiseShaderSource + sourceItem: noiseTexture + wrapMode: ShaderEffectSource.Repeat + visible: false + smooth: true + } + + vertexShader: "qrc:/shaders/terminal_dynamic.vert.qsb" + fragmentShader: "qrc:/shaders/terminal_dynamic.frag.qsb" + + onStatusChanged: if (log) console.log(log) + } + + Loader { + id: terminalFrameLoader + + active: dynamicShader.displayTerminalFrame + + width: staticShader.width + height: staticShader.height + + sourceComponent: ShaderEffectSource { + + sourceItem: terminalFrame + hideSource: true + visible: false + format: ShaderEffectSource.RGBA + + TerminalFrame { + id: terminalFrame + blending: false + anchors.fill: parent + } + } + } + + ShaderLibrary { + id: shaderLibrary + } + + ShaderEffect { + id: staticShader + + width: parent.width * appSettings.windowScaling + height: parent.height * appSettings.windowScaling + + property ShaderEffectSource source: parent.source + property ShaderEffectSource bloomSource: parent.bloomSource + + property color fontColor: parent.fontColor + property color backgroundColor: parent.backgroundColor + property real bloom: bloomSource ? appSettings.bloom * 2.5 : 0 + + property real screenCurvature: parent.screenCurvature + + property real chromaColor: appSettings.chromaColor; + + property real rbgShift: (appSettings.rbgShift / width) * appSettings.totalFontScaling + + property int rasterization: appSettings.rasterization + + property real screen_brightness: Utils.lint(0.5, 1.5, appSettings.brightness) + + property real ambientLight: parent.ambientLight + + property size virtualResolution: parent.virtualResolution + + // Extra uniforms to match shared uniform block + property real time: timeManager.time + property real shadowLength: 0 + property real rasterizationIntensity: Utils.smoothstep(2.0, 4.0, _screenDensity) + property int rasterizationMode: appSettings.rasterization + property real burnInLastUpdate: burnInEffect.lastUpdate + property real burnInTime: burnInEffect.burnInFadeTime + property real burnIn: appSettings.burnIn + property real staticNoise: appSettings.staticNoise + property real glowingLine: appSettings.glowingLine * 0.2 + property size jitterDisplacement: Qt.size(0, 0) + property real jitter: appSettings.jitter + property real horizontalSync: appSettings.horizontalSync + property real horizontalSyncStrength: Utils.lint(0.05, 0.35, horizontalSync) + property real flickering: appSettings.flickering + property real displayTerminalFrame: dynamicShader.displayTerminalFrame + property size scaleNoiseSize: Qt.size((width * 0.75) / (512 * appSettings.windowScaling * appSettings.totalFontScaling), + (height * 0.75) / (512 * appSettings.windowScaling * appSettings.totalFontScaling)) + property real screenShadowCoeff: 0 + property real frameShadowCoeff: 0 + property color frameColor: backgroundColor + property size margin: Qt.size(0, 0) + property real prevLastUpdate: burnInEffect.prevLastUpdate + + blending: false + visible: false + + vertexShader: "qrc:/shaders/passthrough.vert.qsb" + fragmentShader: "qrc:/shaders/terminal_static.frag.qsb" + + onStatusChanged: if (log) console.log(log) + } + + ShaderEffectSource { + id: frameBuffer + visible: false + sourceItem: staticShader + hideSource: true + } } diff --git a/app/qml/TerminalFrame.qml b/app/qml/TerminalFrame.qml index 3e1baef..ea169c4 100644 --- a/app/qml/TerminalFrame.qml +++ b/app/qml/TerminalFrame.qml @@ -40,65 +40,36 @@ ShaderEffect { appSettings.frameMargin / height * appSettings.windowScaling ) - ShaderLibrary { - id: shaderLibrary - } + // Uniforms required by the shared block + property real qt_Opacity: 1.0 + property real time: timeManager.time + property color fontColor: appSettings.fontColor + property color backgroundColor: appSettings.backgroundColor + property real shadowLength: 0 + property size virtualResolution: Qt.size(width, height) + property real rasterizationIntensity: 0 + property int rasterizationMode: 0 + property real burnInLastUpdate: 0 + property real burnInTime: 0 + property real burnIn: 0 + property real staticNoise: 0 + property real glowingLine: 0 + property real chromaColor: 0 + property size jitterDisplacement: Qt.size(0, 0) + property real ambientLight: _ambientLight + property real jitter: 0 + property real horizontalSync: 0 + property real horizontalSyncStrength: 0 + property real flickering: 0 + property real displayTerminalFrame: 0 + property size scaleNoiseSize: Qt.size(0, 0) + property real screen_brightness: 1.0 + property real bloom: 0 + property real rbgShift: 0 + property real prevLastUpdate: 0 - fragmentShader: " - #ifdef GL_ES - precision mediump float; - #endif - - uniform lowp float screenCurvature; - uniform lowp float screenShadowCoeff; - uniform lowp float frameShadowCoeff; - uniform highp float qt_Opacity; - uniform lowp vec4 frameColor; - uniform mediump vec2 margin; - - varying highp vec2 qt_TexCoord0; - - vec2 distortCoordinates(vec2 coords){ - vec2 cc = (coords - vec2(0.5)); - float dist = dot(cc, cc) * screenCurvature; - return (coords + cc * (1.0 + dist) * dist); - } - " + - - shaderLibrary.max2 + - shaderLibrary.min2 + - shaderLibrary.prod2 + - shaderLibrary.sum2 + - - " - - vec2 positiveLog(vec2 x) { - return clamp(log(x), vec2(0.0), vec2(100.0)); - } - - void main() { - vec2 staticCoords = qt_TexCoord0; - vec2 coords = distortCoordinates(staticCoords) * (vec2(1.0) + margin * 2.0) - margin; - - vec2 vignetteCoords = staticCoords * (1.0 - staticCoords.yx); - float vignette = pow(prod2(vignetteCoords) * 15.0, 0.25); - - vec3 color = frameColor.rgb * vec3(1.0 - vignette); - float alpha = 0.0; - - float frameShadow = max2(positiveLog(-coords * frameShadowCoeff + vec2(1.0)) + positiveLog(coords * frameShadowCoeff - (vec2(frameShadowCoeff) - vec2(1.0)))); - frameShadow = max(sqrt(frameShadow), 0.0); - color *= frameShadow; - alpha = sum2(1.0 - step(vec2(0.0), coords) + step(vec2(1.0), coords)); - alpha = clamp(alpha, 0.0, 1.0); - alpha *= mix(1.0, 0.9, frameShadow); - - float screenShadow = 1.0 - prod2(positiveLog(coords * screenShadowCoeff + vec2(1.0)) * positiveLog(-coords * screenShadowCoeff + vec2(screenShadowCoeff + 1.0))); - alpha = max(0.8 * screenShadow, alpha); - - gl_FragColor = vec4(color * alpha, alpha); - } - " + vertexShader: "qrc:/shaders/passthrough.vert.qsb" + fragmentShader: "qrc:/shaders/terminal_frame.frag.qsb" onStatusChanged: if (log) console.log(log) //Print warning messages } diff --git a/app/qml/resources.qrc b/app/qml/resources.qrc index 1114d8d..b5009de 100644 --- a/app/qml/resources.qrc +++ b/app/qml/resources.qrc @@ -46,5 +46,11 @@ menus/ShortContextMenu.qml ShaderLibrary.qml menus/OSXMenu.qml + ../shaders/terminal_dynamic.vert.qsb + ../shaders/terminal_dynamic.frag.qsb + ../shaders/passthrough.vert.qsb + ../shaders/terminal_static.frag.qsb + ../shaders/terminal_frame.frag.qsb + ../shaders/burn_in.frag.qsb diff --git a/app/shaders/burn_in.frag b/app/shaders/burn_in.frag new file mode 100644 index 0000000..4868fb8 --- /dev/null +++ b/app/shaders/burn_in.frag @@ -0,0 +1,63 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform ubuf { + mat4 qt_Matrix; + float qt_Opacity; + float time; + vec4 fontColor; + vec4 backgroundColor; + float shadowLength; + vec2 virtualResolution; + float rasterizationIntensity; + int rasterizationMode; + float burnInLastUpdate; + float burnInTime; + float burnIn; + float staticNoise; + float screenCurvature; + float glowingLine; + float chromaColor; + vec2 jitterDisplacement; + float ambientLight; + float jitter; + float horizontalSync; + float horizontalSyncStrength; + float flickering; + float displayTerminalFrame; + vec2 scaleNoiseSize; + float screen_brightness; + float bloom; + float rbgShift; + float screenShadowCoeff; + float frameShadowCoeff; + vec4 frameColor; + vec2 margin; + float prevLastUpdate; +}; + +layout(binding = 1) uniform sampler2D txt_source; +layout(binding = 2) uniform sampler2D burnInSource; + +float rgb2grey(vec3 v) { + return dot(v, vec3(0.21, 0.72, 0.04)); +} + +void main() { + vec2 coords = qt_TexCoord0; + + vec3 txtColor = texture(txt_source, coords).rgb; + vec4 accColor = texture(burnInSource, coords); + + float prevMask = accColor.a; + float currMask = rgb2grey(txtColor); + + float blurDecay = clamp((burnInLastUpdate - prevLastUpdate) * burnInTime, 0.0, 1.0); + blurDecay = max(0.0, blurDecay - prevMask); + vec3 blurColor = accColor.rgb - vec3(blurDecay); + vec3 color = max(blurColor, txtColor); + + fragColor = vec4(color, currMask) * qt_Opacity; +} diff --git a/app/shaders/burn_in.frag.qsb b/app/shaders/burn_in.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..8d51dbf820edac16a635e7a9cbef90bb0a14cdb3 GIT binary patch literal 3599 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 V{WR{2cQ&`oV<~+8{1>fbXjAi1A3gv8 literal 0 HcmV?d00001 diff --git a/app/shaders/passthrough.vert b/app/shaders/passthrough.vert new file mode 100644 index 0000000..bfebde5 --- /dev/null +++ b/app/shaders/passthrough.vert @@ -0,0 +1,46 @@ +#version 440 + +layout(location = 0) in vec4 qt_Vertex; +layout(location = 1) in vec2 qt_MultiTexCoord0; + +layout(std140, binding = 0) uniform ubuf { + mat4 qt_Matrix; + float qt_Opacity; + float time; + vec4 fontColor; + vec4 backgroundColor; + float shadowLength; + vec2 virtualResolution; + float rasterizationIntensity; + int rasterizationMode; + float burnInLastUpdate; + float burnInTime; + float burnIn; + float staticNoise; + float screenCurvature; + float glowingLine; + float chromaColor; + vec2 jitterDisplacement; + float ambientLight; + float jitter; + float horizontalSync; + float horizontalSyncStrength; + float flickering; + float displayTerminalFrame; + vec2 scaleNoiseSize; + float screen_brightness; + float bloom; + float rbgShift; + float screenShadowCoeff; + float frameShadowCoeff; + vec4 frameColor; + vec2 margin; + float prevLastUpdate; +}; + +layout(location = 0) out vec2 qt_TexCoord0; + +void main() { + qt_TexCoord0 = qt_MultiTexCoord0; + gl_Position = qt_Matrix * qt_Vertex; +} diff --git a/app/shaders/passthrough.vert.qsb b/app/shaders/passthrough.vert.qsb new file mode 100644 index 0000000000000000000000000000000000000000..2574f37d9a635a6d34cd21c89f7c44b925fe85d9 GIT binary patch literal 2521 zcmV;~2`2Uc05WTMob6jZY#hfG9+F3jJdzekQ4(!Y@|p?^G7*^LiF6z@6cmtgB7-yu z9W4YPg!A6r-f_jf-ShtNM+N~GE?l^903&eW!lg?WE?l@U3>Pk4xNzaZU0Rn;5hQPB z-tN7f*<~UnfRp%EIPvzI@BPf1H{a~)hcPz7 z@XKcnRzhaq-|=D@*A%+B2gW{p<1QF0@S(HJ`rtEzrg?Gyse@riy#}8qd>;ZwWwrtX zV}xap47ZpGKYf@e&u|nOw+VY9{xXdw+pGgdbubCp2?o6#PfxvuMG@OD8A;s8BThlW z9&>@t=j@1COX?0yf?n5Po;;BQ)&jBzb9SLns`;yV<})l{`{1Af;gu?*7mj;I39CP>xz zjr@G_oo&JI4N?6k;PYml3q!PwkI^^L-78RohHw@y-&=VOrc(}fQ)~Wqp3zv!NRr>l zBVQ6J$(hyJ%P=n+kT}M>d1lvuREHRrsOY+gcPQLM0+r_P&)Dq! ze6u?A5pT*i#G)<9%|6I8`x$#6mRzpnhL~XoOnH}EqN2PtWN&@Qa(Zh9=xwO1jdY%J z3$h6@`bT-u$5PQH`QtqDEO_*=-Q>RITcHBo>O!*8_>(;28)q6^e0NhX-eU@i54~^Ze?un3FAIip!c`h%CJ=N{uFY@ca`-_`cq$w+6YTTGF)t4-1 zspeA6S%pROlf`m{sstGStGxI{Fml8x(MIamdDIE;UIXtH@NYxW;)eJp&mf&%g{UR( zXbW64(Z#oUE)1Z=l|0MAcXzh~oH`1_*AbnB$#COQINbTq-)~kn7lW{|xV*w25kTe# zk^txN*@g#cn>Me6K=?6#fpKjFdl((T?+oup@m}}`f0Io1@gLZr_|91OQ6a|q5bGmY zKVk#u=W^nwAinc!5c%;vOjxWb#p1cgSRZ1y3D%F;2Ehgp+aXv1u~!K;h**bULx>#{ z>>Ofm5NsH+HwiX^*jofEBK9`HMiG05U}K2AOR#ao-Xqu(h`mp+^N4*wunELIB-kWk z9}#Q{v5yIM0kKaAHjUV)1iOgXX9T;1*cSx5jM$e1n?dX=f<1}Y*93bCv2O@=1+i}l zHjCJI1iOmZ_XN9!7;mN+dm6FfKDiHg9?vj&#rJdM{u=Ae7q>rOU8?=yT`b{ar9RZYfun9VPHPL!29#apN0Dg zf7P2}UxU`_b=b5P5E))jM( z{{RTrl{H-VFw{iA4aBg*9tr*3L#r+%MFs8Y*!iI@){O3 zu0=lBYy#z#PQwf{#&(klQ8blw2(Ifddv=f_26f-E-1W#mG{eYG4YeHa$aY(swwr?M z`@YvU)8#4~59|=~->`#@W7e&<<%ZP8Y}agnHtp7a3YS(C+4rCbupFjSIdSXxBbCr6 z^_PsMW7iL$h;ECb4UyByuI0CF*K}U=O|tf7D1hl$qAV5rVMb}HHJ@kgT0xL1u;Y2{ z)B@L9m3_Mz>K-bhUDiFT*-T~26Vb+GKk^~9!fn%U*{LP%_|_q9iqq9%F>>vu=eNb? zFskJhfDTRn1ZpC^z<$`Zj@LcUZyNkC5mdJ^y- zkN~I&jLbV;-NgO5v|yZ}3p&3P^M7=)_?(Evvx!(N_nsGeV$lxv1s-jnl!E;&)RKyhWuPC`J*qXMfCW{ZX z2-%XS7(Tzy)j-XN>!8X{mq|`tkw?u$&#kMP8u=)PtPp>#SG23JDmNo(MR+v}J!hiF z8e31A$h5*lS(@*@uH}sn@A{XsGP6#?3lP zG^_M{%DC9{kkL)_32BFqYIIX?Q+_0Aw2bn`N0rXa%Yz(Kx=}_=m7`6ySn=If=>t;%|2`S7!TIa9TX!Nje}B`q zKvv;&YdCi8R 0.0) { + vec4 txt_blur = texture(burnInSource, staticCoords); + float blurDecay = clamp((time - burnInLastUpdate) * burnInTime, 0.0, 1.0); + vec3 burnInColor = 0.65 * (txt_blur.rgb - vec3(blurDecay)); + txt_color = max(txt_color, convertWithChroma(burnInColor)); + } + + txt_color += fontColor.rgb * vec3(color); + txt_color = applyRasterization(staticCoords, txt_color, virtualResolution, rasterizationIntensity, rasterizationMode); + + vec3 finalColor = txt_color; + float brightness = mix(1.0, vBrightness, step(0.0, flickering)); + finalColor *= brightness; + + finalColor += vec3(ambientLight) * (1.0 - distance) * (1.0 - distance); + + if (displayTerminalFrame > 0.0) { + vec4 frameColor = texture(frameSource, qt_TexCoord0); + finalColor = mix(finalColor, frameColor.rgb, frameColor.a); + } + + fragColor = vec4(finalColor, qt_Opacity); +} diff --git a/app/shaders/terminal_dynamic.frag.qsb b/app/shaders/terminal_dynamic.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..a75b41f2692ab4bd96ca59550f4e5921dbce8d6f GIT binary patch literal 9450 zcmaKwbx<5Yv*58nkO0AhEe^q57nk4=AUKN#cPF?*&>+FxgS$g;ch|)icZX$PzE^kk z>aObUpI`M%_jFHpPu0{69NdktXXcp!YG&rQUoa4T2s;faB@!?ojN$&T*`W=q1Om;+ zNMzJBIFtV3k`nLP!V>Spb2)P=h6n~mit^zf;JVF|7!*dT@={M$#*@aDliKq(rl_i& zk**)#?tJe$FJ6B9po=U&S$gd%H0=EItysrngPU<4J*MZyhFg(xM#cEDaiJ zjc7sIlEe81VvU5uLbGJeI&pNZEL4jU&96%)EKtDDKg#)kYkJEpxAO_Y-j<@t4zprA zQD%xJ8@P&dem;R5>y$S?&3_y7F$kfXo`4*guMWE~*CSh2En+K&YCjX$U{R=7B88zXX$O# z-zEp9WgjVknkewMP9CnC>IwzpyI2}kvvywa)9k3lW*UY0zil5$Pj0S}>pitB(du&1 z2$PPuItHXtw-~{>A(1S{^Go)kr)N%a4F`47kqao2{+J63adaoK^X3v*SZ=>lyK@@8 zyDIpX3vcEC0_<`?ZPVnXLi%5T7x?s1--rw>vZ|J=aujZF)S(r!V*1RSK$Kt+C^Tg+ z+J)yX#cV>n*e6~Od6SxX)%rQZ>Zhdzs&0^F29n*!nI^PVlY9d@OO%gx^3%Vu?PR7g z=~fqlnvyK1a2q5e+&gpcu+Naig_11!&{sM0H>fPfBJa_}g`zF1KQ{D5-v3htSvuf0 zP)FW_#P!4*u+Ub&O1(tnR?@7J1-Wz2oZ~folWNzSj-^}`4svIn>0-2uqgwS1y0^^V zV6%*)T=jT&Rx9N#HXTd78XV*foS{ffbw`-_%^0yXFj;;3fJ^r3_(bzHEL9Yg)U59H zF_|sTIcW6z{u0XfvI`cCYAKz??v!KPeC88>`Lo*B1f**=obMx8E=gyi@-|ATZ>*fJ zs9a%D<3QQ;T0Pqxf7By|W6u7!p4-gQv2azW+K!>}KGGFHremzkhd((bl}Ojtgh%dP z68bAP1xtBeS4;JY-5T)?ne2<&OB|g+c-pmivBN)GqN@rzG75jj$Ns>Wh)F|X!fJ?f zwV$7R&t;mvh_t9MShurEB?Xh$nPE=BZ9Ij}uxeg-5}V9+3O8%aLKUEMZVT05Y;HZX zo1RKJ-`H8bF@x?o3pBrdE`Hl|)9)f$$QjsIP`o?F6iayk2MZiC(NexKYCQJ*FvWc$gF*=CTj<~GTMG= z*9V)Xc%z~;x7C{bIofZo>(?z#4Vsi6$fupcdQ)|jc_qEFu7~b54J<2K?p?P4MQybG zqVnFzw4*5u4sV9Vj#WW1akDGm74s@Oad)pxU8R1z8b_a!l%VBS7CEO`u0v2mPjD_T zXmXed@A)ub1WP4$>e=hV*Hd4K0Qy~;+q$E#Y)H^%f4fx3OjHt|LjX)B)J7!5u$*11 zw$q{Z)VICY7jdb3=}))8_FM26K&$1!$Xle6Vky&yZplB`XMEp*aXe-#&Y#kslyVSK zGMYpGCb|7QwQtBUKBVs_wG9e5Gmv;uN(AE`MunG>k1|E@mYQN}dktYVg!AlE?7RcS z#Glz%u?Q$6<@ptS+cZm_svXT>@m2ZwJz^k#pnGYjd-IQfBSWwX*!JkfTj4F30G6fs zbo2YoLFW!;w%|WB3-kRN#_=3T3p0&^ftkIrcc#-c#zbDCEQ4D&JBIsG8)8u3sf>*cYZoTb74H$$cu*@{Lgy`mo*2H0&>|G4-5I`K*g}RN z#9u7q>oQ?!yY?IfWFjHX+>)8HdmPOW80AwNd(WZ8I4%x3(RqKT^|`PoF_(12<3y%(H;5Hg(h-IV#qvl)tk zDYd#(`)8xd9N2K|)^p=0-Pfhu*BLxP`SFuizV#BVDetqpzqatQPbuKfPSW|qpM6Jr z7-GZsX=a#z;LJPON4o(|Md{(s+JA($eS3Uxu)^@d0EzoPHVzk5(+I}(l;e$dCb;$r zA~bxozTrWeYON;d@*+F(t*p7bLpxf};bTbh?cDMzSjge~T-Ygo3sD-)m~;5nLT|k0 zpx%P%tOz5!S~uTuEz@D!ERM&-^4Y3J+Q-nw1=BrWVIB{yg~nWH$ih+&0$mo`@n&ZS zCM_9e0dVo9Iose`}S80c5P#gF#+YzH9 z{1w9@o9$N)_|((yiF0O!&G4)2i*tx!m%K|D^qMD>+pmhcy}L?vX-P^H_UqaA!_|68 z{Jono%$G{$qJ$_^aQR|`&DA%^FJ9f8B|B_0*SVCLkn54#HYIs=6hk_ZB z{I!RniwQ4eBT&s@C@AmrLJIsQ=DVv6Es$8fkOsdoJR>I}J>N%I>e0qewhH|cBZiz0 zpt5;LZcsttJ{++4K-PU75vF2E#}sf|JpK)25xfF0n|gHi<3pBGvXSmXA+LF;z^Thj z!{1`7d8n{V2z11GC*>uv4@VZ_Bm@lP_WS+ooEit@6G%3_xQ#j$u8Q^a^QBXJ*%xnR zLIflyA|kn0P=G7j9Wdze4Pk$)ufa5;80kzqAO1vhBfZr^E*E$y37s*c&m7A;$I|Vq z@k5qFf$6_HCk^8UWKtW8VnDSIJfWTlGY*ukBKbXScV8yZzb~S{4kc{j7ZOg^e~IMP zM0=jOB^$KD_YJ=}<1jSG~L~WA0&5qiq>Mn!`V2H6E2jNaaF+M&h6AG%Tr2onNmOPhR#K6Z?c)mT=z-5 zGqH^yP;S|&A2X9O*5Nn1boo67@1`E;1wF&I!XG3dsvC597jlJh56BQ4a3X2j0|oJo zL+z?)oTbXgGtmWc+W^4i97KJ?O9HG}4n>b}U~246v&=O7LYC>Ezj?j|+~pb#?MJ-* z?h0}KwVM^r=GsxeJy&{eG9;99PVqcf2DOuNxga3TjJkf?=ghx(YL`8`QW^L3C2?`| zWlA`=z>e{SH+nSxiaZZxo>3m?@tX3>rXUv0TzazLfELy(c1)W`9=FCYKIM$12&F2t zOc-EJGTGP5aQn4P$jz81-@>ttqm%~o+w*Vwz$xlYhSSY#VIbbX`vo8XQn6G~MBTlp zkE~F=J%rvo*Cn|H0OpyOPwWbA-XUF`v7+QT(mviJ{&P~MZ{-#DIZFTZ*}EZA;pJuL zD-vKH&6g?KE}K#)Q{>*UozA3CXn2oU^FxYMAA^r1&i-fZjU zJ9)D?JF;wFN0p7AfyIDq1lN53HueMcYD}mr!$5E{qua@GbDen)B=77@-Zfq{CyYAM z6}{T^%kuO@k4&Gi^|cwZDx(6+Z^^NMXh;hu1`rF?5&)fo<$r+W?7A}ll|oDC?FqR% z(X-X^-%G~-Ulx|Hjv3X2c3tWJsRdtYu-CQBP=FZyg;I?ML z*u22(W;H`2tV?B%MSq6@;#d1!VJVb1kB<|bOOCI#&+sS@ADLm|J5O*U-Eo${gJz+Y zsrcIKkNNeYqQ_gHQ0N24&UQFtbExdR0CN&OcVpZ0VHrRuD6&n_G=_EZNVBj(>3QLb z{jd-Du>9XV)k@O1( zrx!-X-2rHB*)$I&b8E3ECsk+wn`q-ktUa8mI*S@_b#$LPl#HTVBCitY{$<8@4sCw| znvAv|i{nnJNB25JAUnXjSy#fed^~m73e!bNYfnN?31yu)odShGUQgMJbtpx8O`d|F?*beO+~^xSE!`p z&Oyw$`??n*77QHmlSf@c#vjD#-=P?wQuKZ{;Kmyyd!Uz(({20V(Yo@7_jp86aD!`s zIpt4rL%m?F3!_dM&(E_)c<08dNa0F%m$rFj%p z#OYt*`)^8q7Fm01s;w=IaQ^m4QFt;d`s(0dJ5Q`6PQvutU5T4y?#}6J@N8w)z|~+j z%l@;JcL~!krSmG@wYh=SCg<|68TK{>MT+&y)+reaozkVt`VJ{4EK777O#V=>n5#NG z@(g?HG?w)J-m)tbp+fuiHA=a=PaBJW6jbaq^h5?V%XC}oP2-oJ63>Ty-YfE%< zmend>hKsT$2F+$Js%)>Xt@YNr%U09>;4AEpaAG9Ut7npyTh9^*M~Dc@%Z*Nkxd)NQ zn%KEEfqqtfvf~Sd{VGr^|Ltx?zerExw!X~W-npJxu^83pk}l10uX7e)Qfa%+sk=e4 zlisV1TTzvw$C49l6Ej%o5HLh1o!lPE8djiYHSn^Y9S)!^ophAYoX0cxrEGybd%%@6!;_ZR z^DA)s)=?ypd>n$}oOUW!{U$p`KUjx5am~D(rEuP)hAeO@tRPxcA$FI-Aa@ZV4{GL&E3~LFJs<@1Pg(md4G|9 zN=%Ekx`Q(fp=nQ0>9En@3qgj=cNMWu3g3I71`AY>WBuIDpPOU17954hb*UEbt#K!0&q_?)ERA=eRb zz`Z&j5JhPr5n`jD}5|9cZ z=CWCBqe6L5MS@VfR0%w3@gkbz!AQ}7 zu|~}mV%txsE1;B94kYT{@m@qC+`ty>59Fo8HTj5o>m`o?apk8;Zs#7N;e^u5G{`tN z_fxl{v$hd&L6k;#Bg2el&wE>uhe3FUODjszt&9j?52VxCR)gSa3s{#<%CEWFptc%} zmChu^Eblf0K<~dGyGS0vcb0y@!ZhbP`bEm@XEO^GBu0@5bMrBCWydtHKTl|-TdO9t z?99YGah%vksY`ox1S#l%91HR|bg~&tGFIk|xi;; zUYl))Q9X7}kGS()lm)WVi8#Ak6ZZ10ot+YXnBsv7HJly+w4vqH~_gOn=Y2wb^?1%F@&;L>O;>7LZ>k1fz9WC*mm3dL{7Czs7Xn=W@jwpPPPK z`Ppt2QRmX}P95!_xcyx~e8UtPY06XH>#(XHMWO=MUf7rGBOd}toE+U7HEEi-u0=x0 zacRh+GAii-F!;t3v|(@Fl6K^HI%+Q;X=)45fr!rAG`c3t9%R7RVF{PeqEL*!Ae7|I zC9JH+R~;qC+DtW|SKS;&-77Hee_HPLz)}IcM}C+l>Y%Ir^TSt*rJ;oQXb3M)MZT5t zOf3t7g6!HvK8$&Q9M0L-x6g9~@BTR=K(vU*dtI{J1ATrhTs>>EBLYbKDGkLNk(Tj<1RAkL?h%tf5PHs#cL5n%{gorj1tq z=-0{xQ+(|Rdgk#P8m#yhJ%GlYJq`K(>GVSO-u7yz_Op$xnNOQJjxkvA;SbB7o0c+> zmy9%B?AT|DQ<8y$<3{F2{E1V=;a|pQ?Q_(}iS{TAJ(WCxvk!>_X-RtL=mHjrtgyHB zIk*DAk5rz6l)V*=5N&d`_{+}s7-mEP;=3{kJHb9d=bl1Q9g^chOW#@Qu)^!SJ(_1d zC`+u4$x9C4-#CX2!yd_sfzZdH#L1?3qtN+GaSGDn*YI*AT#o*C1uxJG;T zw|t5AW=48QMZ8KyKS@R3kGP5<0{_F`Hqu=Zj;@dY3r%q*KGcJJ|4+OzUdHIX>vC!j zcfja>l!H1n3E>4n89B3V~fStSjO^&&MW5XTFD{de4pD>pW@&DW55pCCh zhyA}GYU4vK!}s<)9fKHS*FP-7DZ^`Gw#$aM@|d_we15irK>6X$4Bl$}M1r_gAH%9Y zUgkdtBf=MMi#c-tv&evtnl=q-Ac90V#r`)6ecSPONjWAz{-5Z{`5%-2kwiaEI;DiW z0If#{1g@{jN&b7;O`pJf6r%FQp>2ROC;MO0-|am=Q|>TyqT_NHXth@v8EQ~w8M(F6V3ivM4X=Wr1q!YrOD!Ur-h zGiFoeY&`pX+BSU@H7MQHOsyW&lpNydqEb%o$4em=*Tu;}=+l-Q8>_7AVkPoc;6J?; zX7K|VSl8)_=1#5NLJe@AHb(56utF|%FXL!Ah#Dk>ljV9MPq29rEAu4_f z2_-aU!MS*QaC(0)n2);~X^_k$#&0yE;2yFW?4w+0`fE3{|C(cRt+(A_MuaT05ZuFg zM{HkT&rfB`g-5$Os^G_?amg1m=~3XC4QV1o8t}0P)&62^N=W2VGH+wE} zeg&KXd2gJA+-nlRJ=A^s8sLC^QJG3@N{e*$!QKzp-`pGTFuJzp7Wt@|PhqGYjpSR~ zM186kIq1ve0@sairABnGfKTwOFt7TWa?Fg>#LkA)f-M!mbPq4HI*tFHlwI5+r;Gw_ zU6hN9n%!uPv@{zRo^DNIvI?)%4=;83=pY%gDni|pjEL~A9!yI_>UQ!C-oY*E(#;Ane|t-wn_O`NLpnq$HB6#6SGT`_NR4_9 z{-e7jE%qe(K=4_O(do6=I~iF=qeK*LAOhu1UN1TZ&Li`C+$z@(XkU<1X7_X zQOI;)ed<{_mW*K95bK|*7bZzP}vtH%G0wqs(k4}>&fsuM?D?LPQ~-37Php>@3D+<>MnAgUS@^x#w4}L9wOCt3w!$8|Weo*`5T}wuxDE4x{Y? z9D`_KI-Qin!}}tp?cNGW=IG-G+~b!F^VUO{^{&OUohcwRQu$N%Ry7J z0pUcmVqDu#855KFL3|_=HVF+z6R5i%&~z%7wo1rDC2A|@dY4_>^%)A)23E6oY|8_Z zJ39$PmNr+I35Sdgm#o!2RFE53lk9T^a`8@56O?&vmSNi`88;WLNU&ZZxn=qA*f*~( z>^5ve_AvZgsq;NwID&^e-`OV*T8to!v!tl03H;$3iO&!Jz8r3lKTCo&it>&hs~E4w zVRj3l7;3{#46ZoO#*@>5g&F;qNOTm_6n!H&*mvJ-o=0F`*ha(h3Rp3m;6TwBJzq8= zeT_g-7}B!s-efaAJd z2%<;QS8j(Lj0?yOD(H{oyjO+!`F9`r+;^fU(P~x(YcFeKwAopFX;S5n^9Ue zkvLb*EDK@Xp!RNxdHcG)u5L3Dw0!pz>ifQ^rjP8$BIamXHywseXVHc3J{y|mfxbVs zo7Cw7R8l+{Gt(v;@-3z#f~z>_&qe%98H8d*-`&G> ze+*&zJpab@5vlZwt!a?_-EL}JSl87^An(i zd-h=bnLjj;ms)$}hZm}*do*$I*1#Xwj z794k>cB0uPGX(9pfgg6_R(FrTyJC^>ID7;e)`KX3tW<}vh4#g)tEMbYV)&9V#J-neS+Q5g58s(Ko060yIh|0ssI2 literal 0 HcmV?d00001 diff --git a/app/shaders/terminal_dynamic.vert b/app/shaders/terminal_dynamic.vert new file mode 100644 index 0000000..8b11375 --- /dev/null +++ b/app/shaders/terminal_dynamic.vert @@ -0,0 +1,61 @@ +#version 440 + +layout(location = 0) in vec4 qt_Vertex; +layout(location = 1) in vec2 qt_MultiTexCoord0; + +layout(std140, binding = 0) uniform ubuf { + mat4 qt_Matrix; + float qt_Opacity; + float time; + vec4 fontColor; + vec4 backgroundColor; + float shadowLength; + vec2 virtualResolution; + float rasterizationIntensity; + int rasterizationMode; + float burnInLastUpdate; + float burnInTime; + float burnIn; + float staticNoise; + float screenCurvature; + float glowingLine; + float chromaColor; + vec2 jitterDisplacement; + float ambientLight; + float jitter; + float horizontalSync; + float horizontalSyncStrength; + float flickering; + float displayTerminalFrame; + vec2 scaleNoiseSize; + float screen_brightness; + float bloom; + float rbgShift; + float screenShadowCoeff; + float frameShadowCoeff; + vec4 frameColor; + vec2 margin; + float prevLastUpdate; +}; + +layout(binding = 0) uniform sampler2D noiseSource; + +layout(location = 0) out vec2 qt_TexCoord0; +layout(location = 1) out float vBrightness; +layout(location = 2) out float vDistortionScale; +layout(location = 3) out float vDistortionFreq; + +void main() { + qt_TexCoord0 = qt_MultiTexCoord0; + + vec2 coords = vec2(fract(time / 2048.0), fract(time / 1048576.0)); + vec4 initialNoiseTexel = texture(noiseSource, coords); + + vBrightness = 1.0 + (initialNoiseTexel.g - 0.5) * flickering; + + float randval = horizontalSyncStrength - initialNoiseTexel.r; + vDistortionScale = step(0.0, randval) * randval * horizontalSyncStrength * horizontalSync; + vDistortionFreq = mix(4.0, 40.0, initialNoiseTexel.g) * step(0.0, horizontalSync); + + gl_Position = qt_Matrix * qt_Vertex; +} diff --git a/app/shaders/terminal_dynamic.vert.qsb b/app/shaders/terminal_dynamic.vert.qsb new file mode 100644 index 0000000000000000000000000000000000000000..2ef25082b0c3e82027ad4cd14c0f94375df4f6c3 GIT binary patch literal 3618 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 literal 0 HcmV?d00001 diff --git a/app/shaders/terminal_frame.frag b/app/shaders/terminal_frame.frag new file mode 100644 index 0000000..01b4627 --- /dev/null +++ b/app/shaders/terminal_frame.frag @@ -0,0 +1,77 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform ubuf { + mat4 qt_Matrix; + float qt_Opacity; + float time; + vec4 fontColor; + vec4 backgroundColor; + float shadowLength; + vec2 virtualResolution; + float rasterizationIntensity; + int rasterizationMode; + float burnInLastUpdate; + float burnInTime; + float burnIn; + float staticNoise; + float screenCurvature; + float glowingLine; + float chromaColor; + vec2 jitterDisplacement; + float ambientLight; + float jitter; + float horizontalSync; + float horizontalSyncStrength; + float flickering; + float displayTerminalFrame; + vec2 scaleNoiseSize; + float screen_brightness; + float bloom; + float rbgShift; + float screenShadowCoeff; + float frameShadowCoeff; + vec4 frameColor; + vec2 margin; + float prevLastUpdate; +}; + +float min2(vec2 v) { return min(v.x, v.y); } +float max2(vec2 v) { return max(v.x, v.y); } +float prod2(vec2 v) { return v.x * v.y; } +float sum2(vec2 v) { return v.x + v.y; } + +vec2 distortCoordinates(vec2 coords){ + vec2 cc = (coords - vec2(0.5)); + float dist = dot(cc, cc) * screenCurvature; + return (coords + cc * (1.0 + dist) * dist); +} + +vec2 positiveLog(vec2 x) { + return clamp(log(x), vec2(0.0), vec2(100.0)); +} + +void main() { + vec2 staticCoords = qt_TexCoord0; + vec2 coords = distortCoordinates(staticCoords) * (vec2(1.0) + margin * 2.0) - margin; + + vec2 vignetteCoords = staticCoords * (1.0 - staticCoords.yx); + float vignette = pow(prod2(vignetteCoords) * 15.0, 0.25); + + vec3 color = frameColor.rgb * vec3(1.0 - vignette); + float alpha = 0.0; + + float frameShadow = max2(positiveLog(-coords * frameShadowCoeff + vec2(1.0)) + positiveLog(coords * frameShadowCoeff - (vec2(frameShadowCoeff) - vec2(1.0)))); + frameShadow = max(sqrt(frameShadow), 0.0); + color *= frameShadow; + alpha = sum2(1.0 - step(vec2(0.0), coords) + step(vec2(1.0), coords)); + alpha = clamp(alpha, 0.0, 1.0); + alpha *= mix(1.0, 0.9, frameShadow); + + float screenShadow = 1.0 - prod2(positiveLog(coords * screenShadowCoeff + vec2(1.0)) * positiveLog(-coords * screenShadowCoeff + vec2(screenShadowCoeff + 1.0))); + alpha = max(0.8 * screenShadow, alpha); + + fragColor = vec4(color * alpha, alpha) * qt_Opacity; +} diff --git a/app/shaders/terminal_frame.frag.qsb b/app/shaders/terminal_frame.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..dfcec5376a272db7bb523974537b4c0683688b92 GIT binary patch literal 4757 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 literal 0 HcmV?d00001 diff --git a/app/shaders/terminal_static.frag b/app/shaders/terminal_static.frag new file mode 100644 index 0000000..6729d38 --- /dev/null +++ b/app/shaders/terminal_static.frag @@ -0,0 +1,104 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform ubuf { + mat4 qt_Matrix; + float qt_Opacity; + float time; + vec4 fontColor; + vec4 backgroundColor; + float shadowLength; + vec2 virtualResolution; + float rasterizationIntensity; + int rasterizationMode; + float burnInLastUpdate; + float burnInTime; + float burnIn; + float staticNoise; + float screenCurvature; + float glowingLine; + float chromaColor; + vec2 jitterDisplacement; + float ambientLight; + float jitter; + float horizontalSync; + float horizontalSyncStrength; + float flickering; + float displayTerminalFrame; + vec2 scaleNoiseSize; + float screen_brightness; + float bloom; + float rbgShift; + float screenShadowCoeff; + float frameShadowCoeff; + vec4 frameColor; + vec2 margin; + float prevLastUpdate; +}; + +layout(binding = 1) uniform sampler2D source; +layout(binding = 2) uniform sampler2D bloomSource; + +float sum2(vec2 v) { return v.x + v.y; } +float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); } + +vec3 convertWithChroma(vec3 inColor) { + vec3 outColor = fontColor.rgb * rgb2grey(inColor); + if (chromaColor != 0.0) { + outColor = fontColor.rgb * mix(vec3(rgb2grey(inColor)), inColor, chromaColor); + } + return outColor; +} + +void main() { + vec2 cc = vec2(0.5) - qt_TexCoord0; + + vec2 txt_coords = qt_TexCoord0; + if (screenCurvature != 0.0) { + float distortion = dot(cc, cc) * screenCurvature; + vec2 curvatureCoords = (qt_TexCoord0 - cc * (1.0 + distortion) * distortion); + txt_coords = -2.0 * curvatureCoords + 3.0 * step(vec2(0.0), curvatureCoords) * curvatureCoords - 3.0 * step(vec2(1.0), curvatureCoords) * curvatureCoords; + } + + vec3 txt_color = texture(source, txt_coords).rgb; + + if (rbgShift != 0.0) { + vec2 displacement = vec2(12.0, 0.0) * rbgShift; + vec3 rightColor = texture(source, txt_coords + displacement).rgb; + vec3 leftColor = texture(source, txt_coords - displacement).rgb; + txt_color.r = leftColor.r * 0.10 + rightColor.r * 0.30 + txt_color.r * 0.60; + txt_color.g = leftColor.g * 0.20 + rightColor.g * 0.20 + txt_color.g * 0.60; + txt_color.b = leftColor.b * 0.30 + rightColor.b * 0.10 + txt_color.b * 0.60; + } + + txt_color += vec3(0.0001); + float greyscale_color = rgb2grey(txt_color); + + float reflectionMask = 1.0; + if (screenCurvature != 0.0) { + float distortion = dot(cc, cc) * screenCurvature; + vec2 curvatureCoords = (qt_TexCoord0 - cc * (1.0 + distortion) * distortion); + reflectionMask = sum2(step(vec2(0.0), curvatureCoords) - step(vec2(1.0), curvatureCoords)); + reflectionMask = clamp(reflectionMask, 0.0, 1.0); + } + + vec3 finalColor; + if (chromaColor != 0.0) { + vec3 foregroundColor = mix(fontColor.rgb, txt_color * fontColor.rgb / greyscale_color, chromaColor); + finalColor = mix(backgroundColor.rgb, foregroundColor, greyscale_color * reflectionMask); + } else { + finalColor = mix(backgroundColor.rgb, fontColor.rgb, greyscale_color * reflectionMask); + } + + if (bloom != 0.0) { + vec4 bloomFullColor = texture(bloomSource, txt_coords); + vec3 bloomColor = convertWithChroma(bloomFullColor.rgb); + float bloomAlpha = bloomFullColor.a; + finalColor += clamp(bloomColor * bloom * bloomAlpha, 0.0, 0.5); + } + + finalColor *= screen_brightness; + fragColor = vec4(finalColor, qt_Opacity); +} diff --git a/app/shaders/terminal_static.frag.qsb b/app/shaders/terminal_static.frag.qsb new file mode 100644 index 0000000000000000000000000000000000000000..3bc2be55352163e2a409d3b948384662a2967102 GIT binary patch literal 6371 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 V@r;MWyoBoUz!se3{%ecR{{g!1#&-Y! literal 0 HcmV?d00001