/// LSU EE 4702-1 (Fall 2021), GPU Programming
//
 /// Fragment Shader / Phong Shading Demonstration

 /// See demo-09-shader.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"


#ifdef BIND_MATERIAL
#define USE_MATERIAL_COLOR
#endif

layout (binding = BIND_MATERIAL ) uniform Uni_Material
{
  vec4 color_front, color_back;
} ub;

#ifdef BIND_MAT_COLOR
layout (binding = BIND_MAT_COLOR ) uniform Uni
{
  vec4 material_color;
};
#endif

#ifdef BIND_COLORS
layout (binding = BIND_COLORS ) buffer C { vec4 colors[]; };
#endif

///
/// Vertex-Shader Only Code -- "Lighting" Program
///


// 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_NORMAL) in vec3 in_normal;

layout (location = LOC_IN_TCOOR) in vec2 in_tcoor;

#ifndef USE_MATERIAL_COLOR
layout (location = LOC_IN_COLOR) in vec4 in_color;
#endif

// 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 texcoord;
} GLiO; // Generic Lighting Output Block

#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 texcoord;
} GLiI; // Generic Lighting Input Block

layout (location = 0) out vec4 frag_color;

#endif

 // Entry Point for Vertex Shader Code
//
#ifdef _VERTEX_SHADER_
void
vs_main_classic()
{
  /// Pre-Defined Outputs
  //
  // gl_Position, gl_FrontColor, etc.
  //
  // (storage qualifier "out")

  /// Pre-Defined Uniforms 
  //
  // gl_ModelViewMatrix, gl_NormalMatrix, gl_ModelViewProjectionMatrix, ..
  //
  // (storage qualifier uniform) (Compatibility Profile)
  // See OGSL Spec 4.6 Section 7.4.1

  // Transform vertex coordinate to clip space.
  gl_Position = gl_ModelViewProjectionMatrix * in_vertex;

  // Compute eye-space coordinates for vertex and normal.
  //
  vec4 vertex_e = gl_ModelViewMatrix * in_vertex;
  vec3 normal_e = normalize(gl_NormalMatrix * in_normal);

#ifdef USE_MATERIAL_COLOR
  vec4 our_color = ub.color_front;
#else
  vec4 our_color = in_color;
#endif

#ifdef BIND_COLORS
  our_color = colors[ gl_VertexIndex & 0x1f ];
#endif

  // Call our lighting routine to compute the lighted color of this
  // vertex.
  //
  GLiO.color = generic_lighting(vertex_e,our_color,normal_e);

  // Copy texture coordinate to output (no need to modify it).
  // Only copy x and y components since it's a 2D texture.
  //
  GLiO.texcoord.xy = in_tcoor;
}
#endif

#ifdef _FRAGMENT_SHADER_
void
fs_main_classic()
{
  // Note: gl_Color in fragment shader is either gl_FrontColor or gl_BackColor
  // in vertex shader.

  // Get filtered texel.
  //
  vec4 texel = texture(tex_unit_0,GLiI.texcoord.xy);

  // Multiply filtered texel color with lighted color of fragment.
  //
  frag_color = texel * ( gl_FrontFacing ? GLiI.color : vec4(1,0,0,1) );
}
#endif


///
/// Vertex & Fragment Shader Code
///


#ifdef _VERTEX_SHADER_
void
vs_main_phong()
{
  // Transform vertex to clip space.
  gl_Position = gl_ModelViewProjectionMatrix * in_vertex;

  // Compute eye-space vertex coordinate and normal.
  // These are outputs of the vertex shader and inputs to the frag shader.
  //
  GLiO.vertex_e = gl_ModelViewMatrix * in_vertex;
  GLiO.normal_e = normalize(gl_NormalMatrix * in_normal);

  // Copy color to output unmodified. Lighting calculations will
  // be performed in the fragment shader.
  //
#ifndef USE_MATERIAL_COLOR
  gl_BackColor = gl_FrontColor = in_color;
#endif

  // Copy texture coordinate to output (no need to modify it).
  GLiO.texcoord.xy = in_tcoor;
}
#endif

#ifdef _FRAGMENT_SHADER_
void
fs_main_phong()
{
  // Note: gl_Color in fragment shader is either gl_FrontColor or gl_BackColor
  // in vertex shader.

  // Get filtered texel.
  //
  vec4 texel = texture(tex_unit_0,GLiI.texcoord.xy);

#ifdef USE_MATERIAL_COLOR
#ifdef BIND_MAT_COLOR
  vec4 front_color = material_color;
#else
  vec4 front_color = ub.color_front;
#endif
#else
  vec4 front_color = GLiI.color;
#endif

  vec4 our_color = gl_FrontFacing ? front_color : vec4(1,0,0,1);

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

  // Multiply filtered texel color with lighted color of fragment.
  //
  frag_color = texel * lighted_color;
}
#endif