/// LSU EE 4702-1 (Fall 2021), GPU Programming
//

 /// See demo-10-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"

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


 /// Declare Uniform Variables
//
layout ( binding = BIND_BULGE_INFO ) uniform Buldge_Info
{
  float bulge_loc;
  float bulge_dist_thresh;
  float wire_radius;
};

 /// Declare (Bind) Buffer Objects
//
#ifdef BIND_HELIX_COORDS
layout ( binding = BIND_HELIX_COORDS ) buffer Helix_Coord
{ vec4  helix_coord[];  };
#endif

layout ( binding = BIND_TEXUNIT ) uniform sampler2D tex_unit_0;


///
/// Shader Input and Output Variables
///


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

#ifdef LOC_IN_POS
layout (location = LOC_IN_POS) in vec4 pos;
#define gl_Vertex pos
#endif

#ifdef LOC_IN_INT1
layout ( location = LOC_IN_INT1 ) in int helix_index;
#endif

layout (location = LOC_IN_NORMAL, component = 0) in vec3 inNormal;
#define gl_Normal inNormal
layout (location = LOC_IN_TCOOR) in vec2 texcoord;
#define gl_MultiTexCoord0 texcoord

layout (location = 0) out Data
{
  vec3 normal_e;
  vec4 vertex_e;
  vec2 tex_coord;
  int hidx;
};

#endif

#ifdef _FRAGMENT_SHADER_
layout (location = 0) in Data
{
  vec3 normal_e;
  vec4 vertex_e;
  vec2 tex_coord;
  int hidx;
};

layout (location = 0) out vec4 frag_color;
#define gl_FragColor frag_color

#endif


///
/// Shaders
///

#ifdef _VERTEX_SHADER_

#ifdef LOC_IN_POS
void
vs_main_basic()
{
  // Perform basic vertex shading operations.

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

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

  // Copy texture coordinate to output (no need to modify it).
  tex_coord = gl_MultiTexCoord0.xy;
}
#endif

#ifdef BIND_HELIX_COORDS
void
vs_main_helix()
{
  // Perform basic vertex shading operations, but also:
  //   - Compute wire surface coordinates.
  //   - Adjust wire diameter based on location of bulge.
  //
  // Note that this shader only works for the helix.

  // Pass helix index to fragment shader output.
  //
  hidx = helix_index;

  // Set wire radius based on location of bulge.
  //
  float radius = wire_radius * ( hidx == int(bulge_loc) ? 1.2f : 1.0f );

  /// Compute wire surface location by adding normal to helix coordinate.
  //
  vec4 vertex_o;
  vertex_o.xyz = helix_coord[hidx].xyz + radius * gl_Normal;
  vertex_o.w = 1;

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

  // Compute eye-space coordinates for vertex and normal.
  //
  vertex_e = gl_ModelViewMatrix * vertex_o;
  normal_e = normalize(gl_NormalMatrix * gl_Normal);

  // Pass texture coordinate to next stage in pipeline.
  // Only copy x and y components since it's a 2D texture.
  //
  tex_coord = gl_MultiTexCoord0.xy;
}
#endif

#endif


#ifdef _FRAGMENT_SHADER_

void
fs_main_phong()
{
  // Perform lighting, fetch and blend texture, then emit fragment.
  //
  // Note that in the fixed-function pipeline lighting would be performed
  // in the vertex shader.

  // Get filtered texel.
  //
  vec4 texel = texture(tex_unit_0,tex_coord);

  vec4 color = gl_FrontFacing ? color_front : color_back;

  // Compute lighted color of fragment.
  //
  vec4 lighted_color = generic_lighting( vertex_e, color, normal_e);

  // Multiply filtered texel color with lighted color of fragment.
  //
  gl_FragColor = texel * lighted_color;

  // Copy fragment depth unmodified.
  //
  gl_FragDepth = gl_FragCoord.z;
}
#endif