/// LSU EE 4702-1 (Fall 2023), GPU Programming
//
 /// Fragment Shader / Texture Application Variations.

 /// See demo-08-texture.cc for details.


// Specify version of OpenGL Shading Language.
//
#version 460

#extension GL_GOOGLE_include_directive : enable
#include <light.h>
#include <transform.h>
#include "shader-common-generic-lighting.h"

layout ( binding = BIND_TEXTURE_MODE ) uniform Uni_TMode
{
  vec4 tex_env_color;
  int texture_mode;
};

#ifdef BIND_MAT_COLOR
layout ( binding = BIND_MAT_COLOR ) uniform Uni_Material
{
  vec4 color_front, color_back;
};
#endif

// Declare variables for communication between vertex shader
// and fragment shader.
//
#ifdef _VERTEX_SHADER_

layout (location = LOC_IN_POS) in vec4 in_vertex;
layout (location = LOC_IN_TCOOR) in vec2 in_tcoor;

// Declare some outputs as a group. These are grouped together
// because they are used by the generic lighting routine.
//
layout (location = 0) out VF_Generic_Lighting
{
  vec4 vertex_e;
  vec4 color;
  vec3 normal_e;
  vec2 tcoor;
} Out;


#ifdef PIPE_SPHERE

void
vs_main_sphere()
{
  // Transform vertex coordinate to clip space.
  gl_Position = ut.clip_from_object * in_vertex;

  // Compute eye-space coordinates for vertex and normal.
  //
  Out.vertex_e = ut.eye_from_object * in_vertex;

  // Note that for the sphere the object-space coordinate is the normal.
  //
  Out.normal_e = normalize( mat3(ut.eye_from_object) * in_vertex.xyz );

  Out.tcoor = in_tcoor;
}

#else

layout (location = LOC_IN_NORMAL) in vec3 in_normal;
layout (location = LOC_IN_COLOR) in vec4 in_color;

void
vs_main()
{
  // Transform vertex coordinate to clip space.
  gl_Position = ut.clip_from_object * in_vertex;

  // Compute eye-space coordinates for vertex and normal.
  //
  Out.vertex_e = ut.eye_from_object * in_vertex;
  Out.normal_e = normalize( mat3(ut.eye_from_object) * in_normal );
  Out.color = in_color;
  Out.tcoor = in_tcoor;
}

#endif
#endif


#ifdef _FRAGMENT_SHADER_

layout ( binding = BIND_TEXUNIT ) uniform sampler2D tex_unit_0;

layout (location = 0) in VF_Generic_Lighting
{
  vec4 vertex_e;
  vec4 color;
  vec3 normal_e;
  vec2 tcoor;
} In;

layout (location = 0) out vec4 frag_color;

void
fs_main()
{
  // Get filtered texel.
  //
  vec4 texel = texture( tex_unit_0, In.tcoor );

#ifdef LOC_IN_COLOR
  vec4 our_color = gl_FrontFacing ? In.color : vec4(1,0,0,1);
#else
  vec4 our_color = gl_FrontFacing ? color_front : color_back;
#endif

  vec4 lighted_color = generic_lighting( In.vertex_e, our_color, In.normal_e );

  // Based on OpenGL 4.6 Section 16.1
  // C_f, A_f, incoming fragment.
  // C_c, A_c, texture environment color
  // C_p, A_p, output of previous texture processing step or C_f and A_f
  // C_s, A_s, texture source color. (Filtered telex value after swizzling)
  // C_v, A_v, primary color components computed by the texture function.

  switch ( texture_mode ) {
  case FL_NONE: frag_color = lighted_color; break;
  case GL_REPLACE: frag_color = texel; break;
  case GL_MODULATE: frag_color = lighted_color * texel; break;
  case GL_DECAL:
    frag_color.rgb = lighted_color.rgb * ( 1 - texel.a ) + texel.rgb * texel.a;
    frag_color.a = lighted_color.p;
    break;
  case GL_BLEND:
    frag_color.rgb = lighted_color.rgb * ( 1 - texel.rgb )
      + tex_env_color.rgb * texel.rgb;
    frag_color.a = lighted_color.a * texel.a;
    break;
  case GL_ADD:
    frag_color.rgb = lighted_color.rgb + texel.rgb;
    frag_color.a = lighted_color.a * texel.a;
    break;
  default:
    frag_color = vec4(0.5,0.5,0.5,1);
    break;
    }

}
#endif