#ifndef PROTOTYPE1_SRC_L2_MARIE_GRAPHICS_GEOM_H
#define PROTOTYPE1_SRC_L2_MARIE_GRAPHICS_GEOM_H

#include "../../../gen/l1/geom.h"
#include <math.h>

mat4 marie_translation_mat4(vec3 vec) {
    return mat4_new(
        1, 0, 0, vec.x,
        0, 1, 0, vec.y,
        0, 0, 1, vec.z,
        0, 0, 0, 1
        );
}

mat2 marie_2d_rot_mat2(float a) {
    float cosa = cosf(a);
    float sina = sinf(a);
    return mat2_new(
        cosa, -sina,
        sina, cosa);
}

mat3 marie_3d_rot_mat3(vec3 r, float a) {
    float cosa = cosf(a);
    float sina = sinf(a);
    return mat3_new(
        r.x * r.x * (1 - cosa) + cosa,         r.x * r.y * (1 - cosa) - sina * r.z,   r.x * r.z * (1 - cosa) + sina * r.y,
        r.x * r.y * (1 - cosa) + sina * r.z,   r.y * r.y * (1 - cosa) + cosa,         r.y * r.z * (1 - cosa) - sina * r.x,
        r.x * r.z * (1 - cosa) - sina * r.y,   r.y * r.z * (1 - cosa) + sina * r.x,   r.z * r.z * (1 - cosa) + cosa
    );
}

mat4 marie_mat3_to_mat4(mat3 A) {
    return mat4_new(
        A.x.x, A.y.x, A.z.x, 0,
        A.x.y, A.y.y, A.z.y, 0,
        A.x.z, A.y.z, A.z.z, 0,
        0,     0,     0,     1);
}

mat4 marie_mat3_to_mat4_transposed(mat3 A) {
    return mat4_new(
        A.x.x, A.x.y, A.x.z, 0,
        A.y.x, A.y.y, A.y.z, 0,
        A.z.x, A.z.y, A.z.z, 0,
        0,     0,     0,     1);
}

mat4 marie_3d_rot_mat4(vec3 r, double a) {
    return marie_mat3_to_mat4(marie_3d_rot_mat3(r, a));
}


mat4 marie_perspective_projection_mat4(float right, float top, float near, float far) {
    return mat4_new(
        near/right, 0,        0,                           0,
        0,          -near/top, 0,                           0,
        0,          0,        (far + near) / (near - far), 2 * far * near / (near - far),
        0,          0,        -1,                          0                              );
}

mat4 marie_perspective_projection_fov_mat4(float win_width, float win_height, float fov,
    float spat_frustum_near, float spat_frustum_far) {
    float right = tanf(fov / 2) * spat_frustum_near;
    float top = win_height * right / win_width;
    return marie_perspective_projection_mat4(right, top, spat_frustum_near, spat_frustum_far);
}


mat3 marie_simple_camera_rot_m_basis_in_cols(float yaw, float pitch, float roll) {
    float cos_ya = cosf(yaw);
    float sin_ya = sinf(yaw);
    float cos_pi = cosf(pitch);
    float sin_pi = sinf(pitch);
    float cos_ro = cosf(roll);
    float sin_ro = sinf(roll);
    return (mat3){
        .x = (vec3){cos_ro * cos_ya + sin_ro * sin_pi * sin_ya,  sin_ro * cos_pi, -cos_ro * sin_ya + sin_ro * sin_pi * cos_ya},
        .y = (vec3){-sin_ro * cos_ya + cos_ro * sin_pi * sin_ya, cos_ro * cos_pi, sin_ro * sin_ya + cos_ro * sin_pi * cos_ya},
        .z = (vec3){cos_pi * sin_ya,                             -sin_pi,         cos_pi * cos_ya}
    };
}

vec2 marie_trigonom_circle(float angle) {
    return (vec2){cosf(angle), sinf(angle)};
}

vec3 marie_normal_from_tang_space_gradient(float delt_x, float delta_z) {
    float N = 1 / sqrtf(delt_x * delt_x + delta_z * delta_z + 1);
    return (vec3){-delt_x * N, N, -delta_z * N};
}

mat4 marie_3d_scal_mat4(float scale){
    return mat4_new(scale, 0,     0,     0,
                    0,     scale, 0,     0,
                    0,     0,     scale, 0,
                    0,     0,     0,     1);
}


#endif
