/// LSU EE 4702-1 (Fall 2026), GPU Programming
//
 ///  Helix Rendering Code Without Geometry Shaders
//
//    See demo-10-shdr-geo.cc for helix rendering with geometry shaders.
//
 ///  Plain Helix Rendering
//
//    Vertex shader:    vs_main_basic()
//    Fragment shader:  fs_main_phong()
//
//    Just the helix, no bulge.
//
 ///  Helix Rendering with Crude Bulge
//
//    Vertex shader:    vs_main_helix()
//    Fragment shader:  fs_main_phong()  (Used for plain too).
//
//    Renders the helix with a bulge.
//
// 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"


 /// Declare Uniform Variables Common To Both Shaders
//
layout ( binding = BIND_MATERIAL ) uniform Uni_Material
{
  vec4 color_front, color_back;
};

layout ( binding = BIND_BULGE_INFO ) uniform Buldge_Info
{
  float bulge_loc;
  float bulge_dist_thresh;
  float wire_radius;
  bool opt_texture;
};


#ifdef _VERTEX_SHADER_

// Inputs common to both vertex shaders.
//
layout (location = LOC_IN_NORMAL) in vec3 in_normal_o;
layout (location = LOC_IN_TCOOR) in vec2 in_tex_coord;

// Output data common to both vertex shaders.
//
layout (location = 0) out Data
{
  vec3 normal_e;
  vec4 vertex_e;
  vec2 tex_coord;
  int hidx;
} Out;


#ifdef LOC_IN_POS

 /// Basic Shader:  Get Vertex Coordinate from Pipeline Input

// Only used by vs_main_basic
//
layout (location = LOC_IN_POS) in vec4 in_vertex_o;

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

  // Transform vertex to clip space.
  gl_Position = ut.clip_from_object * in_vertex_o;

  // Compute eye-space vertex coordinate and normal.
  // These are outputs of the vertex shader and inputs to the frag shader.
  //
  Out.vertex_e = ut.eye_from_object * in_vertex_o;
  Out.normal_e = normalize(mat3(ut.eye_from_object) * in_normal_o);

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


#ifdef BIND_HELIX_COORDS

 /// Compute Vertex Coordinates using Helix Information

// Only used by vs_main_helix:
//
layout ( binding = BIND_HELIX_COORDS ) buffer Helix_Coord
{ vec4  helix_coord[];  };
//
layout ( location = LOC_IN_INT1 ) in int in_helix_index;

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.
  //
  Out.hidx = in_helix_index;

  // Set wire radius based on location of bulge.
  //
  float radius =
    wire_radius * ( in_helix_index == 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[in_helix_index].xyz + radius * in_normal_o;
  vertex_o.w = 1;

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

  // Compute eye-space coordinates for vertex and normal.
  //
  Out.vertex_e = ut.eye_from_object * vertex_o;
  Out.normal_e = normalize(mat3(ut.eye_from_object) * in_normal_o);

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

#endif


#ifdef _FRAGMENT_SHADER_

layout ( binding = BIND_TEXUNIT ) uniform sampler2D tex_unit_0;

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

layout (location = 0) out vec4 out_frag_color;

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 = opt_texture ? texture(tex_unit_0,In.tex_coord) : vec4(1,1,1,1);

  vec4 color = gl_FrontFacing ? color_front : color_back;

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

  // Multiply filtered texel color with lighted color of fragment.
  //
  out_frag_color = opt_texture ? texel * lighted_color : lighted_color;
}
#endif