lottes.fs 24 KB

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