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

 /// Live Code, From 6 November 2026 Class.
//
// In this live demo vs_main_basic was modified to show the
// bulge.  For this code to work the following change must be
// made to demo-10-shader.cc:
#if 0
@@ -382,7 +382,7 @@ World::init()
   pipe_plain
     .init( vh.qs ).ds_use_texture().ds_set_material().ds_use( uni_light )
     .ds_uniform_use( "BIND_BULGE_INFO", buf_bulge_info )
-    .shader_inputs_info_set<pCoor,pNorm,pTCoor>()
+    .shader_inputs_info_set<int,pCoor,pNorm,pTCoor>()
     .shader_code_set
     ("demo-10-shdr-ngeo.cc",  // File holding shader program.
      "vs_main_basic(); ",     // Name of vertex shader main routine.
#endif

//
// Note that routine vs_main_helix also shows the bulge, but it was
// written in advance.


 /// 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;

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


#ifdef LOC_IN_POS
layout (location = LOC_IN_INT1 ) in int in_idx;


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

layout (location = LOC_IN_POS) in vec4 inn_vertex_o;

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

  /// Live Code -  6 November 2026
  //
  //  Thicken the wire (tube) in the area near the bulge.
  //
  //  bulge_loc:  The bulge location.
  //  in_idx:     The position of the current vertex in the same units
  //                as the bulge. For example, if in_idx == bulge_loc
  //                then the bulge is exactly at this vertex position.

  int current_loc = in_idx;
  float distance = abs( float(in_idx) - bulge_loc );

  // The width of the bulge.
  //
  float dist_th = 2.12;

  bool sufficiently_close = distance <= dist_th;

  // The input vertex was renamed from in_vertex_o to inn_vertex_o so
  // that we could compute a new value of in_vertex_o.
  //
  vec4 in_vertex_o = inn_vertex_o;

  if ( sufficiently_close )
    in_vertex_o.xyz += (dist_th - distance ) * wire_radius * in_normal_o;

  // Data: normal (3), int (1), vertex coord (4)

  //
  /// Live Code - Above. Code below is unchanged.

  // 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










// DON'T LOOK BELOW



#ifdef BIND_HELIX_COORDS

 /// Compute Vertex Coordinates using Helix Information

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;

  // Data Amount:  normal (3)  int (1),  helix_coord (4 but)

  // 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