From 7038c021739466de8fa803665de2903e73aa9f18 Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Mon, 22 Dec 2025 01:23:38 +0100 Subject: [PATCH] Improved terminal frame. Improve size and shininess customization. --- app/qml/ApplicationSettings.qml | 68 ++++++++++++++++---------- app/qml/BurnInEffect.qml | 5 +- app/qml/PreprocessedTerminal.qml | 10 ++-- app/qml/SettingsEffectsTab.qml | 5 ++ app/qml/SettingsGeneralTab.qml | 4 +- app/qml/SettingsTerminalTab.qml | 7 +++ app/qml/ShaderTerminal.qml | 10 ++-- app/qml/TerminalFrame.qml | 20 ++++---- app/qml/utils.js | 27 ++++++++-- app/shaders/burn_in.frag | 2 - app/shaders/burn_in.frag.qsb | Bin 3599 -> 3431 bytes app/shaders/passthrough.vert | 4 +- app/shaders/passthrough.vert.qsb | Bin 2521 -> 2436 bytes app/shaders/terminal_dynamic.frag | 22 +++++---- app/shaders/terminal_dynamic.frag.qsb | Bin 9197 -> 9516 bytes app/shaders/terminal_dynamic.vert | 4 +- app/shaders/terminal_dynamic.vert.qsb | Bin 3528 -> 3518 bytes app/shaders/terminal_frame.frag | 55 +++++++++++++-------- app/shaders/terminal_frame.frag.qsb | Bin 4757 -> 4686 bytes app/shaders/terminal_static.frag | 60 ++++++++++++++--------- app/shaders/terminal_static.frag.qsb | Bin 6371 -> 6992 bytes 21 files changed, 193 insertions(+), 110 deletions(-) diff --git a/app/qml/ApplicationSettings.qml b/app/qml/ApplicationSettings.qml index a6d6643..c73aa37 100644 --- a/app/qml/ApplicationSettings.qml +++ b/app/qml/ApplicationSettings.qml @@ -73,16 +73,11 @@ QtObject { property string _backgroundColor: "#000000" property string _fontColor: "#ff8100" - property string saturatedColor: Utils.mix(Utils.strToColor("#FFFFFF"), - Utils.strToColor(_fontColor), - saturationColor * 0.5) - property color fontColor: Utils.mix(Utils.strToColor(saturatedColor), - Utils.strToColor(_backgroundColor), - 0.7 + (contrast * 0.3)) - property color backgroundColor: Utils.mix(Utils.strToColor( - _backgroundColor), - Utils.strToColor(saturatedColor), - 0.7 + (contrast * 0.3)) + property string _frameColor: "#ffffff" + property string saturatedColor: Utils.mix(Utils.strToColor(_fontColor), Utils.strToColor("#FFFFFF"), (saturationColor * 0.5)) + property color fontColor: Utils.mix(Utils.strToColor(_backgroundColor), Utils.strToColor(saturatedColor), (0.7 + (contrast * 0.3))) + property color backgroundColor: Utils.mix(Utils.strToColor(saturatedColor), Utils.strToColor(_backgroundColor), (0.7 + (contrast * 0.3))) + property color frameColor: Utils.strToColor(_frameColor) property real staticNoise: 0.12 property real screenCurvature: 0.3 @@ -100,13 +95,14 @@ QtObject { property real rbgShift: 0.0 + property real _frameShininess: 0.2 + property real frameShininess: _frameShininess * 0.5 + property real _margin: 0.5 - property real _frameMargin: 0.5 - property real margin: Utils.lint(1.0, 20.0, _margin) - property real frameMargin: Utils.lint(1.0, 50.0, _frameMargin) - property real totalMargin: frameMargin + margin + property real _frameSize: 0.2 + property real frameSize: _frameSize * 0.1 readonly property int no_rasterization: 0 readonly property int scanline_rasterization: 1 @@ -304,7 +300,9 @@ QtObject { "fontWidth": fontWidth, "margin": _margin, "blinkingCursor": blinkingCursor, - "frameMargin": _frameMargin, + "frameSize": _frameSize, + "frameColor": _frameColor, + "frameShininess": _frameShininess } return settings } @@ -413,7 +411,9 @@ QtObject { lineSpacing = settings.lineSpacing !== undefined ? settings.lineSpacing : lineSpacing _margin = settings.margin !== undefined ? settings.margin : _margin - _frameMargin = settings.frameMargin !== undefined ? settings.frameMargin : _frameMargin + _frameSize = settings.frameSize !== undefined ? settings.frameSize : _frameSize + _frameColor = settings.frameColor !== undefined ? settings.frameColor : _frameColor + _frameShininess = settings.frameShininess !== undefined ? settings.frameShininess : _frameShininess blinkingCursor = settings.blinkingCursor !== undefined ? settings.blinkingCursor : blinkingCursor } @@ -498,7 +498,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.1 + "frameSize": 0.1, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -528,7 +530,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.1 + "frameSize": 0.1, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -559,7 +563,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.1 + "frameSize": 0.1, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -590,7 +596,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.1 + "frameSize": 0.1, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -621,7 +629,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.2 + "frameSize": 0.2, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -652,7 +662,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.5 + "frameSize": 0.5, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -683,7 +695,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.2 + "frameSize": 0.2, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -714,7 +728,9 @@ QtObject { "windowOpacity": 1, "margin": 0.5, "blinkingCursor": false, - "frameMargin": 0.1 + "frameSize": 0.1, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } @@ -745,7 +761,9 @@ QtObject { "windowOpacity": 0.7, "margin": 0.1, "blinkingCursor": false, - "frameMargin": 0 + "frameSize": 0, + "frameColor": "#ffffff", + "frameShininess": 0.2 }' builtin: true } diff --git a/app/qml/BurnInEffect.qml b/app/qml/BurnInEffect.qml index 464ca21..4f5fd53 100644 --- a/app/qml/BurnInEffect.qml +++ b/app/qml/BurnInEffect.qml @@ -139,11 +139,10 @@ Loader { property real screen_brightness: 1.0 property real bloom: 0 property real rbgShift: 0 - property real screenShadowCoeff: 0 property real frameShadowCoeff: 0 + property real frameShininess: 0 property color frameColor: backgroundColor - property size margin: Qt.size(0, 0) - + property real frameSize: 0 fragmentShader: "qrc:/shaders/burn_in.frag.qsb" vertexShader: "qrc:/shaders/passthrough.vert.qsb" diff --git a/app/qml/PreprocessedTerminal.qml b/app/qml/PreprocessedTerminal.qml index db1c9a1..a44669f 100644 --- a/app/qml/PreprocessedTerminal.qml +++ b/app/qml/PreprocessedTerminal.qml @@ -98,7 +98,7 @@ Item{ id: kterminal property int textureResolutionScale: appSettings.lowResolutionFont ? devicePixelRatio : 1 - property int margin: appSettings.totalMargin / screenScaling + property int margin: appSettings.margin / screenScaling property int totalWidth: Math.floor(parent.width / (screenScaling * fontWidth)) property int totalHeight: Math.floor(parent.height / screenScaling) @@ -213,7 +213,8 @@ Item{ property alias contextmenu: menuLoader.item MouseArea { - property real margin: appSettings.totalMargin + property real margin: appSettings.margin + property real frameSize: appSettings.frameSize acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton anchors.fill: parent @@ -247,10 +248,13 @@ Item{ kterminal.simulateMouseMove(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers); } - function correctDistortion(x, y){ + function correctDistortion(x, y) { x = (x - margin) / width; y = (y - margin) / height; + x = x * (1 + frameSize * 2) - frameSize; + y = y * (1 + frameSize * 2) - frameSize; + var cc = Qt.size(0.5 - x, 0.5 - y); var distortion = (cc.height * cc.height + cc.width * cc.width) * appSettings.screenCurvature * appSettings.screenCurvatureSize; diff --git a/app/qml/SettingsEffectsTab.qml b/app/qml/SettingsEffectsTab.qml index b6281f2..133eaec 100644 --- a/app/qml/SettingsEffectsTab.qml +++ b/app/qml/SettingsEffectsTab.qml @@ -86,6 +86,11 @@ ColumnLayout { onNewValue: function(newValue) { appSettings.rbgShift = newValue } value: appSettings.rbgShift } + CheckableSlider { + name: qsTr("Frame Shininess") + onNewValue: function(newValue) { appSettings._frameShininess = newValue } + value: appSettings._frameShininess + } } } } diff --git a/app/qml/SettingsGeneralTab.qml b/app/qml/SettingsGeneralTab.qml index ea936d2..0a70685 100644 --- a/app/qml/SettingsGeneralTab.qml +++ b/app/qml/SettingsGeneralTab.qml @@ -215,8 +215,8 @@ ColumnLayout { text: qsTr("Frame size") } SimpleSlider { - onValueChanged: appSettings._frameMargin = value - value: appSettings._frameMargin + onValueChanged: appSettings._frameSize = value + value: appSettings._frameSize } Label { text: qsTr("Opacity") diff --git a/app/qml/SettingsTerminalTab.qml b/app/qml/SettingsTerminalTab.qml index 11b2067..ddfcd16 100644 --- a/app/qml/SettingsTerminalTab.qml +++ b/app/qml/SettingsTerminalTab.qml @@ -209,6 +209,13 @@ ColumnLayout { onColorSelected: appSettings._backgroundColor = color color: appSettings._backgroundColor } + ColorButton { + name: qsTr("Frame") + height: 50 + Layout.fillWidth: true + onColorSelected: appSettings._frameColor = color + color: appSettings._frameColor + } } } } diff --git a/app/qml/ShaderTerminal.qml b/app/qml/ShaderTerminal.qml index 73fb4dc..50ba426 100644 --- a/app/qml/ShaderTerminal.qml +++ b/app/qml/ShaderTerminal.qml @@ -81,20 +81,20 @@ Item { 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 displayTerminalFrame: appSettings._frameSize > 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 frameSize: appSettings.frameSize 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 + property real frameShininess: appSettings.frameShininess anchors.fill: parent blending: false @@ -174,6 +174,7 @@ Item { property real ambientLight: parent.ambientLight property size virtualResolution: parent.virtualResolution + property real frameShininess: appSettings.frameShininess // Extra uniforms to match shared uniform block property real time: timeManager.time @@ -193,10 +194,9 @@ Item { 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 frameSize: appSettings.frameSize property real prevLastUpdate: burnInEffect.prevLastUpdate blending: false diff --git a/app/qml/TerminalFrame.qml b/app/qml/TerminalFrame.qml index ea169c4..dd0e56c 100644 --- a/app/qml/TerminalFrame.qml +++ b/app/qml/TerminalFrame.qml @@ -22,23 +22,25 @@ import QtQuick 2.0 import "utils.js" as Utils ShaderEffect { - property color _staticFrameColor: "#fff" + property color _staticFrameColor: Utils.sum(appSettings.frameColor, Qt.rgba(0.1, 0.1, 0.1, 1.0)) property color _backgroundColor: appSettings.backgroundColor property color _fontColor: appSettings.fontColor property color _lightColor: Utils.mix(_fontColor, _backgroundColor, 0.2) - property real _ambientLight: Utils.lint(0.2, 0.8, appSettings.ambientLight) + property real _ambientLight: appSettings.ambientLight + + property color frameColor: Utils.sum( + Utils.scaleColor(_staticFrameColor, 0.8 * _ambientLight), + Utils.scaleColor(_lightColor, 0.2) + ) - property color frameColor: Utils.mix(_staticFrameColor, _lightColor, _ambientLight) property real screenCurvature: appSettings.screenCurvature * appSettings.screenCurvatureSize + // TODO FILIPPO... Get rid of those... // Coefficient of the log curve used to approximate shadowing - property real screenShadowCoeff: Utils.lint(20.0, 10.0, _ambientLight) - property real frameShadowCoeff: Utils.lint(20.0, 10.0, _ambientLight) + property real frameShadowCoeff: 0.0125//Utils.lint(0.05, 0.025, _ambientLight) + property real frameShininess: appSettings.frameShininess - property size margin: Qt.size( - appSettings.frameMargin / width * appSettings.windowScaling, - appSettings.frameMargin / height * appSettings.windowScaling - ) + property real frameSize: appSettings.frameSize // Uniforms required by the shared block property real qt_Opacity: 1.0 diff --git a/app/qml/utils.js b/app/qml/utils.js index 3cb5a67..83c1877 100644 --- a/app/qml/utils.js +++ b/app/qml/utils.js @@ -32,10 +32,29 @@ function lint(a, b, t) { } function mix(c1, c2, alpha) { - return Qt.rgba(c1.r * alpha + c2.r * (1-alpha), - c1.g * alpha + c2.g * (1-alpha), - c1.b * alpha + c2.b * (1-alpha), - c1.a * alpha + c2.a * (1-alpha)) + return Qt.rgba(c1.r * (1 - alpha) + c2.r * alpha, + c1.g * (1 - alpha) + c2.g * alpha, + c1.b * (1 - alpha) + c2.b * alpha, + c1.a * (1 - alpha) + c2.a * alpha) +} + +function sum(c1, c2) { + let result = Qt.rgba( + clamp(c1.r + c2.r, 0, 1), + clamp(c1.g + c2.g, 0, 1), + clamp(c1.b + c2.b, 0, 1), + clamp(c1.a + c2.a, 0, 1) + ); + return result +} + +function scaleColor(c1, value) { + return Qt.rgba( + clamp(c1.r * value, 0, 1), + clamp(c1.g * value, 0, 1), + clamp(c1.b * value, 0, 1), + clamp(c1.a, 0, 1) + ); } function smoothstep(min, max, value) { diff --git a/app/shaders/burn_in.frag b/app/shaders/burn_in.frag index 4868fb8..ffb4f54 100644 --- a/app/shaders/burn_in.frag +++ b/app/shaders/burn_in.frag @@ -31,10 +31,8 @@ layout(std140, binding = 0) uniform ubuf { float screen_brightness; float bloom; float rbgShift; - float screenShadowCoeff; float frameShadowCoeff; vec4 frameColor; - vec2 margin; float prevLastUpdate; }; diff --git a/app/shaders/burn_in.frag.qsb b/app/shaders/burn_in.frag.qsb index 8d51dbf820edac16a635e7a9cbef90bb0a14cdb3..543399fac6777e1f1e5bcc926fdd5b3c0e3b4a98 100644 GIT binary patch literal 3431 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 J{{Rsj&WyU?u;~B* literal 3599 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 V{WR{2cQ&`oV<~+8{1>fbXjAi1A3gv8 diff --git a/app/shaders/passthrough.vert b/app/shaders/passthrough.vert index bfebde5..60a78da 100644 --- a/app/shaders/passthrough.vert +++ b/app/shaders/passthrough.vert @@ -31,10 +31,10 @@ layout(std140, binding = 0) uniform ubuf { float screen_brightness; float bloom; float rbgShift; - float screenShadowCoeff; float frameShadowCoeff; + float frameShininess; vec4 frameColor; - vec2 margin; + float frameSize; float prevLastUpdate; }; diff --git a/app/shaders/passthrough.vert.qsb b/app/shaders/passthrough.vert.qsb index 2574f37d9a635a6d34cd21c89f7c44b925fe85d9..20a79f371379fda51f03348239a9061af6c83568 100644 GIT binary patch delta 2426 zcmV-=35E9A6ND2h001fdc%1E8J!~Au6`muHlz0>^ilQXi`th0y5;75(D*NCI<-dfk z2tKpybr!P*+hhsz;Lc?`%wb1tjRo)%vNo$Cv-B^#Siv=gYVLz@2zOisV`V<|II$9Z zW>C~*_dhB)3$8ce(}DX@P*h{fFmaZ!EaKrNv*CX`gh086UAoJ_xly zBxc8G^iCR{dYu(X>_IS+xNag&fx`jwfzD(0MAVYHO`V|E4TzIFvd_9e4j^V95~Yg2 zW)h!a5!(X=Z6F`A4RFy1MKNH~)xOEqS#|(1@pVl=+++7ZG!j-55iJixF4mFAK*4nj z#BF~Niba9A?2%XoDSB6AfqN6>a{Q**AG5Me_}v!Se+oWtnN(P!WJ0vQf$Cm`9JGb9 zbot&kDVWYF*vYN=J0_uXIUz}Y*F?T7T#}Ks*eej13rK3?J(JiCAhp1TBQm-s>>UU- zi9n_J`(~?MQB8+njhDxU_)f(>FpIUIj(C4j_P`b`NiO!GN$h9rp;&UclItSEK8W%v zcSJ^cX~^38h#6{Y2IxJ=tc!H+au>Xb(fY?G>*sRTCHWH*`5I^pu-xRnmoER%$Mp*W>~7(TyZvF(ZX!8e9=`RwEvaKeg%X)aZ2=%`n8EV z3EG>Wy$D6CDT(D_xu_`emaJL#mZ7FjXlLmh~0l7*brjt z1RF+dn_y+cUL)8DVts;*B6dWuGl;!Ou(OE0MX)i%-X>TDv3CeIj@Y{dJBQeN1e-wY zeS$rO*arkVkJyISq+^EEx0J;arZd;CKu%K3|dUW%Cs_*kfGZ z1nMh`H7JXku+X1h;rKlAufcc{`R9e-a*w7uCeh{;+P{D{r?3u&(Z+u?+9;uoX@@tk>hlrX7dw(Tc!2USP)@-0IscH$J9l?DiZvK5$w~ zRwwY|wZIEPf;H{dem4vfzfESObhKx;gToES@5XzXM9n&I!#IDjy?ag+cu5T2Qkl?> zVkdMT*?i)zA3J`O`Q-Y_{ASR0sBkk0L1qIeulCz^Trjtj1w_%D(=n)Sy%M-lju^E< z$MM&a@W76fFgMlpfh7b0)HIqQ_u6-&D3@R_2zt2%Zg%T?ZYLLBhuf-)YFP`MPN!hb_1%GLS&V!_ zt2s$mJnVi(?USm6e^5+|RmHW7mZC&e^ z)WS)nqI88LmR+<1>rHLY1IDIX5KzYnWneE_q0@EwmYHi-Q-8wXu+g(02BA#P($Nw(*BF?4 z(Sla6A9OmA6VJ7(^E8*p#AcyTmozHxAS!9$n9`*2thFfQWu2;Y97W)H%>~+q6!LE= zxhB|JcTzJg~TsRvkIFFg+N zA+)}I_ul=+S{Ou8x&l*MNvzn)hh{LB zOAT=9_er8o(nB5|w&TW+KIwajH=XgTE%uU)6%@_XWvlDAb# zTQK-ISP+e#F0FhL%TgeL0$-(gAO?~|k%fFVawVy8_53PshYlPuzGCu(J};H=PrP`I z{NkqTx4Z<7-{1Ef=&EqIwLQ0ayE4Edx7YqP|Fy7p8y*}Z-a&oXn-T0X#}ZO2MQ?vw z+0)e%y>Ve7D(_r~{-C!mtoxtpdl!cP|M=#GuKzE+d!=RhTxuKk z5D2D?^udE$Rx9vf=*x!jbKdrWAYVq^gctMKpKMZ%{IhDkaU%T-^mgd_rfwc+eO7(H sl(Mw7V=E102jwkvMEHX5oXUG=_J0!${{>R%v)X)$sXTH08}bg;p)(rJi~s-t delta 2512 zcmV;>2`~196WJ3h001&;c%1E9J!~Au6&{jDiae4QNl_AQQSzD!3^EazPk4xNzaZU0Rn;5hQPB-tN7f*<~UnfRp%EIPvzI@BPf1H{a~)hcPz7 z@XKcnRzhaq-|=D@*A%+B2gW{p<1QF0@S(HJ z`rtEzrg?Gyse@riy#}8qd>;ZwWwrtXV}xap47Y!n2|s<9D9>;d8Mg_0BK|UsCflq7 zMs+X=*$D={9ZyfahD8zEFd0eQ$Rkcc!X9&h&gbliSxf2;O@dz6V4ggY1J(kv2Xl6z zP^$T>dFC@LVEf>p0pugL2`ReZC*6p9A1*+a1m()5m~0?#H$)%cD4eDa-b!S4-G{U_k_W}XW}w2Y6@H__cI zP=khW7BAmhc@Cyi4t7&({&t?xSjtF}-^n9i5-G`<)!EB1FB_0J#=CiD*ML-q7?!B$ zx`=lu+(ZJE=I`Z4ZHaC=f@r)wHpS1_?EQayvpVzT(0DX zm|+J@d6!$FqP#U^Z+*yedTR#gZK$k`be?hxvI#NzM|si5Qqd*(<2>>#c=WK{!O>pd5~9iUZsL+)x^QmS;2%joq#8iI7_#%Eo_< zc`h%CJ=N{uFY@ca`-_`cq$w+6YTTGF)t4-1speA6S%pROlf`m{sstGStGxI{Fml8x z(MIamdDIE;UIXtH@NYxW;)eJp&mf&%g{UR(XbW64(Z#oUE)1Z=l|0MAcX??vjiP(SF1bYgxZwPh;v2O`Bi`aJryNcNN1iOY9Z>AV~8nNL% zxes_A&oFt#_jBa_8td+x3($f6ff7P2}UxU`_b=b5P5E))jM({{RTrl{H-VFqxY8c{837GEzKaJ9{F*?29iZkeHPAFm3m>3C+y!R?M& zx5E>PhIZSM_lH(}*=Txhxb8WgPq3Oo0qDkRk?k-?H5G$Uij0$WINm9Ph|>Tbs6`6dR0(uhgACLg335?7;Ufsm~xwK%M zp$j^{6!U*{vG|;b#j}Z6Ecc!ldScNNi$@ZR%w7I}t|0u6Qp;Th8M#=8dNeIx*5w7m zw^}yeaPzfNoR9AvRomtR&zIF*K3?YGs@-re7$AQn2VS!oSmAuVv_O{vnJ6_1by=fw z{ZUDaCzK|GC&HwVS9GePSBk-NS_)Le6!Nbqxh&Y4wy7qI548x{lBXCxztGh{&4}xu z%1@U`PF;~l%|y?wtC|}5D2J>Nf2~)vtFS6JBWXo=H48mwqQ@FrPnyWI!d@!r>#NJR zW|V)C5tVh7zofBc42_pjo3zyH7J4Sxhl6gZ*QtAGsO+-F%{odntMq)zxY+cN(M|LT zX@`$$bW?9rek5tMjPk}umCnt}gB(-3QASObqfND0&QQAK$WzHHdO77$s1kLJOCOLL zUrd)Dnnk&F<9x`Ovzi)GPfKk~J;Bm`>3M&M&#;x9J9qC@*L^Pts(0K@6yjl|T0ri* zzx(6*_V(S4QmPzUP{Lf2v&#sz9feA)^we^~rAh;w$~{u3)A*E!XZ5i9Zy)vT$eB;3 zexw%{y}T_L9FrnpYxZoja7iv=GNSl)jP)$#3&u)ppcUPf94)&_NuL3%+$K aZ=T7&(q#A_E)=2F#$!z7iR&NVPm4iRX8)=H diff --git a/app/shaders/terminal_dynamic.frag b/app/shaders/terminal_dynamic.frag index 0eb9453..cc0b057 100644 --- a/app/shaders/terminal_dynamic.frag +++ b/app/shaders/terminal_dynamic.frag @@ -35,10 +35,10 @@ layout(std140, binding = 0) uniform ubuf { float screen_brightness; float bloom; float rbgShift; - float screenShadowCoeff; float frameShadowCoeff; + float frameShininess; vec4 frameColor; - vec2 margin; + float frameSize; float prevLastUpdate; }; @@ -52,6 +52,13 @@ float prod2(vec2 v) { return 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)); } +vec2 distortCoordinates(vec2 coords){ + vec2 paddedCoords = coords * (vec2(1.0) + frameSize * 2.0) - frameSize; + vec2 cc = (paddedCoords - vec2(0.5)); + float dist = dot(cc, cc) * screenCurvature; + return (paddedCoords + cc * (1.0 + dist) * dist); +} + vec3 applyRasterization(vec2 screenCoords, vec3 texel, vec2 virtualRes, float intensity, int mode) { if (intensity <= 0.0 || mode == 0) { return texel; @@ -105,11 +112,6 @@ float randomPass(vec2 coords){ return fract(smoothstep(-120.0, 0.0, coords.y - (virtualResolution.y + 120.0) * fract(time * 0.15))); } -vec2 barrel(vec2 v, vec2 cc) { - float distortion = dot(cc, cc) * screenCurvature; - return (v - cc * (1.0 + distortion) * distortion); -} - vec3 convertWithChroma(vec3 inColor) { vec3 outColor = fontColor.rgb * rgb2grey(inColor); if (chromaColor != 0.0) { @@ -122,7 +124,7 @@ void main() { vec2 cc = vec2(0.5) - qt_TexCoord0; float distance = length(cc); - vec2 staticCoords = barrel(qt_TexCoord0, cc); + vec2 staticCoords = distortCoordinates(qt_TexCoord0); vec2 coords = qt_TexCoord0; float dst = sin((coords.y + time) * vDistortionFreq); @@ -156,7 +158,9 @@ void main() { if (displayTerminalFrame > 0.0) { vec4 frameColor = texture(frameSource, qt_TexCoord0); - finalColor = mix(finalColor, frameColor.rgb, frameColor.a); + vec3 reflection = max(finalColor - backgroundColor.rgb, vec3(0.0)); + reflection *= frameShininess; + finalColor = mix(finalColor, frameColor.rgb + reflection, frameColor.a); } fragColor = vec4(finalColor, qt_Opacity); diff --git a/app/shaders/terminal_dynamic.frag.qsb b/app/shaders/terminal_dynamic.frag.qsb index 553d5ad46e2efd770680317583818b9be702ebc1..ad4dd84b7de24d8ef5d4b31db3ac78508392c9dc 100644 GIT binary patch literal 9516 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 literal 9197 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 literal 3528 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 Qs|4L(aX$6>KUk#pG@_$w2mk;8 literal 4757 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 diff --git a/app/shaders/terminal_static.frag b/app/shaders/terminal_static.frag index 6729d38..a2f3d73 100644 --- a/app/shaders/terminal_static.frag +++ b/app/shaders/terminal_static.frag @@ -31,19 +31,27 @@ layout(std140, binding = 0) uniform ubuf { float screen_brightness; float bloom; float rbgShift; - float screenShadowCoeff; float frameShadowCoeff; + float frameShininess; vec4 frameColor; - vec2 margin; + float frameSize; float prevLastUpdate; }; layout(binding = 1) uniform sampler2D source; layout(binding = 2) uniform sampler2D bloomSource; -float sum2(vec2 v) { return v.x + v.y; } +float min2(vec2 v) { return min(v.x, v.y); } +float max2(vec2 v) { return max(v.x, v.y); } float rgb2grey(vec3 v) { return dot(v, vec3(0.21, 0.72, 0.04)); } +vec2 distortCoordinates(vec2 coords){ + vec2 paddedCoords = coords * (vec2(1.0) + frameSize * 2.0) - frameSize; + vec2 cc = (paddedCoords - vec2(0.5)); + float dist = dot(cc, cc) * screenCurvature; + return (paddedCoords + cc * (1.0 + dist) * dist); +} + vec3 convertWithChroma(vec3 inColor) { vec3 outColor = fontColor.rgb * rgb2grey(inColor); if (chromaColor != 0.0) { @@ -55,16 +63,22 @@ vec3 convertWithChroma(vec3 inColor) { void main() { vec2 cc = vec2(0.5) - qt_TexCoord0; + float shownDraw = 1.0; + float isReflection = 0.0; + float isScreen = 1.0; + vec2 txt_coords = qt_TexCoord0; - if (screenCurvature != 0.0) { - float distortion = dot(cc, cc) * screenCurvature; - vec2 curvatureCoords = (qt_TexCoord0 - cc * (1.0 + distortion) * distortion); + if (screenCurvature > 0.0 || frameSize > 0.0) { + vec2 curvatureCoords = distortCoordinates(qt_TexCoord0); + shownDraw = max2(step(vec2(0.0), curvatureCoords) - step(vec2(1.0), curvatureCoords)); + isScreen = min2(step(vec2(0.0), curvatureCoords) - step(vec2(1.0), curvatureCoords)); + isReflection = shownDraw - isScreen; 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) { + 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; @@ -76,27 +90,27 @@ void main() { 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) { + if (chromaColor > 0.0) { vec3 foregroundColor = mix(fontColor.rgb, txt_color * fontColor.rgb / greyscale_color, chromaColor); - finalColor = mix(backgroundColor.rgb, foregroundColor, greyscale_color * reflectionMask); + finalColor = mix(backgroundColor.rgb, foregroundColor, greyscale_color * shownDraw); } else { - finalColor = mix(backgroundColor.rgb, fontColor.rgb, greyscale_color * reflectionMask); + finalColor = mix(backgroundColor.rgb, fontColor.rgb, greyscale_color * shownDraw); } - 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); + vec4 bloomFullColor = texture(bloomSource, txt_coords); + vec3 bloomColor = convertWithChroma(bloomFullColor.rgb); + float bloomAlpha = bloomFullColor.a; + + if (bloom > 0.0) { + vec3 bloomOnScreen = bloomColor * isScreen; + finalColor += clamp(bloomOnScreen * bloom * bloomAlpha, 0.0, 0.5); + } + + if (frameShininess > 0.0) { + float shine = clamp(frameShininess, 0.0, 1.0); + vec3 reflectionColor = mix(bloomColor, finalColor, shine * 0.5); + finalColor = mix(finalColor, reflectionColor, isReflection); } finalColor *= screen_brightness; diff --git a/app/shaders/terminal_static.frag.qsb b/app/shaders/terminal_static.frag.qsb index 3bc2be55352163e2a409d3b948384662a2967102..2cf21eccf6b4f971b70241eaec64818491a16c6b 100644 GIT binary patch literal 6992 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 literal 6371 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 V@r;MWyoBoUz!se3{%ecR{{g!1#&-Y!