Back to shaders

Shader test bench

Zooming Feedback.fs

vidvox-isf-files utility glsl runnable fragment MIT
Source

Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.

Code

uniform sampler2D inputImage;
uniform vec2 preShift;
uniform float feedbackLevel;
uniform float rotateAngle;
uniform float zoomLevel;
uniform vec2 zoomCenter;
uniform vec2 feedbackShift;
uniform int invert;
uniform int blendMode;
uniform float blackThresh;
uniform float satLevel;
uniform float colorShift;
precision mediump float;
/*{
    "CATEGORIES": [
        "Retro",
        "Feedback"
    ],
    "CREDIT": "",
    "DESCRIPTION": "Creates a simple zooming feedback loop",
    "INPUTS": [
        {
            "NAME": "inputImage",
            "TYPE": "image"
        },
        {
            "DEFAULT": [
                0.5,
                0.5
            ],
            "MAX": [
                1,
                1
            ],
            "MIN": [
                0,
                0
            ],
            "NAME": "preShift",
            "TYPE": "point2D"
        },
        {
            "DEFAULT": 0.9,
            "MAX": 1,
            "MIN": 0,
            "NAME": "feedbackLevel",
            "TYPE": "float"
        },
        {
            "DEFAULT": 0.5,
            "MAX": 1,
            "MIN": 0,
            "NAME": "rotateAngle",
            "TYPE": "float"
        },
        {
            "DEFAULT": 1.2,
            "MAX": 2,
            "MIN": 0.25,
            "NAME": "zoomLevel",
            "TYPE": "float"
        },
        {
            "DEFAULT": [
                0.5,
                0.5
            ],
            "MAX": [
                1,
                1
            ],
            "MIN": [
                0,
                0
            ],
            "NAME": "zoomCenter",
            "TYPE": "point2D"
        },
        {
            "DEFAULT": [
                0.5,
                0.5
            ],
            "MAX": [
                1,
                1
            ],
            "MIN": [
                0,
                0
            ],
            "NAME": "feedbackShift",
            "TYPE": "point2D"
        },
        {
            "DEFAULT": 0,
            "NAME": "invert",
            "TYPE": "bool"
        },
        {
            "DEFAULT": 3,
            "LABELS": [
                "Add",
                "Over Black",
                "Over Alpha",
                "Max",
                "Under Black",
                "Under Alpha"
            ],
            "NAME": "blendMode",
            "TYPE": "long",
            "VALUES": [
                0,
                1,
                2,
                3,
                4,
                5
            ]
        },
        {
            "DEFAULT": 0.1,
            "MAX": 1,
            "MIN": 0,
            "NAME": "blackThresh",
            "TYPE": "float"
        },
        {
            "DEFAULT": 1,
            "MAX": 2,
            "MIN": 0,
            "NAME": "satLevel",
            "TYPE": "float"
        },
        {
            "DEFAULT": 0,
            "MAX": 1,
            "MIN": 0,
            "NAME": "colorShift",
            "TYPE": "float"
        }
    ],
    "ISFVSN": "2",
    "PASSES": [
        {
            "PERSISTENT": true,
            "TARGET": "feedbackBuffer"
        }
    ]
}
*/


const float pi = 3.14159265359;


vec3 rgb2hsv(vec3 c)	{
	vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
	//vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
	//vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
	vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);
	vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);
	
	float d = q.x - min(q.w, q.y);
	float e = 1.0e-10;
	return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

vec3 hsv2rgb(vec3 c)	{
	vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
	vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
	return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}



void main()	{
	vec2		loc = (gl_FragCoord.xy / u_resolution.xy);
	vec4		inputPixelColor = texture2D(inputImage, loc + (0.5 - (preShift)));
	
	vec4		feedbackPixelColor = vec4(0.0);
	
	//	rotate here if needed
	loc = loc * u_resolution;
	float		r = distance(u_resolution/2.0, loc);
	float		a = atan ((loc.y-u_resolution.y/2.0),(loc.x-u_resolution.x/2.0));

	loc.x = r * cos(a + 2.0 * pi * rotateAngle - pi) + 0.5;
	loc.y = r * sin(a + 2.0 * pi * rotateAngle - pi) + 0.5;
	
	loc = loc / u_resolution + vec2(0.5);
	
	vec2		modifiedCenter = zoomCenter;
	loc.x = (loc.x - modifiedCenter.x)*(1.0/zoomLevel) + modifiedCenter.x;
	loc.y = (loc.y - modifiedCenter.y)*(1.0/zoomLevel) + modifiedCenter.y;
	loc += (0.5 - (feedbackShift));
	
	if ((loc.x < 0.0)||(loc.y < 0.0)||(loc.x > 1.0)||(loc.y > 1.0))	{
		feedbackPixelColor = vec4(0.0);
	}
	else	{
		feedbackPixelColor = texture2D(feedbackBuffer, loc);
	}
	
	feedbackPixelColor.rgb = rgb2hsv(feedbackPixelColor.rgb);
	feedbackPixelColor.r = mod(feedbackPixelColor.r+colorShift,1.0);
	feedbackPixelColor.g *= satLevel;
	
	feedbackPixelColor.rgb = hsv2rgb(feedbackPixelColor.rgb);
	
	if (invert)
		feedbackPixelColor.rgb = 1.0 - feedbackPixelColor.rgb;
	
	if (blendMode == 0)	{
		inputPixelColor = inputPixelColor + feedbackLevel * feedbackPixelColor;
	}
	else if (blendMode == 1)	{
		float		val = inputPixelColor.a * (inputPixelColor.r + inputPixelColor.g + inputPixelColor.b) / 3.0;
		inputPixelColor = (val >= blackThresh) ? inputPixelColor : feedbackLevel * feedbackPixelColor;
		inputPixelColor.a = inputPixelColor.a + feedbackPixelColor.a * feedbackLevel;
	}
	else if (blendMode == 2)	{
		//	apply the alpha to the input pixel as this happens
		inputPixelColor.rgb = inputPixelColor.a * inputPixelColor.rgb + (1.0 - inputPixelColor.a) * feedbackLevel * feedbackPixelColor.rgb;
		inputPixelColor.a = inputPixelColor.a + feedbackPixelColor.a * feedbackLevel;
	}
	else if (blendMode == 3)	{
		inputPixelColor.rgb = max(inputPixelColor.a * inputPixelColor.rgb, feedbackLevel * feedbackPixelColor.rgb);
		inputPixelColor.a = inputPixelColor.a + feedbackPixelColor.a * feedbackLevel;
	}
	else if (blendMode == 4)	{
		float		val = feedbackPixelColor.a * (feedbackPixelColor.r + feedbackPixelColor.g + feedbackPixelColor.b) / 3.0;
		inputPixelColor = (val < blackThresh) ? inputPixelColor.a * inputPixelColor : feedbackLevel * feedbackPixelColor;
		inputPixelColor.a = inputPixelColor.a + feedbackPixelColor.a * feedbackLevel;
	}
	else if (blendMode == 5)	{
		//	apply the alpha to the input pixel as this happens
		inputPixelColor.rgb = (1.0-feedbackPixelColor.a) * inputPixelColor.a * inputPixelColor.rgb + feedbackLevel * feedbackPixelColor.rgb;
		inputPixelColor.a = inputPixelColor.a + feedbackPixelColor.a * feedbackLevel;
	}
	
	gl_FragColor = inputPixelColor;
}