#version 450

layout (points) in;
layout (triangle_strip, max_vertices = 4) out;

layout(location = 0) in highp uvec3 Geometry[];

layout(location = 0) out FragmentObj {
    vec3 GeoPos;    // Реальная позиция в мире
    flat uint VoxMTL;    // Материал вокселя
    vec2 LUV;
    flat uint Place;
} Fragment;

layout(push_constant) uniform UniformBufferObject {
    mat4 projview;
    mat4 model;
} ubo;

// struct VoxelVertexPoint {
//     uint32_t 
//         FX : 9, FY : 9, FZ : 9, // Позиция
//         Place : 3,              // Положение распространения xz, xy, zy, и обратные
//         N1 : 1,                 // Не занято
//         LS : 1,                 // Масштаб карты освещения (1м/16 или 1м)
//         TX : 8, TY : 8,         // Размер+1
//         VoxMtl : 16,            // Материал вокселя DefVoxelId_t
//         LU : 14, LV : 14,       // Позиция на карте освещения
//         N2 : 2;                 // Не занято
// };

void main() {
    vec4 baseVec = vec4(
        float(Geometry[0].x & 0x1ff) / 16.f,
        float((Geometry[0].x >> 9) & 0x1ff) / 16.f,
        float((Geometry[0].x >> 18) & 0x1ff) / 16.f,
        1
    );

    vec2 size = vec2(
        float(Geometry[0].y & 0xff)+1,
        float((Geometry[0].y >> 8) & 0xff)+1
    );

    uint voxMTL = ((Geometry[0].y >> 16) & 0xffff);
    vec2 luv = vec2(float(Geometry[0].z & 0x3fff)+0.5f, float((Geometry[0].z >> 14) & 0x3fff)+0.5f);
    int place = int(Geometry[0].x >> 27) & 0x7;

    // Стартовая вершина
    vec4 tempVec = baseVec;
    tempVec = ubo.model*tempVec;
    Fragment.GeoPos = vec3(tempVec);
    Fragment.VoxMTL = voxMTL;
    Fragment.LUV = luv;
    Fragment.Place = place;
    gl_Position = ubo.projview*tempVec;
    EmitVertex();
    

    switch(place) {
    case 0: // xz
        tempVec = baseVec;
        tempVec.z += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(0, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, 0);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec.z += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        break;
    case 1: // xy
        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, 0);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(0, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        break;
    case 2: // zy
        tempVec = baseVec;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(0, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.z += size.x / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, 0);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.z += size.x / 16.f;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        break;
    case 3: // xz inv
        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, 0);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.z += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(0, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec.z += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        break;
    case 4: // xy inv
        tempVec = baseVec;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(0, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, 0);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.x += size.x / 16.f;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        break;
    case 5: // zy inv
        tempVec = baseVec;
        tempVec.z += size.x / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, 0);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(0, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        tempVec = baseVec;
        tempVec.z += size.x / 16.f;
        tempVec.y += size.y / 16.f;
        tempVec = ubo.model*tempVec;
        Fragment.GeoPos = tempVec.xyz;
        Fragment.VoxMTL = voxMTL;
        Fragment.LUV = luv+vec2(size.x, size.y);
        Fragment.Place = place;
        gl_Position = ubo.projview*tempVec;
        EmitVertex();

        break;
    default:
        break;
    }

    EndPrimitive();
}  
