1//_____________________________/\_______________________________ 2//============================================================== 3// 4// 5// [CRTS] PUBLIC DOMAIN CRT-STYLED SCALAR - 20180120b 6// 7// by Timothy Lottes 8// https://www.shadertoy.com/view/MtSfRK 9// adapted for RetroArch by hunterk 10// 11// 12//============================================================== 13//////////////////////////////////////////////////////////////// 14//////////////////////////////////////////////////////////////// 15//////////////////////////////////////////////////////////////// 16//_____________________________/\_______________________________ 17//============================================================== 18// 19// WHAT'S NEW 20// 21//-------------------------------------------------------------- 22// Evolution of prior shadertoy example 23//-------------------------------------------------------------- 24// This one is semi-optimized 25// - Less texture fetches 26// - Didn't get to instruction level optimization 27// - Could likely use texture fetch to generate phosphor mask 28//-------------------------------------------------------------- 29// Added options to disable unused features 30//-------------------------------------------------------------- 31// Added in exposure matching 32// - Given scan-line effect and mask always darkens image 33// - Uses generalized tonemapper to boost mid-level 34// - Note this can compress highlights 35// - And won't get back peak brightness 36// - But best option if one doesn't want as much darkening 37//-------------------------------------------------------------- 38// Includes option saturation and contrast controls 39//-------------------------------------------------------------- 40// Added in subtractive aperture grille 41// - This is a bit brighter than prior 42//-------------------------------------------------------------- 43// Make sure input to this filter is already low-resolution 44// - This is not designed to work on titles doing the following 45// - Rendering to hi-res with nearest sampling 46//-------------------------------------------------------------- 47// Added a fast and more pixely option for 2 tap/pixel 48//-------------------------------------------------------------- 49// Improved the vignette when WARP is enabled 50//-------------------------------------------------------------- 51// Didn't test HLSL or CPU options 52// - Will incorportate patches if they are broken 53// - But out of time to try them myself 54//============================================================== 55//////////////////////////////////////////////////////////////// 56//////////////////////////////////////////////////////////////// 57//////////////////////////////////////////////////////////////// 58//_____________________________/\_______________________________ 59//============================================================== 60// 61// LICENSE = UNLICENSE (aka PUBLIC DOMAIN) 62// 63//-------------------------------------------------------------- 64// This is free and unencumbered software released into the 65// public domain. 66//-------------------------------------------------------------- 67// Anyone is free to copy, modify, publish, use, compile, sell, 68// or distribute this software, either in source code form or as 69// a compiled binary, for any purpose, commercial or 70// non-commercial, and by any means. 71//-------------------------------------------------------------- 72// In jurisdictions that recognize copyright laws, the author or 73// authors of this software dedicate any and all copyright 74// interest in the software to the public domain. We make this 75// dedication for the benefit of the public at large and to the 76// detriment of our heirs and successors. We intend this 77// dedication to be an overt act of relinquishment in perpetuity 78// of all present and future rights to this software under 79// copyright law. 80//-------------------------------------------------------------- 81// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 82// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 83// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 84// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE 85// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 86// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 87// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 88// DEALINGS IN THE SOFTWARE. 89//-------------------------------------------------------------- 90// For more information, please refer to 91// <http://unlicense.org/> 92//============================================================== 93//////////////////////////////////////////////////////////////// 94//////////////////////////////////////////////////////////////// 95//////////////////////////////////////////////////////////////// 96 97#pragma parameter MASK "Mask Type" 1.0 0.0 3.0 1.0 98#pragma parameter MASK_INTENSITY "Mask Intensity" 0.5 0.0 1.0 0.05 99#pragma parameter SCANLINE_THINNESS "Scanline Intensity" 0.5 0.0 1.0 0.1 100#pragma parameter SCAN_BLUR "Sharpness" 2.5 1.0 3.0 0.1 101#pragma parameter CURVATURE "Curvature" 0.02 0.0 0.25 0.01 102#pragma parameter TRINITRON_CURVE "Trinitron-style Curve" 0.0 0.0 1.0 1.0 103#pragma parameter CORNER "Corner Round" 3.0 0.0 11.0 1.0 104#pragma parameter CRT_GAMMA "CRT Gamma" 2.4 0.0 51.0 0.1 105 106#if defined(VERTEX) 107 108#if __VERSION__ >= 130 109#define COMPAT_VARYING out 110#define COMPAT_ATTRIBUTE in 111#define COMPAT_TEXTURE texture 112#else 113#define COMPAT_VARYING varying 114#define COMPAT_ATTRIBUTE attribute 115#define COMPAT_TEXTURE texture2D 116#endif 117 118#ifdef GL_ES 119#define COMPAT_PRECISION mediump 120#else 121#define COMPAT_PRECISION 122#endif 123 124COMPAT_ATTRIBUTE vec4 VertexCoord; 125COMPAT_ATTRIBUTE vec4 COLOR; 126COMPAT_ATTRIBUTE vec4 TexCoord; 127COMPAT_VARYING vec4 COL0; 128COMPAT_VARYING vec4 TEX0; 129 130vec4 _oPosition1; 131uniform mat4 MVPMatrix; 132uniform COMPAT_PRECISION int FrameDirection; 133uniform COMPAT_PRECISION int FrameCount; 134uniform COMPAT_PRECISION vec2 OutputSize; 135uniform COMPAT_PRECISION vec2 TextureSize; 136uniform COMPAT_PRECISION vec2 InputSize; 137 138// compatibility #defines 139#define vTexCoord TEX0.xy 140#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize 141#define OutSize vec4(OutputSize, 1.0 / OutputSize) 142 143void main() 144{ 145 gl_Position = MVPMatrix * VertexCoord; 146 TEX0.xy = TexCoord.xy; 147} 148 149#elif defined(FRAGMENT) 150 151#ifdef GL_ES 152#ifdef GL_FRAGMENT_PRECISION_HIGH 153precision highp float; 154#else 155precision mediump float; 156#endif 157#define COMPAT_PRECISION mediump 158#else 159#define COMPAT_PRECISION 160#endif 161 162#if __VERSION__ >= 130 163#define COMPAT_VARYING in 164#define COMPAT_TEXTURE texture 165out COMPAT_PRECISION vec4 FragColor; 166#else 167#define COMPAT_VARYING varying 168#define FragColor gl_FragColor 169#define COMPAT_TEXTURE texture2D 170#endif 171 172uniform COMPAT_PRECISION int FrameDirection; 173uniform COMPAT_PRECISION int FrameCount; 174uniform COMPAT_PRECISION vec2 OutputSize; 175uniform COMPAT_PRECISION vec2 TextureSize; 176uniform COMPAT_PRECISION vec2 InputSize; 177uniform sampler2D Texture; 178COMPAT_VARYING vec4 TEX0; 179 180// compatibility #defines 181#define Source Texture 182#define vTexCoord TEX0.xy 183 184#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize 185#define OutSize vec4(OutputSize, 1.0 / OutputSize) 186 187#ifdef PARAMETER_UNIFORM 188uniform COMPAT_PRECISION float CRT_GAMMA; 189uniform COMPAT_PRECISION float SCANLINE_THINNESS; 190uniform COMPAT_PRECISION float SCAN_BLUR; 191uniform COMPAT_PRECISION float MASK_INTENSITY; 192uniform COMPAT_PRECISION float CURVATURE; 193uniform COMPAT_PRECISION float CORNER; 194uniform COMPAT_PRECISION float MASK; 195uniform COMPAT_PRECISION float TRINITRON_CURVE; 196#else 197#define CRT_GAMMA 2.4 198#define SCANLINE_THINNESS 0.5 199#define SCAN_BLUR 2.5 200#define MASK_INTENSITY 0.54 201#define CURVATURE 0.02 202#define CORNER 3.0 203#define MASK 1.0 204#define TRINITRON_CURVE 0.0 205#endif 206 207//_____________________________/\_______________________________ 208//============================================================== 209// 210// GAMMA FUNCTIONS 211// 212//-------------------------------------------------------------- 213//-------------------------------------------------------------- 214// Since shadertoy doesn't have sRGB textures 215// And we need linear input into shader 216// Don't do this in your code 217 float FromSrgb1(float c){ 218 return (c<=0.04045)?c*(1.0/12.92): 219 pow(c*(1.0/1.055)+(0.055/1.055),CRT_GAMMA);} 220//-------------------------------------------------------------- 221vec3 FromSrgb(vec3 c){return vec3( 222 FromSrgb1(c.r),FromSrgb1(c.g),FromSrgb1(c.b));} 223 224// Convert from linear to sRGB 225// Since shader toy output is not linear 226float ToSrgb1(float c){ 227 return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);} 228//-------------------------------------------------------------- 229vec3 ToSrgb(vec3 c){return vec3( 230 ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));} 231//-------------------------------------------------------------- 232 233//_____________________________/\_______________________________ 234//============================================================== 235// 236// DEFINES 237// 238//-------------------------------------------------------------- 239// CRTS_CPU - CPU code 240// CRTS_GPU - GPU code 241//-------------------------------------------------------------- 242// CRTS_GLSL - GLSL 243// CRTS_HLSL - HLSL (not tested yet) 244//-------------------------------------------------------------- 245// CRTS_DEBUG - Define to see on/off split screen 246//-------------------------------------------------------------- 247// CRTS_WARP - Apply screen warp 248//-------------------------------------------------------------- 249// CRTS_2_TAP - Faster very pixely 2-tap filter (off is 8) 250//-------------------------------------------------------------- 251// CRTS_MASK_GRILLE - Aperture grille (aka Trinitron) 252// CRTS_MASK_GRILLE_LITE - Brighter (subtractive channels) 253// CRTS_MASK_NONE - No mask 254// CRTS_MASK_SHADOW - Horizontally stretched shadow mask 255//-------------------------------------------------------------- 256// CRTS_TONE - Normalize mid-level and process color 257// CRTS_CONTRAST - Process color - enable contrast control 258// CRTS_SATURATION - Process color - enable saturation control 259//-------------------------------------------------------------- 260#define CRTS_STATIC 261#define CrtsPow 262#define CRTS_RESTRICT 263//============================================================== 264//////////////////////////////////////////////////////////////// 265//////////////////////////////////////////////////////////////// 266//////////////////////////////////////////////////////////////// 267 268//============================================================== 269// SETUP FOR CRTS 270//-------------------------------------------------------------- 271//============================================================== 272//#define CRTS_DEBUG 1 273#define CRTS_GPU 1 274#define CRTS_GLSL 1 275//-------------------------------------------------------------- 276//#define CRTS_2_TAP 1 277//-------------------------------------------------------------- 278#define CRTS_TONE 1 279#define CRTS_CONTRAST 0 280#define CRTS_SATURATION 0 281//-------------------------------------------------------------- 282#define CRTS_WARP 1 283//-------------------------------------------------------------- 284// Try different masks -> moved to runtime parameters 285//#define CRTS_MASK_GRILLE 1 286//#define CRTS_MASK_GRILLE_LITE 1 287//#define CRTS_MASK_NONE 1 288//#define CRTS_MASK_SHADOW 1 289//-------------------------------------------------------------- 290// Scanline thinness 291// 0.50 = fused scanlines 292// 0.70 = recommended default 293// 1.00 = thinner scanlines (too thin) 294#define INPUT_THIN 0.5 + (0.5 * SCANLINE_THINNESS) 295//-------------------------------------------------------------- 296// Horizonal scan blur 297// -3.0 = pixely 298// -2.5 = default 299// -2.0 = smooth 300// -1.0 = too blurry 301#define INPUT_BLUR -1.0 * SCAN_BLUR 302//-------------------------------------------------------------- 303// Shadow mask effect, ranges from, 304// 0.25 = large amount of mask (not recommended, too dark) 305// 0.50 = recommended default 306// 1.00 = no shadow mask 307#define INPUT_MASK 1.0 - MASK_INTENSITY 308//-------------------------------------------------------------- 309#define INPUT_X InputSize.x 310#define INPUT_Y InputSize.y 311//-------------------------------------------------------------- 312// Setup the function which returns input image color 313vec3 CrtsFetch(vec2 uv){ 314 // For shadertoy, scale to get native texels in the image 315 uv*=vec2(INPUT_X,INPUT_Y)/TextureSize.xy; 316 // Move towards intersting parts 317// uv+=vec2(0.5,0.5); 318 // Non-shadertoy case would not have the color conversion 319 return FromSrgb(COMPAT_TEXTURE(Texture,uv.xy,-16.0).rgb);} 320#endif 321 322//////////////////////////////////////////////////////////////// 323//////////////////////////////////////////////////////////////// 324//////////////////////////////////////////////////////////////// 325//_____________________________/\_______________________________ 326//============================================================== 327// 328// GPU CODE 329// 330//============================================================== 331#ifdef CRTS_GPU 332//_____________________________/\_______________________________ 333//============================================================== 334// PORTABILITY 335//============================================================== 336 #ifdef CRTS_GLSL 337 #define CrtsF1 float 338 #define CrtsF2 vec2 339 #define CrtsF3 vec3 340 #define CrtsF4 vec4 341 #define CrtsFractF1 fract 342 #define CrtsRcpF1(x) (1.0/(x)) 343 #define CrtsSatF1(x) clamp((x),0.0,1.0) 344//-------------------------------------------------------------- 345 CrtsF1 CrtsMax3F1(CrtsF1 a,CrtsF1 b,CrtsF1 c){ 346 return max(a,max(b,c));} 347 #endif 348//============================================================== 349 #ifdef CRTS_HLSL 350 #define CrtsF1 float 351 #define CrtsF2 float2 352 #define CrtsF3 float3 353 #define CrtsF4 float4 354 #define CrtsFractF1 frac 355 #define CrtsRcpF1(x) (1.0/(x)) 356 #define CrtsSatF1(x) saturate(x) 357//-------------------------------------------------------------- 358 CrtsF1 CrtsMax3F1(CrtsF1 a,CrtsF1 b,CrtsF1 c){ 359 return max(a,max(b,c));} 360 #endif 361//_____________________________/\_______________________________ 362//============================================================== 363// TONAL CONTROL CONSTANT GENERATION 364//-------------------------------------------------------------- 365// This is in here for rapid prototyping 366// Please use the CPU code and pass in as constants 367//============================================================== 368 CrtsF4 CrtsTone( 369 CrtsF1 contrast, 370 CrtsF1 saturation, 371 CrtsF1 thin, 372 CrtsF1 mask){ 373//-------------------------------------------------------------- 374 if(MASK == 0.0) mask=1.0; 375//-------------------------------------------------------------- 376 if(MASK == 1.0){ 377 // Normal R mask is {1.0,mask,mask} 378 // LITE R mask is {mask,1.0,1.0} 379 mask=0.5+mask*0.5; 380 } 381//-------------------------------------------------------------- 382 CrtsF4 ret; 383 CrtsF1 midOut=0.18/((1.5-thin)*(0.5*mask+0.5)); 384 CrtsF1 pMidIn=pow(0.18,contrast); 385 ret.x=contrast; 386 ret.y=((-pMidIn)+midOut)/((1.0-pMidIn)*midOut); 387 ret.z=((-pMidIn)*midOut+pMidIn)/(midOut*(-pMidIn)+midOut); 388 ret.w=contrast+saturation; 389 return ret;} 390//_____________________________/\_______________________________ 391//============================================================== 392// MASK 393//-------------------------------------------------------------- 394// Letting LCD/OLED pixel elements function like CRT phosphors 395// So "phosphor" resolution scales with display resolution 396//-------------------------------------------------------------- 397// Not applying any warp to the mask (want high frequency) 398// Real aperture grille has a mask which gets wider on ends 399// Not attempting to be "real" but instead look the best 400//-------------------------------------------------------------- 401// Shadow mask is stretched horizontally 402// RRGGBB 403// GBBRRG 404// RRGGBB 405// This tends to look better on LCDs than vertical 406// Also 2 pixel width is required to get triad centered 407//-------------------------------------------------------------- 408// The LITE version of the Aperture Grille is brighter 409// Uses {dark,1.0,1.0} for R channel 410// Non LITE version uses {1.0,dark,dark} 411//-------------------------------------------------------------- 412// 'pos' - This is 'fragCoord.xy' 413// Pixel {0,0} should be {0.5,0.5} 414// Pixel {1,1} should be {1.5,1.5} 415//-------------------------------------------------------------- 416// 'dark' - Exposure of of masked channel 417// 0.0=fully off, 1.0=no effect 418//============================================================== 419 CrtsF3 CrtsMask(CrtsF2 pos,CrtsF1 dark){ 420 if(MASK == 2.0){ 421 CrtsF3 m=CrtsF3(dark,dark,dark); 422 CrtsF1 x=CrtsFractF1(pos.x*(1.0/3.0)); 423 if(x<(1.0/3.0))m.r=1.0; 424 else if(x<(2.0/3.0))m.g=1.0; 425 else m.b=1.0; 426 return m; 427 } 428//-------------------------------------------------------------- 429 if(MASK == 1.0){ 430 CrtsF3 m=CrtsF3(1.0,1.0,1.0); 431 CrtsF1 x=CrtsFractF1(pos.x*(1.0/3.0)); 432 if(x<(1.0/3.0))m.r=dark; 433 else if(x<(2.0/3.0))m.g=dark; 434 else m.b=dark; 435 return m; 436 } 437//-------------------------------------------------------------- 438 if(MASK == 0.0){ 439 return CrtsF3(1.0,1.0,1.0); 440 } 441//-------------------------------------------------------------- 442 if(MASK == 3.0){ 443 pos.x+=pos.y*2.9999; 444 CrtsF3 m=CrtsF3(dark,dark,dark); 445 CrtsF1 x=CrtsFractF1(pos.x*(1.0/6.0)); 446 if(x<(1.0/3.0))m.r=1.0; 447 else if(x<(2.0/3.0))m.g=1.0; 448 else m.b=1.0; 449 return m; 450 } 451 } 452//_____________________________/\_______________________________ 453//============================================================== 454// FILTER ENTRY 455//-------------------------------------------------------------- 456// Input must be linear 457// Output color is linear 458//-------------------------------------------------------------- 459// Must have fetch function setup: CrtsF3 CrtsFetch(CrtsF2 uv) 460// - The 'uv' range is {0.0 to 1.0} for input texture 461// - Output of this must be linear color 462//-------------------------------------------------------------- 463// SCANLINE MATH & AUTO-EXPOSURE NOTES 464// =================================== 465// Each output line has contribution from at most 2 scanlines 466// Scanlines are shaped by a windowed cosine function 467// This shape blends together well with only 2 lines of overlap 468//-------------------------------------------------------------- 469// Base scanline intensity is as follows 470// which leaves output intensity range from {0 to 1.0} 471// -------- 472// thin := range {thick 0.5 to thin 1.0} 473// off := range {0.0 to <1.0}, 474// sub-pixel offset between two scanlines 475// -------- 476// a0=cos(min(0.5, off *thin)*2pi)*0.5+0.5; 477// a1=cos(min(0.5,(1.0-off)*thin)*2pi)*0.5+0.5; 478//-------------------------------------------------------------- 479// This leads to a image darkening factor of roughly: 480// {(1.5-thin)/1.0} 481// This is further reduced by the mask: 482// {1.0/2.0+mask*1.0/2.0} 483// Reciprocal of combined effect is used for auto-exposure 484// to scale up the mid-level in the tonemapper 485//============================================================== 486 CrtsF3 CrtsFilter( 487//-------------------------------------------------------------- 488 // SV_POSITION, fragCoord.xy 489 CrtsF2 ipos, 490//-------------------------------------------------------------- 491 // inputSize / outputSize (in pixels) 492 CrtsF2 inputSizeDivOutputSize, 493//-------------------------------------------------------------- 494 // 0.5 * inputSize (in pixels) 495 CrtsF2 halfInputSize, 496//-------------------------------------------------------------- 497 // 1.0 / inputSize (in pixels) 498 CrtsF2 rcpInputSize, 499//-------------------------------------------------------------- 500 // 1.0 / outputSize (in pixels) 501 CrtsF2 rcpOutputSize, 502//-------------------------------------------------------------- 503 // 2.0 / outputSize (in pixels) 504 CrtsF2 twoDivOutputSize, 505//-------------------------------------------------------------- 506 // inputSize.y 507 CrtsF1 inputHeight, 508//-------------------------------------------------------------- 509 // Warp scanlines but not phosphor mask 510 // 0.0 = no warp 511 // 1.0/64.0 = light warping 512 // 1.0/32.0 = more warping 513 // Want x and y warping to be different (based on aspect) 514 CrtsF2 warp, 515//-------------------------------------------------------------- 516 // Scanline thinness 517 // 0.50 = fused scanlines 518 // 0.70 = recommended default 519 // 1.00 = thinner scanlines (too thin) 520 // Shared with CrtsTone() function 521 CrtsF1 thin, 522//-------------------------------------------------------------- 523 // Horizonal scan blur 524 // -3.0 = pixely 525 // -2.5 = default 526 // -2.0 = smooth 527 // -1.0 = too blurry 528 CrtsF1 blur, 529//-------------------------------------------------------------- 530 // Shadow mask effect, ranges from, 531 // 0.25 = large amount of mask (not recommended, too dark) 532 // 0.50 = recommended default 533 // 1.00 = no shadow mask 534 // Shared with CrtsTone() function 535 CrtsF1 mask, 536//-------------------------------------------------------------- 537 // Tonal curve parameters generated by CrtsTone() 538 CrtsF4 tone 539//-------------------------------------------------------------- 540 ){ 541//-------------------------------------------------------------- 542 #ifdef CRTS_DEBUG 543 CrtsF2 uv=ipos*rcpOutputSize; 544 // Show second half processed, and first half un-processed 545 if(uv.x<0.5){ 546 // Force nearest to get squares 547 uv*=1.0/rcpInputSize; 548 uv=floor(uv)+CrtsF2(0.5,0.5); 549 uv*=rcpInputSize; 550 CrtsF3 color=CrtsFetch(uv); 551 return color;} 552 #endif 553//-------------------------------------------------------------- 554 // Optional apply warp 555 CrtsF2 pos; 556 #ifdef CRTS_WARP 557 // Convert to {-1 to 1} range 558 pos=ipos*twoDivOutputSize-CrtsF2(1.0,1.0); 559 // Distort pushes image outside {-1 to 1} range 560 pos*=CrtsF2( 561 1.0+(pos.y*pos.y)*warp.x, 562 1.0+(pos.x*pos.x)*warp.y); 563 // TODO: Vignette needs optimization 564 CrtsF1 vin=(1.0-( 565 (1.0-CrtsSatF1(pos.x*pos.x))*(1.0-CrtsSatF1(pos.y*pos.y)))) * (0.998 + (0.001 * CORNER)); 566 vin=CrtsSatF1((-vin)*inputHeight+inputHeight); 567 // Leave in {0 to inputSize} 568 pos=pos*halfInputSize+halfInputSize; 569 #else 570 pos=ipos*inputSizeDivOutputSize; 571 #endif 572//-------------------------------------------------------------- 573 // Snap to center of first scanline 574 CrtsF1 y0=floor(pos.y-0.5)+0.5; 575 #ifdef CRTS_2_TAP 576 // Using Inigo's "Improved Texture Interpolation" 577 // http://iquilezles.org/www/articles/texture/texture.htm 578 pos.x+=0.5; 579 CrtsF1 xi=floor(pos.x); 580 CrtsF1 xf=pos.x-xi; 581 xf=xf*xf*xf*(xf*(xf*6.0-15.0)+10.0); 582 CrtsF1 x0=xi+xf-0.5; 583 CrtsF2 p=CrtsF2(x0*rcpInputSize.x,y0*rcpInputSize.y); 584 // Coordinate adjusted bilinear fetch from 2 nearest scanlines 585 CrtsF3 colA=CrtsFetch(p); 586 p.y+=rcpInputSize.y; 587 CrtsF3 colB=CrtsFetch(p); 588 #else 589 // Snap to center of one of four pixels 590 CrtsF1 x0=floor(pos.x-1.5)+0.5; 591 // Inital UV position 592 CrtsF2 p=CrtsF2(x0*rcpInputSize.x,y0*rcpInputSize.y); 593 // Fetch 4 nearest texels from 2 nearest scanlines 594 CrtsF3 colA0=CrtsFetch(p); 595 p.x+=rcpInputSize.x; 596 CrtsF3 colA1=CrtsFetch(p); 597 p.x+=rcpInputSize.x; 598 CrtsF3 colA2=CrtsFetch(p); 599 p.x+=rcpInputSize.x; 600 CrtsF3 colA3=CrtsFetch(p); 601 p.y+=rcpInputSize.y; 602 CrtsF3 colB3=CrtsFetch(p); 603 p.x-=rcpInputSize.x; 604 CrtsF3 colB2=CrtsFetch(p); 605 p.x-=rcpInputSize.x; 606 CrtsF3 colB1=CrtsFetch(p); 607 p.x-=rcpInputSize.x; 608 CrtsF3 colB0=CrtsFetch(p); 609 #endif 610//-------------------------------------------------------------- 611 // Vertical filter 612 // Scanline intensity is using sine wave 613 // Easy filter window and integral used later in exposure 614 CrtsF1 off=pos.y-y0; 615 CrtsF1 pi2=6.28318530717958; 616 CrtsF1 hlf=0.5; 617 CrtsF1 scanA=cos(min(0.5, off *thin )*pi2)*hlf+hlf; 618 CrtsF1 scanB=cos(min(0.5,(-off)*thin+thin)*pi2)*hlf+hlf; 619//-------------------------------------------------------------- 620 #ifdef CRTS_2_TAP 621 #ifdef CRTS_WARP 622 // Get rid of wrong pixels on edge 623 scanA*=vin; 624 scanB*=vin; 625 #endif 626 // Apply vertical filter 627 CrtsF3 color=(colA*scanA)+(colB*scanB); 628 #else 629 // Horizontal kernel is simple gaussian filter 630 CrtsF1 off0=pos.x-x0; 631 CrtsF1 off1=off0-1.0; 632 CrtsF1 off2=off0-2.0; 633 CrtsF1 off3=off0-3.0; 634 CrtsF1 pix0=exp2(blur*off0*off0); 635 CrtsF1 pix1=exp2(blur*off1*off1); 636 CrtsF1 pix2=exp2(blur*off2*off2); 637 CrtsF1 pix3=exp2(blur*off3*off3); 638 CrtsF1 pixT=CrtsRcpF1(pix0+pix1+pix2+pix3); 639 #ifdef CRTS_WARP 640 // Get rid of wrong pixels on edge 641 pixT*=vin; 642 #endif 643 scanA*=pixT; 644 scanB*=pixT; 645 // Apply horizontal and vertical filters 646 CrtsF3 color= 647 (colA0*pix0+colA1*pix1+colA2*pix2+colA3*pix3)*scanA + 648 (colB0*pix0+colB1*pix1+colB2*pix2+colB3*pix3)*scanB; 649 #endif 650//-------------------------------------------------------------- 651 // Apply phosphor mask 652 color*=CrtsMask(ipos,mask); 653//-------------------------------------------------------------- 654 // Optional color processing 655 #ifdef CRTS_TONE 656 // Tonal control, start by protecting from /0 657 CrtsF1 peak=max(1.0/(256.0*65536.0), 658 CrtsMax3F1(color.r,color.g,color.b)); 659 // Compute the ratios of {R,G,B} 660 CrtsF3 ratio=color*CrtsRcpF1(peak); 661 // Apply tonal curve to peak value 662 #ifdef CRTS_CONTRAST 663 peak=pow(peak,tone.x); 664 #endif 665 peak=peak*CrtsRcpF1(peak*tone.y+tone.z); 666 // Apply saturation 667 #ifdef CRTS_SATURATION 668 ratio=pow(ratio,CrtsF3(tone.w,tone.w,tone.w)); 669 #endif 670 // Reconstruct color 671 return ratio*peak; 672 #else 673 return color; 674 #endif 675//-------------------------------------------------------------- 676 } 677 678 679void main() 680{ 681 vec2 warp_factor; 682 warp_factor.x = CURVATURE; 683 warp_factor.y = (3.0 / 4.0) * warp_factor.x; // assume 4:3 aspect 684 warp_factor.x *= (1.0 - TRINITRON_CURVE); 685 FragColor.rgb = CrtsFilter(vTexCoord.xy * OutputSize.xy*(TextureSize.xy / InputSize.xy), 686 InputSize.xy / OutputSize.xy, 687 InputSize.xy * vec2(0.5,0.5), 688 1.0/InputSize.xy, 689 1.0/OutputSize.xy, 690 2.0/OutputSize.xy, 691 InputSize.y, 692 warp_factor, 693 INPUT_THIN, 694 INPUT_BLUR, 695 INPUT_MASK, 696 CrtsTone(1.0,0.0,INPUT_THIN,INPUT_MASK)); 697 698 // Shadertoy outputs non-linear color 699 FragColor.rgb=ToSrgb(FragColor.rgb); 700} 701#endif 702