A new little shader i did (glsl)

ntsc-cgwg-tm runs at 10-15fps. The updated blur looks noop when applied, and if I add fake-crt-geom-potato on top it (the blur) just looks like one pixel ghosting. The best blur so far was the first version, but it didn’t pair well with scanlines on top.

Some shots of my Amiga when I connect via TV modulator and composite. Some notes: image flickers only when chroma or Luma change suddenly on edges on a big margin, eg a gray and then a saturated green, or black and then a bright pixel follows. Colors appear a bit washed out, there is a minimal color bleed. All dithered pixels appear as an extra solid color.

This was invented on a very old PC, slow by today’s standards and it ran fine back in the day. No GPU acceleration required and it does the job just as well as any other solution.

1 Like

If you’re interested and up to the task, what would help a lot is if someone could break out the other Blargg Filters for different systems like NES or Genesis and expose the controls as has been done with the Blargg NTSC SNES Filter.

The problem is not much a performance thing, but that whatever scanlines you add on top breaks the underlying blur as depicted in the above images, Blargg included. I’m not to knowledgeable in the inner workings of the shader pipeline but something is going on that breaks it (edit: on Android).

1 Like

I’ve been using Blargg Filters in conjunction with Simple Scanline Filters for over a decade and more recently with Shaders and this is not what I’ve experienced.

It doesn’t break the blending at all. On the contrary I use it to add blending and transparency to any of my existing shader presets, including the sharpest ones. Scanline emulation is not affected. I’ll post some pics to demonstrate.

1 Like

Yep, sorry, just edited to add “on Android”. DariusG posted a screenshot demonstrating that this is not an issue on PC.

1 Like

Try this and tell me, it’s more of a hack.

#version 110

#define iTime float(FrameCount)
#define pi 3.141592
#if defined(VERTEX)

#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying 
#define COMPAT_ATTRIBUTE attribute 
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 COLOR;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 COL0;
COMPAT_VARYING vec4 TEX0;

vec4 _oPosition1; 
uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;

// compatibility #defines
#define vTexCoord TEX0.xy
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
    gl_Position = MVPMatrix * VertexCoord;
    TEX0.xy = TexCoord.xy;
}

#elif defined(FRAGMENT)

#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;

// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy

#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

#ifdef PARAMETER_UNIFORM
uniform COMPAT_PRECISION float GLITCH;

#else
#define GLITCH 0.1
#endif

#define bend 0.2
#define blurx 0.75
#define blury 0.25


void main()
{

//simple filter, adjustable    
vec2 OGL2pos = vTexCoord*SourceSize.xy;
vec2 cent = floor(OGL2pos)+0.5;
vec2 coords = cent*SourceSize.zw;
vec2 pos; 
pos.x = mix(coords.x, vTexCoord.x, blurx);
pos.y = mix(coords.y, vTexCoord.y, blury);
//////

vec3 res = texture2D(Source,pos).rgb;

vec3 leftp = texture2D(Source,pos-vec2(SourceSize.z,0.0)).rgb;
vec3 rightp = texture2D(Source,pos+vec2(SourceSize.z,0.0)).rgb;
vec3 dither = (leftp+rightp)/2.0;

res =dither*0.5+res*0.5;

vec3 check = texture2D(Source, pos + vec2(SourceSize.z,0.0)).rgb;
float lum = dot(vec3(0.3,0.6,0.1),res);
float lum2 = dot(vec3(0.3,0.6,0.1),check);
if (abs(lum-lum2) > 0.5) res +=0.2*abs(sin(iTime));

FragColor = vec4(res,1.0);
}
#endif
1 Like

Thanks, at this point it probably would be easier to merge the blur and scanlines into the same pass? I’m trying to merge zfast_crt_composite and my zfast_crt_geo. You can give it a try as scanlines is not my field really.

EDIT: @DariusG this is how it looks now, a bit pixelated and blur/ghosting flickers a bit horizontally. Here using zfast_crt_geo but also on fake-crt-geom-potato

Did you use linear on both pass? Here is a comparison with and without (and flickering where ever there is a big luma difference, i wanted to check myself how it works in real conditions on Amiga :wink: )

Here is another job i did, PIxel-Art-AA. Not bad :stuck_out_tongue: Makes that Amstrad games look a bit higher res lol

Not bad on normal resolution too if you combine with something like crt-geom.

#version 110

/*
   Pixel art AA shader by DariusG 2023
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 2 of the License, or (at your option)
   any later version.
*/

#define iTime float(FrameCount)
#define pi 3.141592
#if defined(VERTEX)

#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying 
#define COMPAT_ATTRIBUTE attribute 
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 COLOR;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 COL0;
COMPAT_VARYING vec4 TEX0;

vec4 _oPosition1; 
uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;

// compatibility #defines
#define vTexCoord TEX0.xy
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
    gl_Position = MVPMatrix * VertexCoord;
    TEX0.xy = TexCoord.xy;
}

#elif defined(FRAGMENT)

#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;

// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy

#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

#ifdef PARAMETER_UNIFORM
uniform COMPAT_PRECISION float GLITCH;

#else
#define GLITCH 0.1
#endif

/*
A B C 
D E F
G H I
*/



void main()
{
vec2 pos = vTexCoord;
float dx = SourceSize.z;
float dy = SourceSize.w;

vec3 A = COMPAT_TEXTURE(Source,vTexCoord + vec2(dx,-dy)).rgb;
vec3 B = COMPAT_TEXTURE(Source,vTexCoord + vec2(0.0,-dy)).rgb;
vec3 C = COMPAT_TEXTURE(Source,vTexCoord + vec2(-dx,-dy)).rgb;
vec3 D = COMPAT_TEXTURE(Source,vTexCoord + vec2(dx,0.0)).rgb;
vec3 E = COMPAT_TEXTURE(Source,vTexCoord).rgb;
vec3 F = COMPAT_TEXTURE(Source,vTexCoord + vec2(-dx,0.0)).rgb;
vec3 G = COMPAT_TEXTURE(Source,vTexCoord + vec2(dx,dy)).rgb;
vec3 H = COMPAT_TEXTURE(Source,vTexCoord + vec2(0.0,dy)).rgb;
vec3 I = COMPAT_TEXTURE(Source,vTexCoord + vec2(-dx,dy)).rgb;

#define lumweight vec3(0.3,0.6,0.1)
#define lum(c) dot(lumweight,c)

//pattern type 1
float L = (D == B && B == C && E != D) ? 1.0 : 0.0;
float R = (A == B && A == F && E != F) ? 1.0 : 0.0;
float DL = (D == H && D == I && E != D) ? 1.0 : 0.0;
float DR = (F == G && F == H && E != F) ? 1.0 : 0.0;

E = (L == 1.0 && lum(E)<lum(D) || DL == 1.0 && lum(E)<lum(D)) ? (E+D)/2.0 : E;
E = (R == 1.0 && lum(E)<lum(F) || DR == 1.0 && lum(E)<lum(F)) ? (E+F)/2.0 : E;

//pattern type 2
float GL = (E == H && E == F && E != D) ? 1.0 : 0.0;
float GR = (E == D && E == H && E != F) ? 1.0 : 0.0;
float GDL = (E == B && E == F && E != D) ? 1.0 : 0.0;
float GDR = (E == D && E == B && E != F) ? 1.0 : 0.0;

E = (GL == 1.0 && lum(E)>lum(D) || GDL == 1.0 && lum(E)>lum(D)) ? (E+D)/2.0 : E;
E = (GR == 1.0 && lum(E)>lum(F) || GDR == 1.0 && lum(E)>lum(F)) ? (E+F)/2.0 : E;

//pattern type 3
float SL  = (B == D && B == G && E != D) ? 1.0 : 0.0;
float SR  = (B == F && B == I && E != F) ? 1.0 : 0.0;
float SDL = (H == D && H == A && E != D) ? 1.0 : 0.0;
float SDR = (H == F && H == C && E != F) ? 1.0 : 0.0;

E = (SL == 1.0 && lum(E)<lum(D) || SDL == 1.0 && lum(E)<lum(D)) ? (E+D)/2.0 : E;
E = (SR == 1.0 && lum(E)<lum(F) || SDR == 1.0 && lum(E)<lum(F)) ? (E+F)/2.0 : E;



FragColor = vec4(E,1.0);
}
#endif
3 Likes

It’s fun to experiment and discover new things.

Made a PR to add ‘pixel_art_AA’ and ‘wide_pixels_AA’ on interpolation folder and a preset ‘C64_res_enchance’. Copy from github:

‘Three shaders that will enchance C64 resolution. Works as following: First cut wide pixel in half with ‘wide_pixels_AA’, one part works as AA, then ‘pixel art AA’ where it will detect certain patterns like eq a pixel ‘stairway’ and AA it in certain points. Then apply a pass of ‘crt-sines’ to get that CRT look. ‘Pixel art AA’ works as standalone too in normal resolution games and ‘wide_pixels_AA’ can work as 1st pass on any CRT shader on that C64-Amstrad games.’

5 Likes

So there was a human inside that ship :stuck_out_tongue:

1 Like

Moved shaders to a folder readable without root and checking why that pink tint. This way I corrected all GLES errors on current PR.

Directly loading, correcting and checking the results

3 Likes

@hunterk

Check the difference running pass 2 of ‘ntsc-256’ on Linux and Android. Seems Y has moved to IQ on Android? Pass 1 is identical.

1 Like

Seems this fixes it, don’t ask me why… that’s GLES lol. Instead of yiq2rgb, rgb2yiq and multiply by 2.0 or 2.5 (better)

2 Likes

Did an attempt to convert blargg, what a maze jumping here and there in the code in arrays, pointers etc etc. Probably would be super slow if someone manages to convert that

2 Likes

Don’t forget CPU is way way faster than GPU at calculations. Probably a Pentium 4 would be way faster calculating floats than an average/low end GPU today. At least that’s what I think. Example you load ntsc shader at a low end GPU cellphone and it crawls… Then you load a CPU video filter, blargg that is WAY more complex and runs well.

That blargg filter is probably around or more than 2.000 lines of code ( there are #includes there that expand code a zillion of lines)

2 Likes

That’s some real dedication right there man! I think this something that you just have to have the passion and motivation for and if it’s one person who has that, it might be you.

2 Likes

It’s crazy complex you see 20 lines in main program then it calls a function that calls another function and another and another :stuck_out_tongue_winking_eye:

Way more complex than anything in ntsc shaders folder. Probably 10 or 20 times more code than the most advanced ntsc.

1 Like