#ifndef VEC_H
#define VEC_H

#include "aliases.h"

typedef struct {
  i32 x;
  i32 y;
} vec2i_t;

typedef struct {
  f32 x;
  f32 y;
} vec2f_t;

typedef struct {
  i32 x;
  i32 y;
  i32 z;
} vec3i_t;

typedef struct {
  f32 x;
  f32 y;
  f32 z;
} vec3f_t;

typedef struct {
  i32 x;
  i32 y;
  i32 z;
  i32 w;
} vec4i_t;

typedef struct {
  f32 x;
  f32 y;
  f32 z;
  f32 w;
} vec4f_t;

typedef struct {
  vec3f_t row0;
  vec3f_t row1;
  vec3f_t row2;
} mat3x3f_t;

typedef struct {
  vec4f_t row0;
  vec4f_t row1;
  vec4f_t row2;
} mat3x4f_t;

typedef struct {
  vec4f_t row0;
  vec4f_t row1;
  vec4f_t row2;
  vec4f_t row3;
} mat4x4f_t;

#define vec_add(T, v1, v2) vec_add_##T(v1, v2)
#define vec_sub(T, v1, v2) vec_sub_##T(v1, v2)
#define vec_mul(T, v1, v2) vec_mul_##T(v1, v2)
#define vec_mul_num(T, v1, num) vec_mul_num_##T(v1, num)
#define vec_div_num(T, v1, num) vec_div_num_##T(v1, num)
#define vec_dot(T, v1, v2) vec_dot_##T(v1, v2)
#define vec_magnitude(T, v) vec_magnitude_##T(v)
#define vec_unit(T, v) vec_unit_##T(v)

vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2);
vec2i_t vec_sub_vec2i_t(vec2i_t v1, vec2i_t v2);
vec2i_t vec_mul_vec2i_t(vec2i_t v1, vec2i_t v2);
vec2i_t vec_mul_num_vec2i_t(vec2i_t v1, i32 num);
vec2i_t vec_div_num_vec2i_t(vec2i_t v1, i32 num);
i32 vec_dot_vec2i_t(vec2i_t v1, vec2i_t v2);
i32 vec_magnitude_vec2i_t(vec2i_t v);
vec2i_t vec_unit_vec2i_t(vec2i_t v);

vec2f_t vec_add_vec2f_t(vec2f_t v1, vec2f_t v2);
vec2f_t vec_sub_vec2f_t(vec2f_t v1, vec2f_t v2);
vec2f_t vec_mul_vec2f_t(vec2f_t v1, vec2f_t v2);
vec2f_t vec_mul_num_vec2f_t(vec2f_t v1, f32 num);
vec2f_t vec_div_num_vec2f_t(vec2f_t v1, f32 num);
f32 vec_dot_vec2f_t(vec2f_t v1, vec2f_t v2);
f32 vec_magnitude_vec2f_t(vec2f_t v);
vec2f_t vec_unit_vec2f_t(vec2f_t v);

vec3i_t vec_add_vec3i_t(vec3i_t v1, vec3i_t v2);
vec3i_t vec_sub_vec3i_t(vec3i_t v1, vec3i_t v2);
vec3i_t vec_mul_vec3i_t(vec3i_t v1, vec3i_t v2);
vec3i_t vec_mul_num_vec3i_t(vec3i_t v1, i32 num);
vec3i_t vec_div_num_vec3i_t(vec3i_t v1, i32 num);
i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2);
i32 vec_magnitude_vec3i_t(vec3i_t v);
vec3i_t vec_unit_vec3i_t(vec3i_t v);

vec3f_t vec_add_vec3f_t(vec3f_t v1, vec3f_t v2);
vec3f_t vec_sub_vec3f_t(vec3f_t v1, vec3f_t v2);
vec3f_t vec_mul_vec3f_t(vec3f_t v1, vec3f_t v2);
vec3f_t vec_mul_num_vec3f_t(vec3f_t v1, f32 num);
vec3f_t vec_div_num_vec3f_t(vec3f_t v1, f32 num);
f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2);
f32 vec_magnitude_vec3f_t(vec3f_t v);
vec3f_t vec_unit_vec3f_t(vec3f_t v);
vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation);

vec4i_t vec_add_vec4i_t(vec4i_t v1, vec4i_t v2);
vec4i_t vec_sub_vec4i_t(vec4i_t v1, vec4i_t v2);
vec4i_t vec_mul_vec4i_t(vec4i_t v1, vec4i_t v2);
vec4i_t vec_mul_num_vec4i_t(vec4i_t v1, i32 num);
vec4i_t vec_div_num_vec4i_t(vec4i_t v1, i32 num);
i32 vec_dot_vec4i_t(vec4i_t v1, vec4i_t v2);
i32 vec_magnitude_vec4i_t(vec4i_t v);
vec4i_t vec_unit_vec4i_t(vec4i_t v);

vec4f_t vec_add_vec4f_t(vec4f_t v1, vec4f_t v2);
vec4f_t vec_sub_vec4f_t(vec4f_t v1, vec4f_t v2);
vec4f_t vec_mul_vec4f_t(vec4f_t v1, vec4f_t v2);
vec4f_t vec_mul_num_vec4f_t(vec4f_t v1, f32 num);
vec4f_t vec_div_num_vec4f_t(vec4f_t v1, f32 num);
f32 vec_dot_vec4f_t(vec4f_t v1, vec4f_t v2);
f32 vec_magnitude_vec4f_t(vec4f_t v);
vec4f_t vec_unit_vec4f_t(vec4f_t v);

mat4x4f_t get_translation_matrix(vec3f_t translation);
mat4x4f_t get_rotation_matrix(vec3f_t rotation);
mat4x4f_t get_scaling_matrix(vec3f_t scale);
mat3x3f_t get_rotation_mat3x3f(vec3f_t rotation);
vec3f_t mul_mat3x4f_by_vec4f(mat3x4f_t mat, vec4f_t vec);
mat3x4f_t mul_mat3x4f_by_mat4x4f(mat3x4f_t mat1, mat4x4f_t mat2);
vec4f_t mul_mat4x4f_by_vec4f(mat4x4f_t mat, vec4f_t vec);
mat4x4f_t mul_mat4x4f(mat4x4f_t mat1, mat4x4f_t mat2);

#endif // !VEC_H