#version 450
// vim: ft=c

struct PosNorm {
    vec4 pos;
    vec4 norm;
};

layout(std430, set = 0, binding = 0) buffer positions_buffer {
	PosNorm posnrm[];
} pos;

layout(push_constant, std430) uniform pc {
  layout(offset=0)    vec4 cam_orig;
  layout(offset=16)   vec4 cam_rot;
  layout(offset=32)   uvec2 screen_res;
};

layout (location = 0) out vec4 normal;
layout (location = 1) out vec4 pos_pre;

const float PI = 3.14159;
// Forgive me for I have sinned
const float TAU = PI*2.0;

void main() {
  // assign outs
  normal = pos.posnrm[gl_VertexIndex].norm;
  pos_pre = pos.posnrm[gl_VertexIndex].pos;

  // define constants
  const float zFar = 100.0;
  const float zNear = 0.1;

  // assign the transformee
  gl_Position = pos.posnrm[gl_VertexIndex].pos;

  mat4 fix_coordinates = mat4(
    -1.0, 0.0, 0.0, 0.0,
    0.0, -1.0, 0.0, 0.0,
    0.0, 0.0, -1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
  );
  mat4 view_orig = mat4(
    1.0, 0.0, 0.0, cam_orig.x,
    0.0, 1.0, 0.0, cam_orig.y,
    0.0, 0.0, 1.0, cam_orig.z,
    0.0, 0.0, 0.0, 1.0
  );
  mat4 view_rot_xz = mat4(
    cos(cam_rot.y), 0.0, sin(cam_rot.y), 0.0,
    0.0, 1.0, 0.0, 0.0,
    -sin(cam_rot.y), 0.0, cos(cam_rot.y), 0.0,
    0.0, 0.0, 0.0, 1.0
  );
  mat4 view_rot_yz = mat4(
    1.0, 0.0, 0.0, 0.0,
    0.0, cos(cam_rot.x), sin(cam_rot.x), 0.0,
    0.0, -sin(cam_rot.x), cos(cam_rot.x), 0.0,
    0.0, 0.0, 0.0, 1.0
  );
  mat4 project_aspect = mat4(
    (float(screen_res.y)/float(screen_res.x)), 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
  );
  mat4 project_znear = mat4(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, -zNear,
    0.0, 0.0, 0.0, 1.0
  );
  mat4 project_div = mat4(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, tan((70.0/2.0)/360.0*TAU), 0.0
  );
  mat4 project_normal = mat4(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0/zFar, 0.0,
    0.0, 0.0, 0.0, 1.0
  );

  // vulkan has inverted screen coordinates
  // but we want regular mesh coordinates
  // gl_Position.xyz *= -1.0
  gl_Position *= fix_coordinates;

  // apply view's origin transformation 
  //gl_Position.xyz += cam_orig.xyz;
  // gl_Position *= view_orig;

  // apply view's xz rotation
  //mat2 xz_rot;
  //xz_rot[0] = vec2(cos(cam_rot.y), -sin(cam_rot.y));
  //xz_rot[1] = vec2(sin(cam_rot.y), cos(cam_rot.y));
  //gl_Position.xz *= inverse(xz_rot);
  gl_Position *= view_rot_xz;

  // apply view's yz rotation
  //mat2 yz_rot;
  //yz_rot[0] = vec2(cos(cam_rot.x), -sin(cam_rot.x));
  //yz_rot[1] = vec2(sin(cam_rot.x), cos(cam_rot.x));
  //gl_Position.yz *= inverse(yz_rot);
  gl_Position *= view_rot_yz;

  // aspect correction
  //gl_Position.x *= (1080.0/1920.0);
  gl_Position *= project_aspect;

  // z near correction
  //gl_Position.z -= zNear;
  gl_Position *= project_znear;

  // division by z
  // has to be assigned by w so that the hardware performs the division AFTER clipping.
  //gl_Position.w = (gl_Position.z*sin(140.0/360.0*TAU));
  gl_Position *= project_div;

  // z normalization
  //gl_Position.z /= zFar;
  gl_Position *= project_normal;

}
