cool-retro-term/app/qml/ShaderTerminal.qml
2018-12-02 19:57:24 +01:00

504 lines
18 KiB
QML

/*******************************************************************************
* Copyright (c) 2013 "Filippo Scognamiglio"
* https://github.com/Swordfish90/cool-retro-term
*
* This file is part of cool-retro-term.
*
* cool-retro-term is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
import QtQuick 2.2
import QtGraphicalEffects 1.0
import "utils.js" as Utils
ShaderEffect {
property ShaderEffectSource source
property BurnInEffect burnInEffect
property ShaderEffectSource bloomSource
property ShaderEffectSource screenBuffer: frameBuffer
property color fontColor: appSettings.fontColor
property color backgroundColor: appSettings.backgroundColor
property real bloom: appSettings.bloom * 2.5
property ShaderEffectSource burnInSource: burnInEffect.source
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 staticNoise: appSettings.staticNoise
property size scaleNoiseSize: Qt.size((width) / (noiseTexture.width * appSettings.windowScaling * appSettings.totalFontScaling),
(height) / (noiseTexture.height * appSettings.windowScaling * appSettings.totalFontScaling))
property real screenCurvature: appSettings.screenCurvature * appSettings.screenCurvatureSize
property real glowingLine: appSettings.glowingLine * 0.2
property real chromaColor: appSettings.chromaColor;
property real rbgShift: (appSettings.rbgShift / width) * appSettings.totalFontScaling
property real flickering: appSettings.flickering
property real horizontalSync: appSettings.horizontalSync * 0.5
property int rasterization: appSettings.rasterization
property real screen_brightness: Utils.lint(0.5, 1.5, appSettings.brightness)
property real ambientLight: appSettings.ambientLight * 0.2
property real shadowLength: 0.25 * screenCurvature * Utils.lint(0.50, 1.5, ambientLight)
property size virtual_resolution
property real time: timeManager.time
property ShaderEffectSource noiseSource: noiseShaderSource
// If something goes wrong activate the fallback version of the shader.
property bool fallBack: false
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 && rbgShift !== 0.0 ?"
varying lowp vec4 constantNoise;" : "") +
(!fallBack && flickering !== 0.0 ?"
varying lowp float brightness;
uniform lowp float flickering;" : "") +
(!fallBack && horizontalSync !== 0.0 ?"
uniform lowp float horizontalSync;
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 || rbgShift !== 0) ?
"vec4 initialNoiseTexel = texture2D(noiseSource, coords);"
: "") +
(!fallBack && rbgShift !== 0.0 ?"
constantNoise = initialNoiseTexel;" : "") +
(!fallBack && flickering !== 0.0 ? "
brightness = 1.0 + (initialNoiseTexel.g - 0.5) * flickering;"
: "") +
(!fallBack && horizontalSync !== 0.0 ? "
float randval = horizontalSync - initialNoiseTexel.r;
distortionScale = step(0.0, randval) * randval * horizontalSync;
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 screen_brightness;
uniform lowp float shadowLength;
uniform highp vec2 virtual_resolution;" +
(burnIn !== 0 ? "
uniform sampler2D burnInSource;
uniform highp float burnInLastUpdate;
uniform highp float burnInTime;" : "") +
(staticNoise !== 0 ? "
uniform highp float staticNoise;" : "") +
(((staticNoise !== 0 || jitter !== 0 || rbgShift)
||(fallBack && (flickering || horizontalSync))) ? "
uniform lowp sampler2D noiseSource;
uniform highp vec2 scaleNoiseSize;" : "") +
(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 horizontalSync;" : "") +
(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;" : "") +
(!fallBack && rbgShift !== 0.0 ?"
varying lowp vec4 constantNoise;" : "") +
(glowingLine !== 0 ? "
float randomPass(vec2 coords){
return fract(smoothstep(-120.0, 0.0, coords.y - (virtual_resolution.y + 120.0) * fract(time * 0.00015)));
}" : "") +
"float min2(vec2 v) {
return min(v.x, v.y);
}
float rgb2grey(vec3 v){
return dot(v, vec3(0.21, 0.72, 0.04));
}
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 || rbgShift !== 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 = horizontalSync - initialNoiseTexel.r;
float distortionScale = step(0.0, randval) * randval * horizontalSync;
float distortionFreq = mix(4.0, 40.0, initialNoiseTexel.g);"
: "") +
(fallBack && rbgShift !== 0.0 ?"
lowp vec4 constantNoise = initialNoiseTexel;" : "") +
(staticNoise ? "
float noise = staticNoise;" : "") +
(screenCurvature !== 0 ? "
vec2 curvatureCoords = barrel(qt_TexCoord0, cc);
float staticInScreen = min2(step(0.0, curvatureCoords) - step(1.0, curvatureCoords));
vec2 staticCoords = curvatureCoords;"
:"
vec2 staticCoords = qt_TexCoord0;
float staticInScreen = 1.0;") +
"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 || rbgShift !== 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;") +
"float color = 0.0001;" +
(staticNoise !== 0 ? "
float noiseVal = noiseTexel.a;
color += noiseVal * noise * (1.0 - distance * 1.3);" : "") +
(glowingLine !== 0 ? "
color += randomPass(coords * virtual_resolution) * glowingLine;" : "") +
"txt_coords = mix(qt_TexCoord0, txt_coords, staticInScreen);
float inScreen2 = isInScreen(barrel(txt_coords, cc));
vec3 origTxtColor = texture2D(screenBuffer, txt_coords).rgb;
vec3 txt_color = origTxtColor * inScreen2 + backgroundColor.rgb * (1.0 - inScreen2);" +
(burnIn !== 0 ? "
vec4 txt_blur = texture2D(burnInSource, staticCoords);
float blurDecay = clamp((time - burnInLastUpdate) * burnInTime, 0.0, 1.0);
vec3 burnInColor = 0.5 * (txt_blur.rgb - vec3(blurDecay));
txt_color = max(txt_color, convertWithChroma(burnInColor));"
: "") +
"txt_color += fontColor.rgb * vec3(color);" +
"vec3 finalColor = txt_color;" +
(flickering !== 0 ? "
finalColor *= brightness;" : "") +
(ambientLight !== 0 ? "
finalColor += vec3(ambientLight) * (1.0 - distance) * (1.0 - distance);" : "") +
"float inShadow = 1.0 - min2(smoothstep(0.0, shadowLength, staticCoords) - smoothstep(1.0 - shadowLength, 1.0, staticCoords));
finalColor = mix(finalColor, vec3(0.0), 0.35 * inShadow);
finalColor = mix(origTxtColor, finalColor, staticInScreen);
gl_FragColor = vec4(finalColor * screen_brightness, qt_Opacity);" +
"}"
onStatusChanged: {
// Print warning messages
if (log)
console.log(log);
// Activate fallback mode
if (status == ShaderEffect.Error) {
fallBack = true;
}
}
ShaderEffect {
id: frame
anchors.fill: parent
property ShaderEffectSource source: parent.source
property ShaderEffectSource bloomSource: parent.bloomSource
property color fontColor: parent.fontColor
property color backgroundColor: parent.backgroundColor
property real bloom: parent.bloom
property real screenCurvature: appSettings.screenCurvature * appSettings.screenCurvatureSize
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: appSettings.ambientLight * 0.2
property size virtual_resolution: parent.virtual_resolution
blending: 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 virtual_resolution;" +
(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;" : "") +
"highp float getScanlineIntensity(vec2 coords) {
float result = 1.0;" +
(appSettings.rasterization != appSettings.no_rasterization ?
"float val = 0.0;
vec2 rasterizationCoords = fract(coords * virtual_resolution);
val += smoothstep(0.0, 0.5, rasterizationCoords.y);
val -= smoothstep(0.5, 1.0, rasterizationCoords.y);
result *= mix(0.5, 1.0, val);" : "") +
(appSettings.rasterization == appSettings.pixel_rasterization ?
"val = 0.0;
val += smoothstep(0.0, 0.5, rasterizationCoords.x);
val -= smoothstep(0.5, 1.0, rasterizationCoords.x);
result *= mix(0.5, 1.0, val);" : "") + "
return result;
}
float min2(vec2 v) {
return min(v.x, v.y);
}
float rgb2grey(vec3 v){
return dot(v, vec3(0.21, 0.72, 0.04));
}" +
"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;" +
(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 *= getScanlineIntensity(txt_coords);" +
"txt_color += vec3(0.0001);" +
"float greyscale_color = rgb2grey(txt_color);" +
(chromaColor !== 0 ?
"vec3 foregroundColor = mix(fontColor.rgb, txt_color * fontColor.rgb / greyscale_color, chromaColor);
vec3 finalColor = mix(backgroundColor.rgb, foregroundColor, greyscale_color);"
:
"vec3 finalColor = mix(backgroundColor.rgb, fontColor.rgb, greyscale_color);") +
(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);"
: "") +
(screenCurvature !== 0 ? "
vec2 curvatureMask = step(vec2(0.0), curvatureCoords) - step(vec2(1.0), curvatureCoords);
finalColor *= clamp(0.0, 1.0, curvatureMask.x + curvatureMask.y);"
:"") +
"gl_FragColor = vec4(finalColor * screen_brightness, qt_Opacity);" +
"}"
NewTerminalFrame {
anchors.fill: parent
blending: true
}
}
ShaderEffectSource {
id: frameBuffer
anchors.fill: parent
visible: false
sourceItem: frame
hideSource: true
}
}