/******************************************************************************* * 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 . *******************************************************************************/ import QtQuick 2.2 import QtGraphicalEffects 1.0 import "utils.js" as Utils Item { property ShaderEffectSource source property BurnInEffect burnInEffect property ShaderEffectSource bloomSource property color fontColor: appSettings.fontColor property color backgroundColor: appSettings.backgroundColor property real screenCurvature: appSettings.screenCurvature * appSettings.screenCurvatureSize property real chromaColor: appSettings.chromaColor property real ambientLight: appSettings.ambientLight * 0.2 property size virtual_resolution 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 * 0.5 property real glowingLine: appSettings.glowingLine * 0.2 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) / (noiseTexture.width * appSettings.windowScaling * appSettings.totalFontScaling), (height) / (noiseTexture.height * appSettings.windowScaling * appSettings.totalFontScaling)) property size virtual_resolution: parent.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 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 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) ? "vec4 initialNoiseTexel = texture2D(noiseSource, coords);" : "") + (!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 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) ||(fallBack && (flickering || horizontalSync))) ? " uniform lowp sampler2D noiseSource; uniform highp vec2 scaleNoiseSize;" : "") + (screenCurvature !== 0 ? " uniform highp float screenCurvature; uniform lowp sampler2D frameSource;" : "") + (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;" : "") + (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) ? "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);" : "") + (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;") + "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;" : "") + "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);" + "vec3 finalColor = txt_color;" + (flickering !== 0 ? " finalColor *= brightness;" : "") + (ambientLight !== 0 ? " finalColor += vec3(ambientLight) * (1.0 - distance) * (1.0 - distance);" : "") + (screenCurvature !== 0 ? "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: screenCurvature !== 0 width: staticShader.width height: staticShader.height sourceComponent: ShaderEffectSource { sourceItem: terminalFrame hideSource: true visible: false format: ShaderEffectSource.RGBA NewTerminalFrame { id: terminalFrame blending: false anchors.fill: parent } } } 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: appSettings.bloom * 2.5 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 virtual_resolution: parent.virtual_resolution 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 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 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 = 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);" + (screenCurvature !== 0 ? " float reflectionMask = sum2(step(vec2(0.0), curvatureCoords) - step(vec2(1.0), curvatureCoords)); reflectionMask = clamp(0.0, 1.0, reflectionMask);" : "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 } }