#define diagonal3(m) vec3((m)[0].x, (m)[1].y, m[2].z)
#define projMAD(m, v) (diagonal3(m) * (v) + (m)[3].xyz)

vec3 ScreenToView(vec3 pos) {
    vec4 iProjDiag = vec4(gbufferProjectionInverse[0].x,
                          gbufferProjectionInverse[1].y,
                          gbufferProjectionInverse[2].zw);
    vec3 p3 = pos * 2.0 - 1.0;
    vec4 viewPos = iProjDiag * p3.xyzz + gbufferProjectionInverse[3];
    return viewPos.xyz / viewPos.w;
}

#ifdef VOXY
    vec3 ScreenToViewVoxy(vec3 pos) {
        vec4 iProjDiag = vec4(vxProjInv[0].x,
                              vxProjInv[1].y,
                              vxProjInv[2].zw);
        vec3 p3 = pos * 2.0 - 1.0;
        vec4 viewPos = iProjDiag * p3.xyzz + vxProjInv[3];
        return viewPos.xyz / viewPos.w;
    }
#endif

vec3 ViewToPlayer(vec3 pos) {
    return mat3(gbufferModelViewInverse) * pos + gbufferModelViewInverse[3].xyz;
}

vec3 PlayerToShadow(vec3 pos) {
    vec3 shadowpos = mat3(shadowModelView) * pos + shadowModelView[3].xyz;
    return projMAD(shadowProjection, shadowpos);
}

vec3 ShadowClipToShadowView(vec3 pos) {
    return mat3(shadowProjectionInverse) * pos;
}

vec3 ShadowViewToPlayer(vec3 pos) {
    return mat3(shadowModelViewInverse) * pos;
}

vec3 worldToView(vec3 worldPos) {

    vec4 pos = vec4(worldPos, 0.0);
    pos = gbufferModelView * pos;

    return pos.xyz;
}

#ifdef DISTANT_HORIZONS
    vec3 ScreenToViewDH(vec3 pos) {
        vec4 iProjDiag = vec4(dhProjectionInverse[0].x,
                            dhProjectionInverse[1].y,
                            dhProjectionInverse[2].zw);
        vec3 p3 = pos * 2.0 - 1.0;
        vec4 viewPos = iProjDiag * p3.xyzz + dhProjectionInverse[3];
        return viewPos.xyz / viewPos.w;
    }
#endif
