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

 /// See demo-05-more-vulkan.cc for details.


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

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


///
 /// Shader Uniforms
///

// Note: this uniform is also defined in transform.h.
layout ( binding = BIND_TRANSFORM ) uniform Uni_Transform
{
  //   Course Name           OpenGL Name
  mat4 eye_from_object;   // gl_ModelViewMatrix
  mat4 clip_from_eye;     // gl_ProjectionMatrix
  mat4 clip_from_object;  // gl_ModelViewProjectionMatrix
  mat4 object_from_eye;   // gl_ModelViewMatrixInverse
  mat4 eye_from_clip;     // gl_ProjectionMatrixInverse
  mat4 object_from_clip;  // gl_ModelViewProjectionMatrixInverse
};

layout ( binding = BIND_OPTIONS ) uniform Uni_Options
{
  ivec4 tryout;
  vec4 tryoutf;
  int opt_tri_normals;
};

#ifdef _VERTEX_SHADER_

 /// Vertex Shader Inputs
///
layout ( location = LOC_IN_POS ) in vec4 in_vertex;
layout ( location = LOC_IN_NORMAL ) in vec3 in_normal;
layout ( location = LOC_IN_COLOR ) in vec4 in_color;

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

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

  // Compute eye-space vertex coordinate and normal.
  // These are outputs of the vertex shader and inputs to the frag shader.
  //
  Out.vertex_e = eye_from_object * in_vertex;
  Out.normal_e = normalize( mat3(eye_from_object) * in_normal );
  Out.color = in_color;
}
#endif

#ifdef _GEOMETRY_SHADER_

// Indicate type of input primitive expected by geometry shader.
//
layout ( triangles ) in;
layout ( triangle_strip, max_vertices = 3 ) out;

layout (location = 0) in VGF
{
  vec4 vertex_e;
  vec4 color;
  vec3 normal_e;
} In[];

layout (location = 0) out VGF
{
  vec4 vertex_e;
  vec4 color;
  vec3 normal_e;
} Out;

void
gs_main()
{
  /// Geometry Shader
  //
  //  Reads one primitive (triangle in declaration above) ..
  //  .. and writes 0 or more primitives (triangle strips in declaration above).
  //
  //  Inputs: An array. 
  //     User inputs: named In[], above.
  //     Built-In inputs: gl_in[]
  //
  //  Outputs: Not an array.
  //     User outputs: named Out, above.
  //     Built-In output: gl_Position.
  //
  //  Functions for Emitting Triangles
  //     EmitVertex(): Sends the values of output variables to next stage.
  //     EndPrimitive(): Starts a new primitive, such as a new triangle strip.

  // Compute triangle normal, in case we want to override the
  // normal sent as an attribute.
  //
  vec3 v01 = In[0].vertex_e.xyz - In[1].vertex_e.xyz;
  vec3 v02 = In[0].vertex_e.xyz - In[2].vertex_e.xyz;
  vec3 tn = normalize( cross(v01,v02) );

  // Emit one triangle.
  //
  for ( int i=0; i<3; i++ )
    {
      gl_Position = gl_in[i].gl_Position;
      Out.vertex_e = In[i].vertex_e;

      // Always use color of 1st vertex so we can individually color
      // triangles.
      //
      Out.color = In[ tryout.x == 0 ? i : 0 ].color;

      Out.normal_e = opt_tri_normals != 0 ? tn : In[i].normal_e;
      EmitVertex();
    }
  EndPrimitive();
}

#endif

#ifdef _FRAGMENT_SHADER_

 /// Fragment Shader Inputs
//
layout ( location = 0 ) in VGF
{
  vec4 vertex_e;
  vec4 color;
  vec3 normal_e;
} In;

 /// Fragment Shader Output
//
layout ( location = 0 ) out vec4 out_frag_color;

void
fs_main()
{
  vec4 our_color = gl_FrontFacing ? In.color : vec4(1,0,0,1);
  vec4 lighted_color = generic_lighting( In.vertex_e, our_color, In.normal_e );
  out_frag_color = lighted_color;
}
#endif