#version 150 core
///shaderType:geometry

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

in vec2 posVO[];
in vec2 texPosVO[];
out vec2 posGO;
out vec2 texPosGO;

uniform uvec2 modelType;

uniform mat4 proj;
uniform mat4 view;
uniform mat4 model;

const vec2 texPosTL = vec2(0.0, 0.0);
const vec2 texPosBL = vec2(0.0, 1.0);
const vec2 texPosTR = vec2(1.0, 0.0);
const vec2 texPosBR = vec2(1.0, 1.0);


void emit(in int i, in vec2 tp) {
    gl_Position = gl_in[i].gl_Position;
    posGO = posVO[i];
    texPosGO = tp;
    EmitVertex();
}
void emit(in int i) {
    emit(i, texPosVO[i]);
}

void emit(in int i, in vec4 height) {
    gl_Position = gl_in[i].gl_Position + height;
    posGO = posVO[i];
    texPosGO = texPosVO[i];
    EmitVertex();
}

void emit(in int i, in int j, in vec4 height) {
    gl_Position = ((gl_in[i].gl_Position + gl_in[j].gl_Position) / 2.0) + height;
    posGO = (posVO[i] + posVO[j]) / 2.0;
    texPosGO = (texPosVO[i] + texPosVO[j]) / 2.0;
    EmitVertex();
}


void main() {
    bool triangle_type = (texPosVO[0].y == 0.0); // tl,bl,tr (true) or bl,tr,br (false)
    vec4 height = proj * view * model * vec4(
        0.0,
        0.0,
        0.03 * float(((modelType.x - 1u) / 2u) + 1u),
        0.0
    ); // no offset here

    if (modelType.x == 0u) { // flat
        emit(0);
        emit(1);
        emit(2);
    } else if ((modelType.x & 1u) == 1u) { // odd -> spike
        if (triangle_type) { // TODO: merge adjacent spikes by looking at the borders in modelType.y?
            emit(1);
            emit(0);
            emit(1, 2, height); // randomized but stable half height?
            emit(2);
        } else {
            emit(0);
            emit(2);
            emit(0, 1, height);
            emit(1);
        }
    } else { // even -> box
        //  6--4       2--0
        //  | /|      /|\ |
        //  |/ |     //| \|
        // 51--3--4 4--3--15
        //  |\ |//     | /|
        //  | \|/      |/ |
        //  0--2       4--6
        if (triangle_type) {
            emit(1, texPosBR); // mirror tex coords at the edges for re-used vertices
            emit(0, texPosTR);
            emit(1, height);
            emit(0, height);
            emit(2, height);
            emit(0, texPosBL);
            emit(2, texPosBR);
        } else {
            emit(1, texPosTL);
            emit(2, texPosBL);
            emit(1, height);
            emit(2, height);
            emit(0, height);
            emit(2, texPosTR);
            emit(0, texPosTL);
        }
    }

    EndPrimitive();
}