Advertisement
Guest User

Artifact Colors (NTSC)

a guest
Jul 6th, 2017
471
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.33 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement