#version 460
#extension GL_GOOGLE_include_directive : enable
#include <light.h>
#include <transform.h>
#include "shdr-common.h"
#include "shdr-generic-lighting.h"
layout ( binding = BIND_UNI_COMMON ) uniform UC
{
  Shdr_Uni_Common uc;
};
bvec2 debug_bool = bvec2( bool(uc.debug_bool.x), bool(uc.debug_bool.y) );
float debug_float = uc.debug_float;
layout ( binding = BIND_BALLS_POS ) buffer Balls_Pos { vec4 balls_pos[]; };
#ifdef _VERTEX_SHADER_
 layout ( location = LOC_IN_INT2 ) in ivec2 in_indices;
layout ( location = 0 ) out Data_to_GS
{
                  vec4 vertex_e[2][2];    vec4 vertex_c[2][2];  
        vec2 texCoord[2];
  vec3 normal_e[2];
      vec3 radial_e;  };
void
vs_main_lines()
{
  const float spiral_radius = 0.5;
  const float omega = 10;
  const int bidx = in_indices.x;    const int ti = in_indices.y;    
    const int radial_idx = bidx * uc.opt_segments + ti;
  const float delta_t = 1.0 / uc.opt_segments;
    const float t = float(ti) * delta_t;
  const float theta = delta_t * radial_idx * omega;
  vec3 pos1 = balls_pos[bidx-1].xyz;
  vec3 pos2 = balls_pos[bidx].xyz;
  vec3 v12 = pos2.xyz - pos1.xyz;
      vec3 ax =
    normalize(v12.x == 0 ? vec3(0,v12.z,-v12.y) : vec3(v12.y,-v12.x,0));
      vec3 ay = normalize(cross(v12,ax));
  vec3 vx = ax * spiral_radius;
  vec3 vy = ay * spiral_radius;
      vec3 p = pos1 + t * v12;
      vec3 radial = vx * cos(theta) + vy * sin(theta);
  vec3 p_outer = p + radial;
  const float inner_frac = 0.5;
  vec3 p_inner = p + inner_frac * radial;
      vec3 tangial = -omega * vx * sin(theta) + omega * vy * cos(theta);
  vec3 tang = v12 + tangial;
  vec3 tang_inner = v12 + inner_frac * tangial;
  vec3 norm = normalize(cross(radial,tang));
  vec3 norm_inner = normalize(cross(radial,tang_inner));
          
  vec3 v12n = normalize(v12);
  vec3 depth_vector = 0.1f * v12n;
      vec3 pos_o[2][2];
  pos_o[0][0] = p_inner;
  pos_o[0][1] = p_outer;
  pos_o[1][0] = p_inner + depth_vector;
  pos_o[1][1] = p_outer + depth_vector;
      for ( int l=0; l<2; l++ )
    for ( int r=0; r<2; r++ )
      {
        vec4 position_o = vec4( pos_o[l][r], 1 );
        vertex_c[l][r] = gl_ModelViewProjectionMatrix * position_o;
        vertex_e[l][r] = gl_ModelViewMatrix * position_o;
      }
  normal_e[0] = gl_NormalMatrix * norm_inner;
  normal_e[1] = gl_NormalMatrix * norm;
      float tex_zoom = 0.5;
    
  const float du = 0.5 * tex_zoom / uc.chain_length;
  const float u = float(bidx) * du;
  texCoord[0].x = texCoord[1].x = tex_zoom * t;
  texCoord[0].y = 0.18 + u;
  texCoord[1].y = 0.18 + u + du;
  radial_e = gl_NormalMatrix * radial;
}
#endif
#ifdef _GEOMETRY_SHADER_
layout ( location = 0 ) in Data_to_GS
{
      
  vec4 vertex_e[2][2];    vec4 vertex_c[2][2];    vec2 texCoord[2];
  vec3 normal_e[2];
  vec3 radial_e;  } In[];
layout ( location = 0 ) out Data_to_FS
{
  vec3 normal_e;
  vec4 vertex_e;
  vec2 texCoord;
  flat int is_edge;  };
 layout ( lines ) in;
 layout ( triangle_strip, max_vertices = 16 ) out;
void
gs_main_lines()
{
            
      for ( int level=0; level<2; level++ )             {
      for ( int theta=0; theta<2; theta++ )
        {
          for ( int r=0; r<2; r++ )                         {
              normal_e       = In[theta].normal_e[r];
              vertex_e       = In[theta].vertex_e[level][r];
              gl_Position    = In[theta].vertex_c[level][r];
              texCoord       = In[theta].texCoord[r];
              is_edge = 0;
              EmitVertex();
            }
        }
      EndPrimitive();               }
              for ( int r=0; r<2; r++ )                         {
      for ( int theta=0; theta<2; theta++ )
        {
          for ( int level=0; level<2; level++ )             {
              normal_e    = r==0 ? -In[theta].radial_e : In[theta].radial_e;
              vertex_e    = In[theta].vertex_e[level][r];
              gl_Position = In[theta].vertex_c[level][r];
              is_edge = 1;
              EmitVertex();
            }
        }
      EndPrimitive();               }
}
#endif
#ifdef _FRAGMENT_SHADER_
layout ( location = 0 ) in Data_to_FS
{
  vec3 normal_e;
  vec4 vertex_e;
  vec2 texCoord;
  flat int is_edge;
};
layout ( binding = BIND_TEXUNIT ) uniform sampler2D tex_unit_0;
layout ( location = 0 ) out vec4 frag_color;
void
fs_main()
{
      vec4 color =
    bool(is_edge) ? uc.color_edge :
    gl_FrontFacing ? uc.color_front : uc.color_back;
      vec4 texel = bool(is_edge) ? vec4(1,1,1,1) : texture(tex_unit_0,texCoord);
      bool hole = texel.r + texel.g + texel.b < 0.05;
  if ( hole ) discard;
      frag_color = texel * generic_lighting(vertex_e, color, normalize(normal_e));
}
#endif