#version 300 es
#ifdef GL_FRAGMENT_PRECISION_HIGH
  precision highp float;
#else
  precision mediump float;
#endif

// input from vert shadow
in vec3 fN;
in vec3 fL;
in vec3 fE;
in vec2 texCoord;
in vec4 vPos;

// 2d 1 - 999
const int typeSingleColor         =    1;
const int typeText                =    2;
const int typeTextAlpha           =    3;
const int typeDurationBackground  =  100;
const int typePalmMuteBackground  =  101;
const int typeBend                =  102;
const int typeVibrato             =  103;
const int typeTremolo             =  104;
const int typePHBackground        =  105;
const int typeSlide               =  106;
const int typeHudPreviewBackground=  200;
const int typeImage               =  700;
const int typeDraggable           =  801;
const int typeLock                =  802;
const int typeLibraryBackground   =  901;
const int typeLibraryButtonBack   =  902;
const int typeHudButtonBack       =  903;
//3d 1000 - ....
const int type3d                  = 1000;
const int typeSingleColor3d       = 1001;
const int typeBarline3d           = 1009;
const int typeFretboardFret3d     = 1010;
const int typeFretboardString3d   = 1011;
const int typeFretboardInlays     = 1012;
const int typeChord3dEmptyString  = 1101;
const int typeChord3dNote         = 1102;
const int typeChord3dNoteHarmonic = 1103;
const int typeChord3dNoteMute     = 1104;
const int typeChord3dNotePalmMute = 1105;
const int typeChord3dNoteHammeron = 1106;
const int typeChord3dNotePulloff  = 1107;
const int typeChord3dGhostNote    = 1108;
const int typeChord3dBase         = 1109;
const int typeChord3dNoteSustain  = 1110;
const int typeChord3dFlare        = 1111;
const int typeChord3dPalmMute     = 1112;

uniform lowp int objType;

uniform vec4 color;
uniform float alpha;
// texture
uniform sampler2D texSampler0;
uniform float texUmin0;
uniform float texUrange0;
uniform float texVmin0;
uniform float texVrange0;

// special
uniform int draggableState; // 0 - normal, 1 - disabled, 2 - highlighted, 3 - dragged
uniform float highlight;
uniform vec4 highlightColor;

//fog
uniform float fogMin;
uniform float fogMax;

// output
out vec4 FragColor;

void singleColor()
{
    FragColor = color;
}

vec4 getTexColor(int s)
{
    switch(s)
    {
        case 0:
        default:
            return texture(texSampler0, vec2(texCoord.x * texUrange0 + texUmin0, texCoord.y * texVrange0 + texVmin0));
    }
}

void text(float alpha)
{
    vec4 texColor = getTexColor(0);
    if (texColor.a < 0.2f) discard;
    FragColor = color;
    FragColor.a = texColor.a * color.a * alpha;
}

void singleColor3d(bool specLight, bool transparency)
{
    vec3 N = normalize(fN);
    vec3 L = normalize(fL);
    vec3 E = normalize(-fE);
    vec3 H = normalize(L+E);

    float diffuse_intensity=max(dot(N,L),0.0);
    vec4 diffuse_final = (diffuse_intensity+0.1) * color;

    if(specLight) {
        float spec_intensity = pow( max( dot(N,H), 0.0 ), 70.0);
        vec4 spec_final = spec_intensity * vec4(0.5, 0.5, 0.5, 1.0);
        FragColor = diffuse_final + spec_final;
    }
    else {
        FragColor = diffuse_final;
    }
    if(transparency) {
        FragColor.a = color.a;
    }
    else {
        FragColor.a = 1.0;
    }
}

void texture3d(bool specLight, bool transparency)
{
    vec3 N = normalize(fN);
    vec3 L = normalize(fL);
    vec3 E = normalize(-fE);
    vec3 H = normalize(L+E);

    float diffuse_intensity=max(dot(N,L),0.0);
    vec4 textureColor = getTexColor(0);
    if (textureColor.a == 0.0f) discard;
    vec4 diffuse_final = (diffuse_intensity+0.1) * textureColor;

    if(specLight) {
        float spec_intensity = pow( max( dot(N,H), 0.0 ), 70.0);
        vec4 spec_final = spec_intensity * vec4(0.5, 0.5, 0.5, 1.0);
        FragColor = diffuse_final + spec_final;
    }
    else {
        FragColor = diffuse_final;
    }
    if(transparency) {
        FragColor.a = textureColor.a;
    }
    else {
        FragColor.a = 1.0;
    }
}

void colorizedTexture()
{
    float u = texCoord.x > 1.0 ? fract(texCoord.x) : texCoord.x;
    float v = texCoord.y > 1.0 ? fract(texCoord.y) : texCoord.y;
    vec4 texColor = texture(texSampler0, vec2(u * texUrange0 + texUmin0, v * texVrange0 + texVmin0));
    if (texColor.a == 0.0) discard;
    FragColor = color;
    FragColor.a = texColor.a * color.a;
}

void colorizedTextureWithHighlight()
{
    float u = texCoord.x > 1.0 ? fract(texCoord.x) : texCoord.x;
    float v = texCoord.y > 1.0 ? fract(texCoord.y) : texCoord.y;
    vec4 texColor = texture(texSampler0, vec2(u * texUrange0 + texUmin0, v * texVrange0 + texVmin0));
    if (texColor.a == 0.0) discard;
    FragColor.rgb = (1.0-highlight) * color.rgb * texColor.rgb + highlightColor.rgb * highlight;
    FragColor.a = texColor.a * color.a;
}

void colorizedTexture3d(bool specLight, bool transparency)
{
    vec3 N = normalize(fN);
    vec3 L = normalize(fL);
    vec3 E = normalize(-fE);
    vec3 H = normalize(L+E);

    float diffuse_intensity=max(dot(N,L),0.0);
    vec4 textureColor = getTexColor(0);
    if (textureColor.a == 0.0f) discard;

    vec4 diffuse_final = (diffuse_intensity+0.1) * color * textureColor;

    if(specLight) {
        float spec_intensity = pow( max( dot(N,H), 0.0f ), 70.0f);
        vec4 spec_final = spec_intensity * vec4(0.5f, 0.5f, 0.5f, 1.0f);
        FragColor = diffuse_final + spec_final;
    }
    else {
        FragColor = diffuse_final;
    }
    if(transparency) {
        FragColor.a = textureColor.a * color.a;
    }
    else {
        FragColor.a = 1.0f;
    }
}


void draggable()
{
    bool border = texCoord.x <= 0.1f || texCoord.y <= 0.1f || texCoord.x >= 0.9f || texCoord.y >= 0.9f;

    switch(draggableState)
    {
        case 1: // disabled
            FragColor = vec4(0.7f, 0.7f, 0.7f, 0.3f);
            break;
        case 2: // highlighted
            FragColor = vec4(0.0f, 0.0f, 5.0f, 0.9f);
            break;
        case 3: // dragged
            FragColor = vec4(0.0f, 0.0f, 5.0f, 0.9f);
            break;
        default: // normal
            FragColor = vec4(0.0f, 0.0f, 5.0f, 0.3f);
    }
    if(border)
        FragColor.a = 1.0f;
}

void sustain() {
    if (vPos.y < 0.0f) discard;
    colorizedTexture3d(true, true);
}

void flare() {
    float u = texCoord.x > 1.0f ? fract(texCoord.x) : texCoord.x;
    float v = texCoord.y > 1.0f ? fract(texCoord.y) : texCoord.y;
    vec4 texColor = texture(texSampler0, vec2(u * texUrange0 + texUmin0, v * texVrange0 + texVmin0));
    texColor.a = texColor.a * alpha;
    if (texColor.a == 0.0f) discard;
    FragColor = texColor;
}

void texture2d()
{
    FragColor = getTexColor(0);
    if (FragColor.a == 0.0f) discard;
}

void texture2dAlpha()
{
    FragColor = getTexColor(0);
    FragColor.a = FragColor.a * alpha;
}

void applyFog()
{
    if (vPos.y > fogMin) {
        float factor = max( (fogMax - vPos.y) / (fogMax - fogMin), 0.0);
        FragColor.rgb = FragColor.rgb * factor;
    }
}

void main()
{
    switch(objType) {
        case typeSingleColor:
            singleColor();
            break;
        case typeSingleColor3d:
            singleColor3d(false, false);
            applyFog();
            break;
        case typeImage:
            texture2d();
            break;
        case typeText:
            text(1.0f);
            break;
        case typeTextAlpha:
            text(alpha);
            break;
        case typeDraggable:
            draggable();
            break;
        case typeDurationBackground:
            colorizedTextureWithHighlight();
            break;
        case typePHBackground:
        case typePalmMuteBackground:
        case typeBend:
        case typeLock:
        case typeVibrato:
        case typeTremolo:
        case typeSlide:
            colorizedTexture();
            break;
        case typeLibraryBackground:
            texture2d();
            break;
        case typeHudPreviewBackground:
            texture2d();
            break;
        case typeHudButtonBack:
        case typeLibraryButtonBack:
            texture2dAlpha();
            break;
        case typeChord3dEmptyString:
        case typeChord3dNote:
        case typeChord3dNoteHarmonic:
        case typeChord3dNoteMute:
        case typeChord3dNotePalmMute:
        case typeChord3dNoteHammeron:
        case typeChord3dNotePulloff:
        case typeFretboardFret3d:
            singleColor3d(true, false);
            applyFog();
            break;
        case typeChord3dPalmMute:
            singleColor3d(true, true);
            applyFog();
            break;
        case typeChord3dGhostNote:
            singleColor3d(false, true);
            break;
        case typeChord3dBase:
            texture3d(true, true);
            applyFog();
            break;
        case typeBarline3d:
            singleColor3d(true, true);
            applyFog();
            break;
        case typeFretboardString3d:
            singleColor3d(false, false);
            break;
        case typeFretboardInlays:
            colorizedTexture3d(false, true);
            break;
        case typeChord3dNoteSustain:
            sustain();
            applyFog();
            break;
        case typeChord3dFlare:
            flare();
            break;
    }
}


