summaryrefslogtreecommitdiff
path: root/src/maths.c
blob: 3a7ecf13f20cb48c8d9f1f435e05c1db4255fcd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <celeritas.h>

vec3 vec3_create(f32 x, f32 y, f32 z) { return (vec3){ x, y, z }; }
vec3 vec3_add(vec3 u, vec3 v) { return (vec3){ .x = u.x + v.x, .y = u.y + v.y, .z = u.z + v.z }; }
vec3 vec3_sub(vec3 a, vec3 b) { return (vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; }
vec3 vec3_mult(vec3 a, f32 s) { return (vec3){ a.x * s, a.y * s, a.z * s }; }
vec3 vec3_div(vec3 a, f32 s) { return (vec3){ a.x / s, a.y / s, a.z / s }; }

f32 vec3_len_squared(vec3 a) { return (a.x * a.x) + (a.y * a.y) + (a.z * a.z); }
f32 vec3_len(vec3 a) { return sqrtf(vec3_len_squared(a)); }
vec3 vec3_negate(vec3 a) { return (vec3){ -a.x, -a.y, -a.z }; }

vec3 vec3_normalise(vec3 a) {
  f32 length = vec3_len(a);
  return vec3_div(a, length);
}

f32 vec3_dot(vec3 a, vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }

vec3 vec3_cross(vec3 a, vec3 b) {
  return (vec3){ .x = a.y * b.z - a.z * b.y, .y = a.z * b.x - a.x * b.z, .z = a.x * b.y - a.y * b.x };
}

vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z, w }; }

f32 quat_dot(quat a, quat b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; }

quat quat_normalise(quat a) {
  f32 length = sqrtf(quat_dot(a, a));  // same as len squared

  return (quat){ a.x / length, a.y / length, a.z / length, a.w / length };
}

quat quat_from_axis_angle(vec3 axis, f32 angle, bool normalize) {
  const f32 half_angle = 0.5f * angle;
  f32 s = sinf(half_angle);
  f32 c = cosf(half_angle);

  quat q = (quat){ s * axis.x, s * axis.y, s * axis.z, c };
  if (normalize) {
    return quat_normalise(q);
  }
  return q;
}

mat4 mat4_ident() { return (mat4){ .data = { 1.0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.0 } }; }

mat4 mat4_translation(vec3 position) {
  mat4 out_matrix = mat4_ident();
  out_matrix.data[12] = position.x;
  out_matrix.data[13] = position.y;
  out_matrix.data[14] = position.z;
  return out_matrix;
}

mat4 mat4_scale(vec3 scale) {
  mat4 out_matrix = mat4_ident();
  out_matrix.data[0] = scale.x;
  out_matrix.data[5] = scale.y;
  out_matrix.data[10] = scale.z;
  return out_matrix;
}

// TODO: double check this
mat4 mat4_rotation(quat rotation) {
  mat4 out_matrix = mat4_ident();
  quat n = quat_normalise(rotation);

  out_matrix.data[0] = 1.0f - 2.0f * n.y * n.y - 2.0f * n.z * n.z;
  out_matrix.data[1] = 2.0f * n.x * n.y - 2.0f * n.z * n.w;
  out_matrix.data[2] = 2.0f * n.x * n.z + 2.0f * n.y * n.w;

  out_matrix.data[4] = 2.0f * n.x * n.y + 2.0f * n.z * n.w;
  out_matrix.data[5] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.z * n.z;
  out_matrix.data[6] = 2.0f * n.y * n.z - 2.0f * n.x * n.w;

  out_matrix.data[8] = 2.0f * n.x * n.z - 2.0f * n.y * n.w;
  out_matrix.data[9] = 2.0f * n.y * n.z + 2.0f * n.x * n.w;
  out_matrix.data[10] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.y * n.y;

  return out_matrix;
}

// mat4 mat4_mult(mat4 lhs, mat4 rhs) {
//   mat4 out_matrix = mat4_ident();

//   const f32* m1_ptr = lhs.data;
//   const f32* m2_ptr = rhs.data;
//   f32* dst_ptr = out_matrix.data;

//   for (i32 i = 0; i < 4; ++i) {
//     for (i32 j = 0; j < 4; ++j) {
//       *dst_ptr = m1_ptr[0] * m2_ptr[0 + j] + m1_ptr[1] * m2_ptr[4 + j] + m1_ptr[2] * m2_ptr[8 + j] +
//                  m1_ptr[3] * m2_ptr[12 + j];
//       dst_ptr++;
//     }
//     m1_ptr += 4;
//   }

//   return out_matrix;
// }
mat4 mat4_mult(mat4 lhs, mat4 rhs) {
  mat4 out_matrix = mat4_ident();

  for (i32 row = 0; row < 4; row++) {
    for (i32 col = 0; col < 4; col++) {
      f32 sum = 0;
      for (i32 i = 0; i < 4; i++) {
        // column-major: first matrix columns × second matrix rows
        sum += lhs.data[row + i * 4] * rhs.data[i + col * 4];
      }
      out_matrix.data[row + col * 4] = sum;
    }
  }

  return out_matrix;
}

mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_z, f32 far_z) {
  f32 half_tan_fov = tanf(fov_radians * 0.5f);
  mat4 out_matrix = { .data = { 0 } };
  out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov);
  out_matrix.data[5] = 1.0f / half_tan_fov;
  out_matrix.data[10] = -((far_z + near_z) / (far_z - near_z));
  out_matrix.data[11] = -1.0f;
  out_matrix.data[14] = -((2.0f * far_z * near_z) / (far_z - near_z));
  return out_matrix;
}

mat4 mat4_look_at(vec3 position, vec3 target, vec3 up) {
  mat4 out_matrix;
  vec3 z_axis;
  z_axis.x = target.x - position.x;
  z_axis.y = target.y - position.y;
  z_axis.z = target.z - position.z;

  z_axis = vec3_normalise(z_axis);
  vec3 x_axis = vec3_normalise(vec3_cross(z_axis, up));
  vec3 y_axis = vec3_cross(x_axis, z_axis);

  out_matrix.data[0] = x_axis.x;
  out_matrix.data[1] = y_axis.x;
  out_matrix.data[2] = -z_axis.x;
  out_matrix.data[3] = 0;
  out_matrix.data[4] = x_axis.y;
  out_matrix.data[5] = y_axis.y;
  out_matrix.data[6] = -z_axis.y;
  out_matrix.data[7] = 0;
  out_matrix.data[8] = x_axis.z;
  out_matrix.data[9] = y_axis.z;
  out_matrix.data[10] = -z_axis.z;
  out_matrix.data[11] = 0;
  out_matrix.data[12] = -vec3_dot(x_axis, position);
  out_matrix.data[13] = -vec3_dot(y_axis, position);
  out_matrix.data[14] = vec3_dot(z_axis, position);
  out_matrix.data[15] = 1.0f;

  return out_matrix;
}