SHARE
TWEET

Artifact Colors (NTSC)

a guest Jul 6th, 2017 56 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. Adapted for RetroArch from Flyguy's "Apple II-Like Artifact Colors" from shadertoy:
  3. https://www.shadertoy.com/view/llyGzR
  4.  
  5. "Colors created through NTSC artifacting on 4-bit patterns, similar to the Apple II's lo-res mode."
  6.  
  7. "Ported to ReShade by Matsilagi and luluco250"
  8. */
  9.  
  10. #if ARTIFACT_COLORS_MUL_FIX
  11.     //on directx the matrices must be multiplied in reverse
  12.     #if (__RENDERER__ >= 0x10000)
  13.         #define MUL(A, B) mul(A, B)
  14.     #else
  15.         #define MUL(A, B) mul(B, A)
  16.     #endif
  17. #else
  18.     #define MUL(A, B) mul(A, B)
  19. #endif
  20.  
  21. #include "ReShade.fxh"
  22.  
  23. //Macros/////////////////////////////////////////////////////////////////////////////////////////
  24.  
  25. uniform float display_sizeX <
  26.     ui_type = "drag";
  27.     ui_min = 1.0;
  28.     ui_max = BUFFER_WIDTH;
  29.     ui_label = "Screen Width [ArtifactColors]";
  30. > = BUFFER_WIDTH;
  31.  
  32. uniform float display_sizeY <
  33.     ui_type = "drag";
  34.     ui_min = 1.0;
  35.     ui_max = BUFFER_HEIGHT;
  36.     ui_label = "Screen Height [ArtifactColors]";
  37. > = BUFFER_HEIGHT;
  38.  
  39. uniform float HUE <
  40.     ui_type = "drag";
  41.     ui_min = 0.0;
  42.     ui_max = 1.0;
  43.     ui_step = 0.01;
  44.     ui_label = "Hue [ArtifactColors]";
  45. > = 0.0;
  46.  
  47. uniform float SATURATION <
  48.     ui_type = "drag";
  49.     ui_min = 0.0;
  50.     ui_max = 100.0;
  51.     ui_step = 1.0;
  52.     ui_label = "Saturation [ArtifactColors]";
  53. > = 30.0;
  54.  
  55. uniform float BRIGHTNESS <
  56.     ui_type = "drag";
  57.     ui_min = 0.0;
  58.     ui_max = 2.0;
  59.     ui_label = "Brightness [ArtifactColors]";
  60.     ui_step = 0.01;
  61. > = 1.0;
  62.  
  63. uniform float F_COL <
  64.     ui_type = "drag";
  65.     ui_min = 4.0;
  66.     ui_max = 8.0;
  67.     ui_step = 1.0;
  68.     ui_label = "F Col [ArtifactColors]";
  69.     ui_tooltip = "Realtime changes not available in DX9.\nUse F_COL_DX9 to mod that in DX9.\n(Preprocessor Definition)";
  70. > = 4.0;
  71.  
  72. uniform float F_COL_BW <
  73.     ui_type = "drag";
  74.     ui_min = 10.0;
  75.     ui_max = 200.0;
  76.     ui_step = 1.0;
  77.     ui_label = "F Col BW [ArtifactColors]";
  78.     ui_tooltip = "Realtime changes not available in DX9.\nUse F_COL_BW_DX9 to mod that in DX9.\n(Preprocessor Definition)";
  79. > = 50.0;
  80.  
  81. uniform float F_LUMA_LP <
  82.     ui_type = "drag";
  83.     ui_min = 1.0;
  84.     ui_max = 12.0;
  85.     ui_step = 1.0;
  86.     ui_label = "F Luma LP [ArtifactColors]";
  87.     ui_tooltip = "Realtime changes not available in DX9.\nUse F_LUMA_LP_DX9 to mod that in DX9.\n(Preprocessor Definition)";
  88. > = 6.0;
  89.  
  90. uniform int Viewmode <
  91.     ui_type = "combo";
  92.     ui_label = "View Mode [ArtifactColors]";
  93.     ui_items = "Composite\0RGB\0Luma\0Chroma\0Signal\0Split\0";
  94. > = 0;
  95.  
  96. //DirectX 9 fixes HERE WE GOOOOOO fuck...
  97. #ifndef F_COL_DX9
  98.     #define F_COL_DX9 4.0
  99. #endif
  100.  
  101. #ifndef F_LUMA_LP_DX9
  102.     #define F_LUMA_LP_DX9 6.0
  103. #endif
  104.  
  105. #ifndef F_COL_BW_DX9
  106.     #define F_COL_BW_DX9 50.0
  107. #endif
  108.  
  109. #define FIR_SIZE 29
  110.  
  111. #define display_size float2(display_sizeX,display_sizeY)
  112.  
  113. //Statics////////////////////////////////////////////////////////////////////////////////////////
  114.  
  115. static const float pi = atan(1.0) * 4.0;
  116. static const float tau = atan(1.0) * 8.0;
  117. static const float3x3 rgb2yiq = float3x3(
  118.     0.299, 0.596, 0.211,
  119.     0.587,-0.274,-0.523,
  120.     0.114,-0.322, 0.312
  121. );
  122. static const float3x3 yiq2rgb = float3x3(
  123.     1.000, 1.000, 1.000,
  124.     0.956,-0.272,-1.106,
  125.     0.621,-0.647, 1.703
  126. );
  127.  
  128. //Uniforms///////////////////////////////////////////////////////////////////////////////////////
  129. //Textures///////////////////////////////////////////////////////////////////////////////////////
  130.  
  131. texture ArtifactChannel0_tex {
  132.     Width = BUFFER_WIDTH;
  133.     Height = BUFFER_HEIGHT;
  134.     Format = RGBA32F;
  135. };
  136.  
  137. texture tArtifactColors_Modulator {
  138.     Width = BUFFER_WIDTH;
  139.     Height = BUFFER_HEIGHT;
  140.     Format = R16F;
  141. };
  142. sampler sArtifactColors_Modulator {
  143.     Texture = tArtifactColors_Modulator;
  144. };
  145.  
  146. texture tArtifactColors_Demodulator {
  147.     Width = BUFFER_WIDTH;
  148.     Height = BUFFER_HEIGHT;
  149.     Format = RGBA16F;
  150. };
  151.  
  152. sampler sArtifactColors_Demodulator {
  153.     Texture = tArtifactColors_Demodulator;
  154. };
  155.  
  156. sampler ArtifactChannel0 {
  157.     Texture = ArtifactChannel0_tex;
  158. };
  159.  
  160. //Functions//////////////////////////////////////////////////////////////////////////////////////
  161.  
  162. //Angle -> 2D rotation matrix
  163. float2x2 rotate(float a) {
  164.     return float2x2(
  165.          cos(a), sin(a),
  166.         -sin(a), cos(a)
  167.     );
  168. }
  169.  
  170. //Non-normalized texture sampling
  171. float4 sample2D(sampler sp, float2 res, float2 uv) {
  172.     return tex2D(sp, uv / res);
  173. }
  174.  
  175. //Complex multiply
  176. float2 cmul(float2 a, float2 b) {
  177.     return float2((a.x * b.x) - (a.y * b.y), (a.x * b.y) + (a.y * b.y));
  178. }
  179.  
  180. float sinc(float x) { //reshade warns about division by zero here, even though there should be none
  181.     //return (x == 0.0) ? 1.0 : sin(x * pi) / max(x * pi, 0.001); //so we'll use max()
  182.     return (x == 0.0) ? 1.0 : sin(x * pi) / (x * pi);
  183. }
  184.  
  185. //https://en.wikipedia.org/wiki/Window_function
  186. float WindowBlackman(float a, int N, int i) {
  187.     float a0 = (1.0 - a) / 2.0;
  188.     float a1 = 0.5;
  189.     float a2 = a / 2.0;
  190.    
  191.     float wnd = a0;
  192.     wnd -= a1 * cos(2.0 * pi * (float(i) / float(N - 1)));
  193.     wnd += a2 * cos(4.0 * pi * (float(i) / float(N - 1)));
  194.    
  195.     return wnd;
  196. }
  197.  
  198. //FIR lowpass filter
  199. //Fc = Cutoff freq., Fs = Sample freq., N = # of taps, i = Tap index
  200. float Lowpass(float Fc, float Fs, int N, int i) {
  201.     float wc = (Fc / Fs);
  202.    
  203.     float wnd = WindowBlackman(0.16, N, i);
  204.    
  205.     return 2.0 * wc * wnd * sinc(2.0 * wc * float(i - N / 2));
  206. }
  207.  
  208. //FIR bandpass filter
  209. //Fa/Fb = Low/High cutoff freq., Fs = Sample freq., N = # of taps, i = Tap index
  210. float Bandpass(float Fa, float Fb, float Fs, int N, int i) {
  211.     float wa = (Fa / Fs);
  212.     float wb = (Fb / Fs);
  213.    
  214.     float wnd = WindowBlackman(0.16, N, i);
  215.    
  216.     return 2.0 * (wb - wa) * wnd * (sinc(2.0 * wb * float(i - N / 2)) - sinc(2.0 * wa * float(i - N / 2)));
  217. }
  218.  
  219. //Complex oscillator, Fo = Oscillator freq., Fs = Sample freq., n = Sample index
  220. float2 Oscillator(float Fo, float Fs, float N) {
  221.     float phase = (tau * Fo * floor(N)) / Fs;
  222.     return float2(cos(phase), sin(phase));
  223. }
  224.  
  225. float2 p_sh(float2 p_){
  226.  
  227.     float2 xx = float2(320.0, 240.0); //output screen res              
  228.     float2 ar = float2(1.0,1.0); //final aspect ratio (calculated)
  229.    
  230.     xx = display_size;
  231.    
  232.     ar = float(1.0).xx;
  233.    
  234.     return 0.5 * float2(
  235.         step(0.0, 1.0 - ar.y) * (1.0 - 1.0 / ar.y),
  236.         step(1.0, ar.y) * (1.0 - ar.y));
  237. }
  238.  
  239. //Shaders////////////////////////////////////////////////////////////////////////////////////////
  240.  
  241. float4 PS_Stock(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
  242. {  
  243.     float2 p_ = texcoord.xy*float2((float)BUFFER_WIDTH,(float)BUFFER_HEIGHT);
  244.     float2 xx = float2(320.0,240.0);
  245.     float2 ar = float2(1.0,1.0); //final aspect ratio (calculated)
  246.    
  247.     xx = ReShade::ScreenSize.xy;
  248.     ar = float(1.0).xx;
  249.    
  250.     xx = display_size;
  251.        
  252.     p_ = texcoord;
  253.     p_ -= 0.5;
  254.     p_ *= ar;
  255.     p_ += 0.5;
  256.        
  257.     if(ar.y<1.0){p_ -= 0.5; p_ = p_*(1.0/ar.y); p_ += 0.5; }
  258.        
  259.     p_ = floor(p_*xx)/xx;
  260.     p_ +=  p_sh(p_);
  261.    
  262.     return tex2D(ReShade::BackBuffer, p_).rgba;
  263. }      
  264.  
  265. float PS_Modulator(
  266.     float4 pos : SV_POSITION,
  267.     float2 uv : TEXCOORD
  268. ) : SV_TARGET {
  269.     float Fs = BUFFER_WIDTH;
  270.     float Fcol = Fs * (1.0 / F_COL);
  271.     float n = floor(uv.x * BUFFER_WIDTH);
  272.  
  273.     float3 cRGB = tex2D(ArtifactChannel0, uv).rgb;
  274.     float3 cYIQ = MUL(rgb2yiq, cRGB);
  275.  
  276.     float2 cOsc = Oscillator(Fcol, Fs, n);
  277.  
  278.     float sig = cYIQ.x + dot(cOsc, cYIQ.yz);
  279.  
  280.     return sig;
  281. }
  282.  
  283. float4 PS_Demodulator(
  284.     float4 pos : SV_POSITION,
  285.     float2 uv : TEXCOORD
  286. ) : SV_TARGET {
  287.     float2 _uv = uv * ReShade::ScreenSize;
  288.  
  289.     float Fs = BUFFER_WIDTH;
  290.     float Fcol = Fs * (1.0 / F_COL_DX9);
  291.     float Fcolbw = Fs * (1.0 / F_COL_BW_DX9);
  292.     float Flumlp = Fs * (1.0 / F_LUMA_LP_DX9);
  293.     float n = floor(_uv.x);
  294.    
  295.     if (__RENDERER__ != 0x09300){
  296.         Fcol = Fs * (1.0 / F_COL);
  297.         Fcolbw = Fs * (1.0 / F_COL_BW);
  298.         Flumlp = Fs * (1.0 / F_LUMA_LP);
  299.     }
  300.  
  301.     float y_sig = 0.0;
  302.     float iq_sig = 0.0;
  303.  
  304.     float2 cOsc = Oscillator(Fcol, Fs, n);
  305.  
  306.     n += float(FIR_SIZE) / 2.0;
  307.  
  308.     //Separate luma(Y) & chroma(IQ) signals
  309.     [unroll]
  310.     for (int i = 0; i < FIR_SIZE; ++i) {
  311.         int tpidx = FIR_SIZE - i - 1;
  312.         float lp = Lowpass(Flumlp, Fs, FIR_SIZE, tpidx);
  313.         float bp = Bandpass(Fcol - Fcolbw, Fcol + Fcolbw, Fs, FIR_SIZE, tpidx);
  314.  
  315.         y_sig += sample2D(sArtifactColors_Modulator, ReShade::ScreenSize, float2(n - float(i), _uv.y)).x * lp;
  316.         iq_sig += sample2D(sArtifactColors_Modulator, ReShade::ScreenSize, float2(n - float(i), _uv.y)).x * bp;
  317.     }
  318.  
  319.     //Shift IQ signal down from Fcol to DC
  320.     float2 iq_sig_mix = cmul(float2(iq_sig, 0.0), cOsc);
  321.  
  322.     return float4(y_sig, iq_sig_mix, 0.0);
  323. }
  324.  
  325. float4 PS_Final(
  326.     float4 pos : SV_POSITION,
  327.     float2 uv : TEXCOORD
  328. ) : SV_TARGET {
  329.     float Fs = BUFFER_WIDTH;
  330.     float Fcol = Fs * (1.0 / F_COL);
  331.     float Flumlp = Fs * (1.0 / F_LUMA_LP);
  332.     float n = floor(uv.x * BUFFER_WIDTH);
  333.    
  334.     if (__RENDERER__ != 0x09300){
  335.         Fcol = Fs * (1.0 / F_COL_DX9);
  336.         Flumlp = Fs * (1.0 / F_LUMA_LP_DX9);
  337.     }
  338.  
  339.     float2 _uv = uv * ReShade::ScreenSize;
  340.  
  341.     float luma = sample2D(sArtifactColors_Demodulator, ReShade::ScreenSize, _uv).x;
  342.     float2 chroma = 0.0;
  343.  
  344.     //Filtering out unwanted high frequency content from the chroma(IQ) signal
  345.     [unroll]
  346.     for (int i = 0; i < FIR_SIZE; ++i) {
  347.         int tpidx = FIR_SIZE - i -1;
  348.         float lp = Lowpass(Flumlp, Fs, FIR_SIZE, tpidx);
  349.         chroma += sample2D(sArtifactColors_Demodulator, ReShade::ScreenSize, _uv - float2(i - FIR_SIZE / 2, 0)).yz * lp;
  350.     }
  351.        
  352.  
  353.     //chroma *= rotate(tau * HUE);
  354.     chroma = MUL(chroma, rotate(tau * HUE));
  355.  
  356.     float3 color = MUL(yiq2rgb, float3(BRIGHTNESS * luma, chroma * SATURATION));
  357.    
  358.     if (Viewmode == 0) {
  359.         return float4(color, 0.0);
  360.     } else if (Viewmode == 1) {
  361.         return tex2D(sArtifactColors_Modulator, uv).xxxx;
  362.     } else if (Viewmode == 2){
  363.         return float4(luma.xxx, 0.0);
  364.     } else if (Viewmode == 3){
  365.         return float4(40.0 * chroma + 0.5, 0.0, 0.0);
  366.     } else if (Viewmode == 4){
  367.         return 0.5 * tex2D(sArtifactColors_Demodulator, uv).xxxx + 0.25;
  368.     } else if (Viewmode == 5){
  369.         if (uv.x < 0.5)
  370.             return tex2D(sArtifactColors_Modulator, uv).xxxx;
  371.         else
  372.             return float4(color, 0.0);
  373.     } else {
  374.         return 0;
  375.     }
  376. }
  377.  
  378. //Technique//////////////////////////////////////////////////////////////////////////////////////
  379.  
  380. technique ArtifactColors {
  381.     pass Resize {
  382.         VertexShader = PostProcessVS;
  383.         PixelShader = PS_Stock;
  384.         RenderTarget = ArtifactChannel0_tex;
  385.     }
  386.     pass Modulator {
  387.         VertexShader = PostProcessVS;
  388.         PixelShader = PS_Modulator;
  389.         RenderTarget = tArtifactColors_Modulator;
  390.     }
  391.     pass Demodulator {
  392.         VertexShader = PostProcessVS;
  393.         PixelShader = PS_Demodulator;
  394.         RenderTarget = tArtifactColors_Demodulator;
  395.     }
  396.     pass Final {
  397.         VertexShader = PostProcessVS;
  398.         PixelShader = PS_Final;
  399.     }
  400. }
RAW Paste Data
Pastebin PRO Summer Special!
Get 60% OFF on Pastebin PRO accounts!
Top