
////////////////////////////////////////////////////////////////////
//  This file contains GLSL functions that use Meta Controls to transform a scene.
//  File is automatically prepended to GLSL files upon building
// documentation build functions.glsl --polyglot -f md >notes.md
////////////////////////////////////////////////////////////////////

STRING(

vec4 _hueSaturationLEGACY(vec4 color, float hue, float saturation){
	color.rgb = _rgb2hsv(clamp(color.rgb, 0.0, 1.0));
	color.r = color.r+hue;
	color.g = clamp(color.g+saturation, 0.0, 1.0);
	color.rgb = _hsv2rgb(color.rgb);
	return color;
}

vec4 _hueSaturation(vec4 color, float hue, float saturation){
	color.rgb = _rgb2hsv(clamp(color.rgb, 0.0, 1.0));
	color.r = color.r+hue;
	color.g = clamp(color.g*(saturation*abs(saturation)*2.5+1.0), 0.0, 1.0);
	color.rgb = _hsv2rgb(color.rgb);
	return color;
}

// These "apply" functions apply Meta controls to a color
vec4 _applyMaster(vec4 colIn) {
	// clamp so the scene linearly fades to black
	colIn = clamp(colIn, 0.0, 1.0);
	return _brightness(colIn, _Master);
}
       
vec4 _applyBrightness(vec4 colIn){
  return _brightness(colIn, _Brightness);
}

vec4 _applyGamma(vec4 colIn){
  float gamma = _Gamma;
	// extend the range of gamma from 0-2 to 0-3
  if (gamma > 1.0) gamma = 1.0 + (gamma - 1.0)*2.0;
  return _gamma(colIn, gamma);
}

vec4 _applyContrast(vec4 color) {
	float contrast = _Contrast;
	// square contrast above 1 to allow higher contrast
	if (contrast > 1.0) contrast *= contrast;
	return _contrast(color, contrast);
}

vec4 _applyMediaContrast(vec4 color) {
	float contrast = _Media_Contrast;
	// square contrast above 1 to allow higher contrast
	if (contrast > 1.0) contrast *= contrast;
	return _contrast(color, contrast);
}

vec4 _applyMediaGamma(vec4 color) {
	float gamma = _Media_Gamma;
	// square gamma above 1 to allow higher contrast
	if (gamma > 1.0) gamma *= gamma;
	return _gamma(color, gamma);
}

vec4 _applyMediaHueSaturation(vec4 color) {
	return _hueSaturation(color, _Media_Hue, _Media_Saturation);
}

vec4 _applyHueSaturation(vec4 colIn){
	return _hueSaturation(colIn, _Hue, _Saturation);
}

vec4 _applyInvert(vec4 colIn) {
	return _invert(colIn, _Invert);
}

vec4 _applyInvertMedia(vec4 colIn) {
	return _invert(colIn, _Invert_Media);
}

// apply all color meta controls
vec4 _applyColorCorrection(vec4 colIn) {
	return _applyBrightness(_applyGamma(_applyContrast(_applyHueSaturation(_applyInvert(colIn)))));
}

// Recolor based on luminance
// Creates a ramp of black -> low color -> high color -> white
vec4 _applyDichrome(vec4 colIn){
	if (_Limit_Colors < 0.5) return colIn;
	return _dichrome(colIn, _Low_Color, _High_Color);
}

// Shows the left half of the screen mirrored if the MetaControl Vert_Mirror is set to on.
vec2 _applyVerticalMirroring(vec2 posIn){
  if (_Vert_Mirror > 0.5 && posIn.x > 0.5) posIn.x = 1.0-posIn.x;
  return posIn;
}
       
// Shows the left half of the screen mirrored if the MetaControl Vert_Mirror is set to on.
vec2 _applyHorizontalMirroring(vec2 posIn){
  if (_Hor_Mirror > 0.5 && posIn.y < 0.5) posIn.y = 1.0-posIn.y;
  return posIn;
}

// Uses the user preference to determine whether we zoom to fit the screen 
// or black bar to show the whole scene
float _zoomOrFit(float wr, float hr){
	return syn_Prefs_ZoomOrFit > 0.5 ? max(wr, hr) : min(wr, hr);
}

// Determine whether to use a scene's alpha channel or default to 1
vec4 _applyAlpha(vec4 colorIn){
	if (_Alpha_Channel < 0.5) colorIn.a = 1.0;
  return colorIn;
}


// User Media loading functions. One of these functions is used in almost every scene
// to load media with meta controls applied.
// _Media_Scale zoom is applied here (in scene-space) rather than in the media stage,
// so that zooming expands into black bar regions instead of being clipped by the
// media framebuffer bounds.
vec4 _loadMedia() {
	vec2 uv = _applyMediaScale(_correctImageCoords(textureSize(syn_Media, 0)));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return texture(syn_Media, uv);
}

vec4 _loadMedia(vec2 offset) {
	vec2 uv = _applyMediaScale(_correctImageCoords(textureSize(syn_Media, 0)));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return texture(syn_Media, uv + offset);
}

vec4 _textureMedia(vec2 uv) {
	uv = _applyMediaScale(_correctImageCoords(textureSize(syn_Media, 0), uv));
	return texture(syn_Media, uv);
}

vec4 _loadMediaAsMask() {
	// use the raw media syn_UserImage input sampler instead of the affected syn_Media pass,
	// since we don't want the media to have contrast applied to it. For masks, media contrast
	// becomes the threshold value.
	vec2 uv = _applyMediaScale(_flipMediaCoords(_correctImageCoords(textureSize(syn_UserImage, 0))));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return _applyInvertMedia(_imageToMask(texture(syn_UserImage, uv)));
}

vec4 _loadMediaAsMask(vec2 offset) {
	vec2 uv = _applyMediaScale(_flipMediaCoords(_correctImageCoords(textureSize(syn_UserImage, 0))));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return _applyInvertMedia(_imageToMask(texture(syn_UserImage, uv + offset)));
}

vec4 _textureMediaAsMask(vec2 uv) {
	uv = _applyMediaScale(_flipMediaCoords(_correctImageCoords(textureSize(syn_UserImage, 0), uv)));
	return _applyInvertMedia(_imageToMask(texture(syn_UserImage, uv)));
}

// Media loading overloads with mipmap support (lod = level of detail)
vec4 _loadMedia(float lod) {
	vec2 uv = _applyMediaScale(_correctImageCoords(textureSize(syn_Media, int(lod))));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return textureLod(syn_Media, uv, lod);
}

vec4 _loadMedia(vec2 offset, float lod) {
	vec2 uv = _applyMediaScale(_correctImageCoords(textureSize(syn_Media, int(lod))));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return textureLod(syn_Media, uv + offset, lod);
}

vec4 _textureMedia(vec2 uv, float lod) {
	uv = _applyMediaScale(_correctImageCoords(textureSize(syn_Media, int(lod)), uv));
	return texture(syn_Media, uv, lod);
}

vec4 _loadMediaAsMask(float lod) {
	vec2 uv = _applyMediaScale(_flipMediaCoords(_correctImageCoords(textureSize(syn_UserImage, int(lod)))));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return _applyInvertMedia(_imageToMask(textureLod(syn_UserImage, uv, lod)));
}

vec4 _loadMediaAsMask(vec2 offset, float lod) {
	vec2 uv = _applyMediaScale(_flipMediaCoords(_correctImageCoords(textureSize(syn_UserImage, int(lod)))));
	if (_inRange(uv, 0.0, 1.0) < 0.5) return vec4(0.0);
	return _applyInvertMedia(_imageToMask(textureLod(syn_UserImage, uv + offset, lod)));
}

vec4 _textureMediaAsMask(vec2 uv, float lod) {
	uv = _applyMediaScale(_flipMediaCoords(_correctImageCoords(textureSize(syn_UserImage, int(lod)), uv)));
	return _applyInvertMedia(_imageToMask(textureLod(syn_UserImage, uv, lod)));
}


// DEPRECATED FUNCTIONS. These are maintained for backwards compatibility 

// renamed to _applyColorCorrection, which is more accurate
vec4 _applyAllLuminanceCorrections(vec4 colIn){
  return _applyMaster(_applyBrightness(_applyGamma(_applyContrast(_applyHueSaturation(_applyInvert(colIn))))));
}

// replaced by _hueSaturation. Contrast used to use hsv math which is why it was combined with hue and saturation
vec4 _hueSaturationContrast(vec4 colIn, float hue, float saturation, float contrast){
	colIn = _hueSaturation(colIn, hue, saturation);
	colIn = _applyContrast(colIn);
  return colIn;
}

// replaced by _hueSaturation. Contrast used to use hsv math which is why it was combined with hue and saturation
vec4 _hueSaturationContrastLEGACY(vec4 colIn, float hue, float saturation, float contrast){
	colIn = _hueSaturationLEGACY(colIn, hue, saturation);
	colIn = _applyContrast(colIn);
  return colIn;
}

// replaced by _applyHueSaturation and _applyContrast
vec4 _applyHueSaturationContrast(vec4 colIn){
  return _hueSaturationContrast(colIn, _Hue, _Saturation, _Contrast);
}

// renamed to _applyInvertMedia to be more clear
vec4 _invertImage(vec4 colIn){
	return _applyInvertMedia(colIn);
}

// "user image" was renamed to "media" to match the UI
vec4 _loadUserImage() {
  return _loadMedia();
}

vec4 _loadUserImage(vec2 offset) {
  return _loadMedia(offset);
}

vec4 _textureUserImage(vec2 uv) {
  return _textureMedia(uv);
}

vec4 _loadUserImageAsMask() {
  return _loadMediaAsMask();
}

vec4 _loadUserImageAsMask(vec2 offset) {
  return _loadMediaAsMask(offset);
}

vec4 _textureUserImageAsMask(vec2 uv) {
  return _textureMediaAsMask(uv);
}


\n
)
