#version 330
// compatibility
#define float4x4 mat4x4
#define float4 vec4
#define float3 vec3
#define float2 vec2

const float EPS = 0.001;
const int MAX_ITER = 128;

uniform vec2 u_resolution;
out vec4 fragColor;

struct sdQuery {
    float value;
    int obj_id;
};

float sdCube(vec3 p, vec3 b) {
    p = abs(p) - b;
    return length(max(p, 0.0)) + min(max(p.x, max(p.y, p.z)), 0.0);
}

float sdSphere(vec3 p, float r) {
    return length(p) - r;
}

float sdCappedCylinder( vec3 p, float r, float h )
{
    vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(r,h);
    return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}

float sdVerticalCapsule( vec3 p, float h, float r )
{
    p.y -= clamp( p.y, 0.0, h );
    return length( p ) - r;
}
float sdTorus( vec3 p, vec2 t )
{
    vec2 q = vec2(length(p.xz)-t.x,p.y);
    return length(q)-t.y;
}

sdQuery sd(vec3 p) {
    sdQuery qry;
    qry.value = 100000000.0;
    qry.obj_id = -1;
    <SDF_BLOCK>
    return qry;
}

vec3 nrm(vec3 p) {
    vec2 d = vec2(EPS, 0.0);
    return normalize(vec3(
        sd(p + d.xyy).value - sd(p - d.xyy).value,
        sd(p + d.yxy).value - sd(p - d.yxy).value,
        sd(p + d.yyx).value - sd(p - d.yyx).value
    ));
}

vec4 materialColor(int obj_id) {
    <COLOR_BLOCK>
    return vec4(1.0);
}

vec4 color(vec3 p, int obj_id) {
    vec3 normal = nrm(p);
    vec3 light_dir = normalize(vec3(0.5, 0.8, -0.6));
    float light = 0.2 + 0.8 * max(dot(normal, light_dir), 0.0);
    vec4 base = materialColor(obj_id);
    return vec4(base.rgb * light, base.a);
}

vec4 march(vec3 p, vec3 r) {
    sdQuery qry;
    vec4 col = vec4(0.0);
    for(int i = 0; i < MAX_ITER; ++i) {
        qry = sd(p);
        if(qry.value < EPS){
            col = color(p, qry.obj_id);
            break;
        }
        p += qry.value * r;
    }
    return col;
}

void main() {
    vec2 uv = 2. * (gl_FragCoord.xy / u_resolution - .5) * vec2(u_resolution.x / u_resolution.y, 1.);
    vec3 c_p = vec3(<CAM_POS>);
    vec3 c_z = normalize(vec3(<CAM_DIR>));
    vec3 world_up = abs(c_z.y) > 0.999 ? vec3(0., 0., 1.) : vec3(0., 1., 0.);
    vec3 c_x = normalize(cross(c_z, world_up));
    vec3 c_y = normalize(cross(c_x, c_z));
    mat3 view = mat3(c_x, c_y, c_z);
    vec3 r = normalize(vec3(uv, <CAM_FOCUS>));
    fragColor = march(c_p, view * r);
}
