//import <GLUP/current_profile/fragment_shader_preamble.h>
//import <GLUPGLSL/state.h>
//import <GLUP/stdglup.h>
//import <GLUP/current_profile/toggles.h>
//import <GLUP/current_profile/primitive.h>
//import <GLUP/fragment_shader_utils.h>

#ifndef GLUP_NO_GL_CLIPPING
in float gl_ClipDistance[];
#endif

in VertexData {
    vec4 vertex_clip_space;
    vec4 color;
    vec4 tex_coord;
#if GLUP_PRIMITIVE_DIMENSION==2
    vec3 normal;
#endif
    vec4 mesh_tex_coord;
} FragmentIn;


bool is_triangle(in vec4 mesh_tex_coord) {
    if(
        !glupIsEnabled(GLUP_CLIPPING) ||
        GLUP.clipping_mode != GLUP_CLIP_SLICE_CELLS
    ) {
        switch(glup_primitive) {
        case GLUP_TRIANGLES:
            return true;
        case GLUP_QUADS:
            return false;
        case GLUP_TETRAHEDRA:
            return true;
        case GLUP_HEXAHEDRA:
            return false;
        }
    }
    return (
        (mesh_tex_coord.x +
         mesh_tex_coord.y +
         mesh_tex_coord.z +
         mesh_tex_coord.w) < 1.5
    );
}

float edge_factor(in vec4 mesh_tex_coord) {
    if(is_triangle(mesh_tex_coord)) {
        return edge_factor3(mesh_tex_coord.xyz);
    } else {
        return edge_factor4(mesh_tex_coord);
    }
}

vec4 glup_draw_mesh(in vec4 color, in vec4 mesh_tex_coord) {
    return mix(
        GLUP.mesh_color, color, edge_factor(mesh_tex_coord)
    );
}

void main() {

#ifdef GLUP_GL_ES
#ifndef GLUP_NO_GL_CLIPPING
    if(glupIsEnabled(GLUP_CLIPPING) && (gl_ClipDistance[0] < 0.0)) {
        discard;
    }
#endif
#endif

    if(glupIsEnabled(GLUP_PRIMITIVE_FILTERING)) {
        glup_primitive_filter(gl_PrimitiveID);
    }

    if(glupIsEnabled(GLUP_PICKING)) {
        glup_FragColor = glup_picking(gl_PrimitiveID);
        return;
    }

    vec4 result;
    if(glupIsEnabled(GLUP_VERTEX_COLORS)) {
        result = FragmentIn.color;
    } else {
        result = gl_FrontFacing ? GLUP.front_color : GLUP.back_color;
    }

    if(glupIsEnabled(GLUP_TEXTURING) && !glupIsEnabled(GLUP_NORMAL_MAPPING)) {
        result = glup_texturing(result, FragmentIn.tex_coord);
    }
    if(glupIsEnabled(GLUP_LIGHTING)) {
        vec3 N;
        if(
            glupIsEnabled(GLUP_TEXTURING) &&
            glupIsEnabled(GLUP_NORMAL_MAPPING)
        ){
            N = glup_texturing(vec4(1.0,1.0,1.0,1.0), FragmentIn.tex_coord).xyz;
            N = N-vec3(0.5,0.5,0.5);
            N = normalize(GLUP.normal_matrix*N);
            if(!gl_FrontFacing) {
                N = -N;
            }
        } else {
#if GLUP_PRIMITIVE_DIMENSION==2
            if(glupIsEnabled(GLUP_VERTEX_NORMALS)) {
                N = normalize(FragmentIn.normal);
                if(!gl_FrontFacing) {
                    N = -N;
                }
            } else
#endif
            {
                vec3 U = dFdx(FragmentIn.vertex_clip_space.xyz);
                vec3 V = dFdy(FragmentIn.vertex_clip_space.xyz);

                mat3 M = transpose(
                    mat3(
                        GLUP.projection_matrix[0].xyz,
                        GLUP.projection_matrix[1].xyz,
                        GLUP.projection_matrix[2].xyz
                    )
                );

// I do not know why it is reversed, to be checked
// (maybe it is just my test program that does not
// have the same transform orientation, but then I
// do not understand why it gives the same result as
// the desktop version with GLUPES2...)
#ifdef GLUP_GL_ES
                N = normalize(M*cross(U,V));
#else
                N = -normalize(M*cross(U,V));
#endif
            }
        }
        result = glup_lighting(result, N);
    }
    if(glupIsEnabled(GLUP_DRAW_MESH)) {
        result = glup_draw_mesh(result, FragmentIn.mesh_tex_coord);
    }
    glup_FragColor = result;
    glup_alpha_discard();
}
