/// LSU EE 4702-1 (Fall 2023), GPU Programming
//
 /// Homework 4 -- SOLUTION
 //
 //  Modified this file and hw04.cc.
 //  Assignment: https://www.ece.lsu.edu/gpup/2023/hw04.pdf
 //  Solution:   https://www.ece.lsu.edu/gpup/2023/hw04_sol.pdf

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

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

layout ( binding = BIND_UNI_COMMON ) uniform Common_Uniform
{
  Shdr_Uni_Common com;
};

bool opt_tryout1 = bool(com.tryout.x);
bool opt_tryout2 = bool(com.tryout.y);
float opt_tryoutf = com.tryoutf.x;

const int TX_None = 0, TX_Orig = 1, TX_Square = 2, TX_Circle = 3;

layout ( binding = BIND_HW04 ) uniform HW_04
{
  vec4 color;
  int opt_texture;
  /// SOLUTION -- Problem 3b
  float r_scale_factor, omega;
};

#ifdef _VERTEX_SHADER_

layout ( location = LOC_IN_POS ) in vec4 in_vertex_o;
layout ( location = LOC_IN_TCOOR ) in vec2 in_tex_coor;

// Interface block for vertex shader output / geometry shader input.
//
layout ( location = 0 ) out Data_to_GS
{
  vec4 vertex_o;
  vec2 tex_coor;
} Out;

void
vs_main()
{
  Out.vertex_o = in_vertex_o;
  Out.tex_coor = in_tex_coor;
}


#endif

#ifdef _GEOMETRY_SHADER_

layout ( location = 0 ) in Data_to_GS
{
  vec4 vertex_o;
  vec2 tex_coor;
} In[];

layout ( location = 0 ) out Data_to_FS
{
  vec3 normal_e;
  vec4 vertex_e;
  vec2 tex_coor;
} Out;

// Type of primitive at geometry shader input.
//
layout ( triangles ) in;

// Type of primitives emitted geometry shader output.
//
layout ( triangle_strip, max_vertices = 3 ) out;



void
gs_main()
{
  // Homework 4 Problem 2: Compute the correct normal.
  /// SOLUTION -- Problem 2
  //
  //  Compute normal by taking the cross product of vectors formed
  //  by the triangle vertices.
  //
  vec3 normal_o =
    cross( In[1].vertex_o.xyz - In[0].vertex_o.xyz,
           In[2].vertex_o.xyz - In[0].vertex_o.xyz );
  vec3 normal_e = mat3( ut.eye_from_object ) * normal_o;

  for ( int i=0; i<3; i++ )
    {
      gl_Position = ut.clip_from_object * In[i].vertex_o;
      Out.normal_e = normal_e;
      Out.vertex_e = ut.eye_from_object * In[i].vertex_o;
      Out.tex_coor = In[i].tex_coor;
      EmitVertex();
    }
  EndPrimitive();
}



#endif


#ifdef _FRAGMENT_SHADER_

#ifdef BIND_TEXUNIT
layout ( binding = BIND_TEXUNIT ) uniform sampler2D tex_unit_0;
#endif

layout ( location = 0 ) in Data_to_FS
{
  vec3 normal_e;
  vec4 vertex_e;
  vec2 tex_coor;
} In;

layout ( location = 0 ) out vec4 out_frag_color;


void
fs_main()
{
  vec4 lit_color = generic_lighting(In.vertex_e, color, In.normal_e);

  if ( opt_texture == TX_None )
    {
      out_frag_color = lit_color;
    }
  else if ( opt_texture == TX_Circle )
    {
      /// SOLUTION -- Problem 3b.
      //
      //  The texture coordinates in In.tex_coor are just the
      //  coordinate of the fragment relative to the wheel center and
      //  scaled so that the outer ring has a radius of 1. Use
      //  In.tex_coor to compute the angle of the ball. The angle is
      //  used to compute the y texture coordinate (assigned to tc).
      //  Compute the distance of In.tex_coor from the center (which
      //  is at the origin) and use that to compute the x texture
      //  coordinate component.

      float dist = length(In.tex_coor);
      float angle = atan(In.tex_coor.y,In.tex_coor.x);
      vec2 tc =
        vec2( ( dist - 1 ) * r_scale_factor,
              angle * omega );

      out_frag_color = lit_color * texture(tex_unit_0,tc);
    }
  else
    {
      out_frag_color = lit_color * texture(tex_unit_0,In.tex_coor);
    }

}


#endif