#version 330 core
in uint xy_packed;
in uint zy_packed;
in uint ij;

uniform int color_mode;
uniform float max_distance;
uniform float point_size;
uniform int use_rgb_mode;

uniform mat4 mvp;

out float v_color_cursor;
flat out int v_ij_raw;

const uint IJ_INVALID   = 0xBC00BC00u;
const uint IJ_HIGHLIGHT  = 0x40004000u;

int signExtend21(uint v) {
    v &= 0x1FFFFFu;
    return (v & 0x100000u) != 0u ? int(v | 0xFFE00000u) : int(v);
}

vec3 decodeXYZ(uint w0, uint w1) {
    int xm = signExtend21(w0);
    int ym = signExtend21((w0 >> 21) | ((w1 & 0x3FFu) << 11));
    int zm = signExtend21(w1 >> 10);
    return vec3(float(xm), float(ym), float(zm)) * 0.001;
}

float halfToFloat(uint h) {
    uint e = (h >> 10) & 0x1Fu;
    if (e == 0u) return uintBitsToFloat((h & 0x8000u) << 16);
    if (e == 31u) return uintBitsToFloat(((h & 0x8000u) << 16) | 0x7F800000u);
    return uintBitsToFloat(((h & 0x8000u) << 16) | ((e + 112u) << 23) | ((h & 0x3FFu) << 13));
}

void main(void)
{
    vec3 xyz = decodeXYZ(xy_packed, zy_packed);
    v_ij_raw = int(ij);

    float i_val, j_val;
    if (use_rgb_mode == 1) {
        if (ij == IJ_INVALID) {
            gl_Position = vec4(0.0, 0.0, 0.0, 0.0);
            v_color_cursor = -1.0;
            return;
        }
        i_val = 0.5;
        j_val = 0.5;
    } else {
        i_val = halfToFloat(ij & 0xFFFFu);
        j_val = halfToFloat(ij >> 16);
    }

    if(i_val < 0.0) {
        gl_Position = vec4(0.0, 0.0, 0.0, 0.0);
        v_color_cursor = -1.0;
        return;
    }
    gl_Position = mvp * vec4(xyz, 1.0);
    if (color_mode == 0) {
        v_color_cursor = i_val;
    } else if (color_mode == 1) {
        v_color_cursor = length(xyz) / max_distance;
    } else if (color_mode == 2) {
        v_color_cursor = j_val;
    } else if (color_mode == 3) {
        if ( i_val >= 0.0 && i_val <= 1.0)
            v_color_cursor = 1.0 - i_val;
        else
            v_color_cursor = i_val;
    } else if (color_mode == 4) {
        if ( j_val >= 0.0 && j_val <= 1.0)
            v_color_cursor = 1.0 - j_val;
        else
            v_color_cursor = j_val;
    } else {
        v_color_cursor = 0.0;
    }
    gl_PointSize = point_size;
}
