/**
 * Copyright (C) 2013 Stellar Jockeys.
 * All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Stellar Jockeys and its suppliers, if any.  The intellectual and technical
 * concepts contained herein are proprietary to Stellar Jockeys and its suppliers.
 * Dissemination of this information or reproduction of this material is
 * strictly forbidden unless prior written permission is obtained from
 * Stellar Jockeys.
 *
 * @file fragcolorshift.glsl
 * @author Harry Hsiao
 * @date 03/12/2013
 */
#ifndef FRAGCOLORSHIFT_GLSL
#define FRAGCOLORSHIFT_GLSL

/*
 * Converts color to YIQ, performs the color modulation, and converts it back to RGB.
 *
 * YIQ here has I and Q normalized to [-1, 1].
 *
 * NOTES
 * - This assumes linear gamma.
 * - Color shifting is approximate.
 * - Interpolating shifts will probably not give expected results.
 * @see beesbuzz.biz/code/hsv_color_transforms.php (adjusted to use HSL instead)
 *
 * shift = <L' * S * cos(H), L' * S * sin(H), L>
 * H := hue rotation
 * S := saturation multiplier
 * L := lightness adjustment [-1, 1]
 *      where -1 => black; 1 => white; 0 => no change
 * L' = 1 - abs(L)
 *
 * Y update (only L affects the luma):
 * Y' = {  Y * L'       if L <= 0
 *      { (Y * L') + L  else
 * Y' = (Y - Yabs(L)) + abs(L/2) + L/2
 * Y' = Y + abs(L)(1/2 - Y) + L/2
 */
const mat3 TO_YIQ = mat3(0.299,  0.595716 / 0.5957,  0.211456 / 0.5226,
                         0.587, -0.274453 / 0.5957, -0.522591 / 0.5226,
                         0.114, -0.321263 / 0.5957,  0.311135 / 0.5226);
const mat3 TO_RGB = mat3(1.0            ,  1.0            ,  1.0            ,
                         0.9563 * 0.5957, -0.2721 * 0.5957, -1.1070 * 0.5957,
                         0.6210 * 0.5226, -0.6474 * 0.5226,  1.7046 * 0.5226);

vec4 ShiftColor(in vec3 shift, in vec4 color)
{
    vec3 result = TO_YIQ * color.rgb;

    float magnitudeL = abs(shift.z);
    float partial = (0.5 - result.r) * magnitudeL + result.r;
    result.r = shift.z * 0.5 + partial;
    result.gb = mat2(shift.x, shift.y, -shift.y, shift.x) * result.gb;

    return vec4(TO_RGB * result, color.a);
}

#endif // FRAGCOLORSHIFT_GLSL
