Back to shaders

Shader test bench

Auto Colors Histogram.fs

vidvox-isf-files color glsl runnable fragment MIT
Source
runnable fragment

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

Code

uniform sampler2D inputImage;
uniform sampler2D sourceHistogram;
uniform int colorMode;
uniform int colorAdjustment;
uniform float maxGain;
uniform float threshold;
uniform float timeSmoothing;
precision mediump float;
/*
{
  "CATEGORIES" : [
    "Color Adjustment", "Histogram"
  ],
  "DESCRIPTION" : "",
  "ISFVSN" : "2",
  "INPUTS" : [
    {
      "NAME" : "inputImage",
      "TYPE" : "image"
    },
    {
      "NAME" : "sourceHistogram",
      "TYPE" : "image"
    },
	{
		"DEFAULT": 0,
		"LABEL": "Normalization Mode",
		"LABELS": [
			"Average",
			"Darker",
			"Brighter",
			"RGB"
		],
		"NAME": "colorMode",
		"TYPE": "long",
		"VALUES": [
			0,
			1,
			2,
			3
		]
	},
	{
		"DEFAULT": 1,
		"LABEL": "Adjustment Type",
		"LABELS": [
			"Contrast",
			"Gamma"
		],
		"NAME": "colorAdjustment",
		"TYPE": "long",
		"VALUES": [
			0,
			1
		]
	},
    {
      "NAME" : "maxGain",
      "TYPE" : "float",
      "MAX" : 8,
      "DEFAULT" : 2,
      "MIN" : 1
    },
    {
      "NAME" : "threshold",
      "TYPE" : "float",
      "MAX" : 1.0,
      "DEFAULT" : 0.02,
      "MIN" : 0.0
    },
    {
      "NAME" : "timeSmoothing",
      "TYPE" : "float",
      "MAX" : 1.0,
      "DEFAULT" : 0.0,
      "MIN" : 0.0
    }
  ],
  "PASSES" : [
    {
      "WIDTH" : "2",
      "TARGET" : "minmax",
      "HEIGHT" : "1"
    },
    {
      "WIDTH" : "2",
      "TARGET" : "smoothedminmax",
      "HEIGHT" : "1",
      "PERSISTENT": true,
      "FLOAT": true
    },
    {

    }
  ],
  "CREDIT" : "VIDVOX"
}
*/

float minChannel (vec3 c)	{
	float	tmpVal = c.r;
	if (c.g < tmpVal)
		tmpVal = c.g;
	if (c.b < tmpVal)
		tmpVal = c.b;
	return tmpVal;
}

float maxChannel (vec3 c)	{
	float	tmpVal = c.r;
	if (c.g > tmpVal)
		tmpVal = c.g;
	if (c.b > tmpVal)
		tmpVal = c.b;
	return tmpVal;
}


void main()	{
	vec4		returnMe = vec4(0.0);
	if (PASSINDEX==0)	{
		//float		minOrMax = ((gl_FragCoord.xy / u_resolution.xy).x < 0.5) ? 0.0 : 1.0;
		vec4		accum = vec4(0.0);
		//	go through each pixel of sourceHistogram
		//		find the darkest and brightest for each color channel
		if ((gl_FragCoord.xy / u_resolution.xy).x < 0.5)	{
			returnMe.a = 1.0;
			for(int i=0;i<256;++i)	{
				vec4	histo = texture2D(sourceHistogram, (vec2(float(i) / u_resolution.xy),0.5));
				accum += histo;
				if (returnMe.r == 0.0)	{
					if (accum.r > threshold)	{
						returnMe.r = float(i)/255.0;
					}
				}
				if (returnMe.g == 0.0)	{
					if (accum.g > threshold)	{
						returnMe.g = float(i)/255.0;
					}
				}
				if (returnMe.b == 0.0)	{
					if (accum.b > threshold)	{
						returnMe.b = float(i)/255.0;
					}
				}
				if ((returnMe.r != 0.0)&&(returnMe.g != 0.0)&&(returnMe.b != 0.0))	{
					break;
				}
			}
		}
		else	{
			returnMe = vec4(1.0);
			for(int i=255;i>=0;--i)	{
				vec4	histo = texture2D(sourceHistogram, (vec2(float(i) / u_resolution.xy),0.5));
				accum += histo;
				if (returnMe.r == 1.0)	{
					if (accum.r > threshold)	{
						returnMe.r = float(i)/255.0;
					}
				}
				if (returnMe.g == 1.0)	{
					if (accum.g > threshold)	{
						returnMe.g = float(i)/255.0;
					}
				}
				if (returnMe.b == 1.0)	{
					if (accum.b > threshold)	{
						returnMe.b = float(i)/255.0;
					}
				}
				if ((returnMe.r != 1.0)&&(returnMe.g != 1.0)&&(returnMe.b != 1.0))	{
					break;
				}
			}
		}
	}
	else if (PASSINDEX==1)	{
		vec4		freshPixel = texture2D(minmax, (gl_FragCoord.xy) / u_resolution.xy);
		vec4		stalePixel = texture2D(smoothedminmax, (gl_FragCoord.xy) / u_resolution.xy);
		returnMe = mix(freshPixel,stalePixel,timeSmoothing);
		
		if (colorMode == 0)	{
			//	Average
			returnMe = vec4((returnMe.r + returnMe.g + returnMe.b) / 3.0);
		}
		else if (colorMode == 1)	{
			//	we want to subtract the biggest and maximize the spread
			//	find the brightest rgb channel
			float	tmpVal = maxChannel(returnMe.rgb);
			returnMe = vec4(tmpVal);
		}
		else if (colorMode == 2)	{
			//	we want to subtract the smallest and minimize the spread
			//	find the darkest rgb channel in min
			float	tmpVal = minChannel(returnMe.rgb);
			returnMe = vec4(tmpVal);
		}
	}
	else if (PASSINDEX==2)	{
		returnMe = IMG_THIS_PIXEL(inputImage);
		vec4	minVal = texture2D(smoothedminmax, (vec2(0.5,0.5) / u_resolution.xy));
		vec4	maxVal = texture2D(smoothedminmax, (vec2(1.5,0.5) / u_resolution.xy));
		
		if (colorAdjustment == 0)	{
			vec4	contrastVal = (colorMode == 1) ? (maxVal - minVal) : 1.0 / (maxVal - minVal);
		
			if (colorMode == 1)	{
				float	iMaxGain = 1.0 / maxGain;
				if (contrastVal.r < iMaxGain)
					contrastVal.r = iMaxGain;

				if (contrastVal.g < iMaxGain)
					contrastVal.g = iMaxGain;
		
				if (contrastVal.b < iMaxGain)
					contrastVal.b = iMaxGain;
			}
			else	{
				if (contrastVal.r > maxGain)
					contrastVal.r = maxGain;

				if (contrastVal.g > maxGain)
					contrastVal.g = maxGain;
		
				if (contrastVal.b > maxGain)
					contrastVal.b = maxGain;
			}
		
			returnMe.r = (returnMe.r - minVal.r) * contrastVal.r;
			returnMe.g = (returnMe.g - minVal.g) * contrastVal.g;
			returnMe.b = (returnMe.b - minVal.b) * contrastVal.b;
		}
		else if (colorAdjustment == 1)	{
			//	the input gamma range is 0.0-1.0 (normalized).  the actual gamma range i want to use is 0.0 - 5.0.
			//	however, actual gamma 0.0-1.0 is just as interesting as actual gamma 1.0-5.0, so we scale the normalized input to match...
			vec4	realGamma = (colorMode == 1) ? 1.0 / (maxVal - minVal) - 1.0 : 1.0 / (maxVal - minVal) - 0.5;
			
			if (realGamma.r > maxGain)
				realGamma.r = maxGain;

			if (realGamma.g > maxGain)
				realGamma.g = maxGain;
	
			if (realGamma.b > maxGain)
				realGamma.b = maxGain;
			
			float	iMaxGain = 1.0 / maxGain;
			if (realGamma.r < iMaxGain)
				realGamma.r = iMaxGain;

			if (realGamma.g < iMaxGain)
				realGamma.g = iMaxGain;
	
			if (realGamma.b < iMaxGain)
				realGamma.b = iMaxGain;
			
			returnMe.rgb = pow(returnMe.rgb, vec3(1.0/realGamma));
		}
	}
	
	gl_FragColor = returnMe;
}