A new little shader i did (glsl)

The ntsc encoding if accurate i think it has 910 lines totally horizontally some of them are hblank, hsync (not visible) and more tech stuff that i am not expert at them. So when you use SourceSize is wrong if 1x. At least that’s what i think. You should at least use 640 pixels horiz and ignore the hblank etc. The simple ntsc shaders i wrote use that profile

1 Like

Check these, another write i did, but not passing because that hanning array [ ] needs GLES 3.0 and for the moment i want it to work on 2.0 (one of my cellphones is 2.0 lol). This is the better one with hanning window. 1st is the preset, 2nd is the first pass and 3rd is the 2nd pass. That’s blazing fast more than 500 fps full screen on HD630

shaders = "3"
feedback_pass = "0"
shader0 = "../stock.glsl"
filter_linear0 = "false"
scale_type_x0 = "absolute"
scale_x0 = "640.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "shaders/ntsc-simple/ntsc-mini-0.glsl"
filter_linear1 = "false"
scale_type_x1 = "source"
scale_x1 = "1.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "shaders/ntsc-simple/ntsc-mini-1.glsl"
filter_linear2 = "false"
scale_type_x2 = "source"
scale_x2 = "1.000000"
scale_type_y2 = "source"
scale_y2 = "1.000000"





#version 110

/*
NTSC-mini 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.
*/

#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)

#ifdef PARAMETER_UNIFORM
uniform COMPAT_PRECISION float WHATEVER;
#else
#define WHATEVER 0.0
#endif

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

#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 vTexCoord TEX0.xy
#define Source Texture
#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 compo;
uniform COMPAT_PRECISION float rainbow;

#else
#define compo 1.0
#define rainbow 1.0
#endif

float TAU = 3.1415926/2.0;
mat3 rgb2yiq = mat3(0.299, 0.596, 0.211,
                    0.587,-0.274,-0.523,
                    0.114,-0.322, 0.312);


void main()
{
    vec3 res = COMPAT_TEXTURE(Source,vTexCoord).rgb;
    res *= rgb2yiq;
    float phase = 0.0;
    if (rainbow == 0.0) phase = TAU  * (SourceSize.x * vTexCoord.x+mod(vTexCoord.y*SourceSize.y,3.0));
    else phase = TAU  * (SourceSize.x * vTexCoord.x);
    
    // saturate s-video
    float amp = 1.0; if (compo == 0.0) amp = 2.0;
    float sig = res.y*cos(phase) + res.z*sin(phase) ;
    sig *= amp;
    
    if (compo == 1.0) FragColor = vec4(vec3(res.x+sig),0);
    else FragColor = vec4(vec3(res.x,vec2(sig)),0);
}
#endif




#version 130

#pragma parameter compo "S-Video/Composite" 1.0 0.0 1.0 1.0
#pragma parameter rainbow "Rainbow Effect" 0.0 0.0 1.0 1.0
/*
NTSC-mini 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.
*/

#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)

#ifdef PARAMETER_UNIFORM
uniform COMPAT_PRECISION float WHATEVER;
#else
#define WHATEVER 0.0
#endif

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

#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 vTexCoord TEX0.xy
#define Source Texture
#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 compo;
uniform COMPAT_PRECISION float rainbow;

#else
#define compo 1.0
#define rainbow 1.0
#endif
//Modulator


float PI = 3.1415926;
float TAU = 3.1415926/2.0;
#define FIR 13
mat3 yiq2rgb = mat3(1.000, 1.000, 1.000,
                    0.956,-0.272,-1.106,
                    0.621,-0.647, 1.703);



//  Hann window function
float hann(float n, float N) {
    return 0.5 * (1.0 - cos((TAU*4.0*n)/(N-1.0)));
}

//  Sinc function
float sinc(float x) {
    if (x == 0.0) return 1.0;
    return sin(PI*x) / (PI*x);
}

void main()
{

vec2 ps = vec2(SourceSize.z,0.0);
//  Gather sampling weights
        float weights[FIR];
        float sum = 0.0;
        for (int n=0; n<FIR; n++) {
            weights[n] = hann(float(n), FIR) * sinc(0.25 * float(n-7));
            sum += weights[n];
        }
        
//  Normalize sampling weights
        for (int n=0; n<FIR; n++) {
            weights[n] /= sum;
        }
        
 // Sample composite signal and decode to YIQ
        vec3 res = vec3(0.0);
        for (int n=0; n<FIR; n++) {
            vec2 pos = vTexCoord + float(n-7)*ps;
            float phase = 0.0;
            if (rainbow == 0.0) phase = TAU * (SourceSize.x * pos.x+mod(pos.y*SourceSize.y,3.0));
            else phase = TAU * (SourceSize.x * pos.x);
            res += vec3(1.0, cos(phase), sin(phase)) * COMPAT_TEXTURE(Source, pos).rgb * weights[n];
        }
// Decode to RGB
    res *= yiq2rgb;
    FragColor = vec4(res,0);
}
#endif

1 Like

Ahah, no array make things difficult. Maybe you can try to use vec4s and implement some logic to switch between them with multiple serialized cycles, or maybe is too complicated (does 2.0 support access to vec4 by indexes like vec4[i] at least?).

I precalculate indexes into an array in the vertex shader and brutely pass it as a varying to fragment; I don’t know and don’t want to know what happens nor how the compiler manages that, but it works :slight_smile:

If you look zoomed in image of the above code, you see the artifacting is working on higher resolution than 1 core pixel it just uses the same color, for that i have to investigate more.

no rainbow here

Yup, see the greenish shade on the left side of the head:
Screenshot_20231221_133115

Green is the artifact color that is shaded versus the light brown background; I mean, the effect can be obtained, maybe not 100% properly, but with a good tradeoff, at 1x and with a slight blur on it on a subsequent lighter 2x pass.

1 Like

Funny thing is without any purpose on my code (or any extra code), the artifacts have the colors of the nearest pixel :stuck_out_tongue: eg that brown has red and green artifacts, white has red blue green

Here without rainbow, using the diagonal pattern

Some zx spectrum screenshots I found on the internet

The first two are 48k composite mod, the last two are 128k composite mod.

Here is a quick one pass “ntsc” simulator

#version 110

/*
NTSC-single-pass 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.
*/

#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)

#ifdef PARAMETER_UNIFORM
uniform COMPAT_PRECISION float WHATEVER;
#else
#define WHATEVER 0.0
#endif

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

#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 vTexCoord TEX0.xy
#define Source Texture
#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 compo;
uniform COMPAT_PRECISION float rainbow;

#else
#define compo 1.0
#define rainbow 1.0
#endif


//Modulator

#define F_COL (1.0 / 4.0)
float pi = 3.1415926;
float tau = pi;

mat3 rgb2yiq = mat3(0.299, 0.596, 0.211,
                    0.587,-0.274,-0.523,
                    0.114,-0.322, 0.312);

mat3 yiq2rgb = mat3(1.000, 1.000, 1.000,
                    0.956,-0.272,-1.106,
                    0.621,-0.647, 1.703);

void main()
{
    vec2 ps = vec2(SourceSize.z,0.0);
    float phase = vTexCoord.x*SourceSize.x + vTexCoord.y*SourceSize.y*2.0;
    int FIR = 2;
    vec3 yiq = vec3(0.0);
 
    float sum = 0.0;
    
    for (int i=-FIR; i<FIR+1; i++)
    {
    float p = float(i);
    float w = exp(-0.2*p*p);   
    vec3 res = COMPAT_TEXTURE(Source,vTexCoord+ps*p).rgb*rgb2yiq;
    
    phase = phase + p;
    
    res *= vec3(1.0,0.5*cos(phase*tau),0.5*sin(phase*tau));
    
    // composite signal
    float signal = dot(vec3(1.0),res);
    yiq += vec3(signal*vec3(1.0,cos(phase*tau),sin(phase*tau)))*w;
    sum += w;
    }

    yiq /= sum;
    yiq *= yiq2rgb;

    vec3 clean = COMPAT_TEXTURE(Source,vTexCoord).rgb*0.49;
     clean += COMPAT_TEXTURE(Source,vTexCoord+ps).rgb*0.23;
     clean += COMPAT_TEXTURE(Source,vTexCoord-ps).rgb*0.23;
     clean += COMPAT_TEXTURE(Source,vTexCoord-2.0*ps).rgb*0.025;
     clean += COMPAT_TEXTURE(Source,vTexCoord+2.0*ps).rgb*0.025;
    
    // artifacts strength control
    yiq = yiq*0.3 + clean*0.7;

    FragColor.rgb = yiq;
}
#endif

2 Likes

@Cyber tell me what you think of this after accepted PR :wink: Still looking around the C code and merging stuff tbh, let’s call this “alpha”

3 Likes

Darius, didn’t know about your thread. Just to let you know I really appreciate your work, trying to simplify some shaders for users who can’t run heavier alternatives or don’t want too many options. I see a few have been ported to slang, do you plan to eventually port more of them?

1 Like

Thanks. Tell me which one you want and I will port it to slang.

No shader in particular, I was just asking. But thanks s a lot for your disposition. Just wrote that because I thought it would be interesting to showcase your work for a wider audience. I really mean that I appreciate your effort, it’s interesting, works well and provides freedom of choice for many different users. I helped quite a few people to set up your gdv-mini (which already has a slang version) and they were quite delighted with the results. Until then, they thought shaders were too complicated or needed a powerhouse PC.

1 Like

For now I believe Ntsc-simple is the most useful to update to slang (current slang version is fairly recent). Probably crt-sines too, I wrote that after reading some reddit comments that “there is no light shader with glow”. The rest are mostly up-to-date. Try gdv-mini-ultra-Trinitron, that looks cool too :wink:

That blargg shader is heavy, running tons of passes on each pixel, barely 60 fps on Hd630 laptop. But I can make it more light as an option (reduce passes as a parameter)

2 Likes

Added option to tweak color carrier angle etc, so effectively one can make it look like any system he wants, if he knows how it supposed to look like ofc

5 Likes

No problem, Is there anything specific you would like me to do with it?

Play around tell me what you think. Evaluate lol

That “phase angle” option is effectively changing the “colorburst/pixel clock” frequency (since PI should be constant in reality) so it would look-alike any system if you know how it looks like, except if it has something strange going on.

1 Like

Actual megadrive ntsc shot

Ntsc/ntsc-j has rainbow effect and no dot crawl…

PAL no rainbow effect-dot crawl yes

7 Likes

Also I have that problem on my android phone Are you know how fix it? I like NTSC-Adaptive

Do you notice that the rainbow effect seems to dissipate over the blue water and as it reaches the grass cannot be seen anymore.

While in your example here:

…possibly due to the settings used, it’s much more prominent all the way from the top to the bottom of the screen.

The TV is probably using a comb filter, it cancels chroma better than a simple low pass filter used in the example. NTSC-Blastem is using a comb filter. Low Pass was the crude way done on very early TVs (60s-70s).

If you reduce comb filter strength to 0.0 you have this

3 Likes