// Reference:
// https://github.com/facebookresearch/DeepSDF/blob/master/src/ShaderProgram.cpp

#include <pangolin/gl/glsl.h>

constexpr const char* shaderText = R"Shader(
@start vertex
#version 330 core

layout(location = 0) in vec3 vertex;

out vec4 position_world;

uniform mat4 MVP;

void main(){
    gl_Position =  MVP * vec4(vertex,1);
    position_world = vec4(vertex,1);
}

@start geometry
#version 330

layout ( triangles ) in;
layout ( triangle_strip, max_vertices = 3 ) out;

in vec4 position_world[];

out vec3 normal_camera;
out vec3 normal_world;
out vec4 xyz_world;
flat out int face_id;

uniform mat4 V;

void main()
{
    vec3 A = position_world[1].xyz - position_world[0].xyz;
    vec3 B = position_world[2].xyz - position_world[0].xyz;
    vec3 normal = normalize(cross(A,B));
    vec3 normal_cam = (V * vec4(normal,0)).xyz;


    gl_Position = gl_in[0].gl_Position;
    normal_camera = normal_cam;
    normal_world = normal;
    xyz_world = position_world[0];
    face_id = gl_PrimitiveIDIn;
    EmitVertex();

    gl_Position = gl_in[1].gl_Position;
    normal_camera = normal_cam;
    normal_world = normal;
    xyz_world = position_world[1];
    face_id = gl_PrimitiveIDIn;

    EmitVertex();

    gl_Position = gl_in[2].gl_Position;
    normal_camera = normal_cam;
    normal_world = normal;
    xyz_world = position_world[2];
    face_id = gl_PrimitiveIDIn;

    EmitVertex();
    EndPrimitive();
}

@start fragment
#version 330 core

in vec3 normal_world;
in vec3 normal_camera;
in vec4 xyz_world;
flat in int face_id;

layout(location = 0) out vec4 FragColorNormal;
layout(location = 1) out vec4 FragColorVertex;


void main(){
    vec3 view_vector = vec3(0,0,1);
    vec3 correct_normal;
    float d = dot(normalize(normal_camera), normalize(view_vector));

    if (abs(d) < 0.001) {
        FragColorVertex = vec4(0,0,0,0);
        FragColorNormal = vec4(0,0,0,0);
        return;
    }
    if (d < 0) {
        // backface
        correct_normal = -normal_world;
    } else {
        correct_normal= normal_world;
    }

    FragColorVertex = xyz_world;
    FragColorVertex.w = face_id + 1.0f;

    FragColorNormal.xyz = normalize(correct_normal);
    FragColorNormal.w = face_id + 1.0f;
}
)Shader";

pangolin::GlSlProgram GetShaderProgram() {
    pangolin::GlSlProgram program;

    program.AddShader(pangolin::GlSlAnnotatedShader, shaderText);
    program.Link();

    return program;
}
