1b877906bSopenharmony_ci#ifndef LINMATH_H
2b877906bSopenharmony_ci#define LINMATH_H
3b877906bSopenharmony_ci
4b877906bSopenharmony_ci#include <string.h>
5b877906bSopenharmony_ci#include <math.h>
6b877906bSopenharmony_ci#include <string.h>
7b877906bSopenharmony_ci
8b877906bSopenharmony_ci/* 2021-03-21 Camilla Löwy <elmindreda@elmindreda.org>
9b877906bSopenharmony_ci * - Replaced double constants with float equivalents
10b877906bSopenharmony_ci */
11b877906bSopenharmony_ci
12b877906bSopenharmony_ci#ifdef LINMATH_NO_INLINE
13b877906bSopenharmony_ci#define LINMATH_H_FUNC static
14b877906bSopenharmony_ci#else
15b877906bSopenharmony_ci#define LINMATH_H_FUNC static inline
16b877906bSopenharmony_ci#endif
17b877906bSopenharmony_ci
18b877906bSopenharmony_ci#define LINMATH_H_DEFINE_VEC(n) \
19b877906bSopenharmony_citypedef float vec##n[n]; \
20b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \
21b877906bSopenharmony_ci{ \
22b877906bSopenharmony_ci	int i; \
23b877906bSopenharmony_ci	for(i=0; i<n; ++i) \
24b877906bSopenharmony_ci		r[i] = a[i] + b[i]; \
25b877906bSopenharmony_ci} \
26b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \
27b877906bSopenharmony_ci{ \
28b877906bSopenharmony_ci	int i; \
29b877906bSopenharmony_ci	for(i=0; i<n; ++i) \
30b877906bSopenharmony_ci		r[i] = a[i] - b[i]; \
31b877906bSopenharmony_ci} \
32b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_scale(vec##n r, vec##n const v, float const s) \
33b877906bSopenharmony_ci{ \
34b877906bSopenharmony_ci	int i; \
35b877906bSopenharmony_ci	for(i=0; i<n; ++i) \
36b877906bSopenharmony_ci		r[i] = v[i] * s; \
37b877906bSopenharmony_ci} \
38b877906bSopenharmony_ciLINMATH_H_FUNC float vec##n##_mul_inner(vec##n const a, vec##n const b) \
39b877906bSopenharmony_ci{ \
40b877906bSopenharmony_ci	float p = 0.f; \
41b877906bSopenharmony_ci	int i; \
42b877906bSopenharmony_ci	for(i=0; i<n; ++i) \
43b877906bSopenharmony_ci		p += b[i]*a[i]; \
44b877906bSopenharmony_ci	return p; \
45b877906bSopenharmony_ci} \
46b877906bSopenharmony_ciLINMATH_H_FUNC float vec##n##_len(vec##n const v) \
47b877906bSopenharmony_ci{ \
48b877906bSopenharmony_ci	return sqrtf(vec##n##_mul_inner(v,v)); \
49b877906bSopenharmony_ci} \
50b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_norm(vec##n r, vec##n const v) \
51b877906bSopenharmony_ci{ \
52b877906bSopenharmony_ci	float k = 1.f / vec##n##_len(v); \
53b877906bSopenharmony_ci	vec##n##_scale(r, v, k); \
54b877906bSopenharmony_ci} \
55b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_min(vec##n r, vec##n const a, vec##n const b) \
56b877906bSopenharmony_ci{ \
57b877906bSopenharmony_ci	int i; \
58b877906bSopenharmony_ci	for(i=0; i<n; ++i) \
59b877906bSopenharmony_ci		r[i] = a[i]<b[i] ? a[i] : b[i]; \
60b877906bSopenharmony_ci} \
61b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_max(vec##n r, vec##n const a, vec##n const b) \
62b877906bSopenharmony_ci{ \
63b877906bSopenharmony_ci	int i; \
64b877906bSopenharmony_ci	for(i=0; i<n; ++i) \
65b877906bSopenharmony_ci		r[i] = a[i]>b[i] ? a[i] : b[i]; \
66b877906bSopenharmony_ci} \
67b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_dup(vec##n r, vec##n const src) \
68b877906bSopenharmony_ci{ \
69b877906bSopenharmony_ci	int i; \
70b877906bSopenharmony_ci	for(i=0; i<n; ++i) \
71b877906bSopenharmony_ci		r[i] = src[i]; \
72b877906bSopenharmony_ci}
73b877906bSopenharmony_ci
74b877906bSopenharmony_ciLINMATH_H_DEFINE_VEC(2)
75b877906bSopenharmony_ciLINMATH_H_DEFINE_VEC(3)
76b877906bSopenharmony_ciLINMATH_H_DEFINE_VEC(4)
77b877906bSopenharmony_ci
78b877906bSopenharmony_ciLINMATH_H_FUNC void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b)
79b877906bSopenharmony_ci{
80b877906bSopenharmony_ci	r[0] = a[1]*b[2] - a[2]*b[1];
81b877906bSopenharmony_ci	r[1] = a[2]*b[0] - a[0]*b[2];
82b877906bSopenharmony_ci	r[2] = a[0]*b[1] - a[1]*b[0];
83b877906bSopenharmony_ci}
84b877906bSopenharmony_ci
85b877906bSopenharmony_ciLINMATH_H_FUNC void vec3_reflect(vec3 r, vec3 const v, vec3 const n)
86b877906bSopenharmony_ci{
87b877906bSopenharmony_ci	float p = 2.f * vec3_mul_inner(v, n);
88b877906bSopenharmony_ci	int i;
89b877906bSopenharmony_ci	for(i=0;i<3;++i)
90b877906bSopenharmony_ci		r[i] = v[i] - p*n[i];
91b877906bSopenharmony_ci}
92b877906bSopenharmony_ci
93b877906bSopenharmony_ciLINMATH_H_FUNC void vec4_mul_cross(vec4 r, vec4 const a, vec4 const b)
94b877906bSopenharmony_ci{
95b877906bSopenharmony_ci	r[0] = a[1]*b[2] - a[2]*b[1];
96b877906bSopenharmony_ci	r[1] = a[2]*b[0] - a[0]*b[2];
97b877906bSopenharmony_ci	r[2] = a[0]*b[1] - a[1]*b[0];
98b877906bSopenharmony_ci	r[3] = 1.f;
99b877906bSopenharmony_ci}
100b877906bSopenharmony_ci
101b877906bSopenharmony_ciLINMATH_H_FUNC void vec4_reflect(vec4 r, vec4 const v, vec4 const n)
102b877906bSopenharmony_ci{
103b877906bSopenharmony_ci	float p  = 2.f*vec4_mul_inner(v, n);
104b877906bSopenharmony_ci	int i;
105b877906bSopenharmony_ci	for(i=0;i<4;++i)
106b877906bSopenharmony_ci		r[i] = v[i] - p*n[i];
107b877906bSopenharmony_ci}
108b877906bSopenharmony_ci
109b877906bSopenharmony_citypedef vec4 mat4x4[4];
110b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_identity(mat4x4 M)
111b877906bSopenharmony_ci{
112b877906bSopenharmony_ci	int i, j;
113b877906bSopenharmony_ci	for(i=0; i<4; ++i)
114b877906bSopenharmony_ci		for(j=0; j<4; ++j)
115b877906bSopenharmony_ci			M[i][j] = i==j ? 1.f : 0.f;
116b877906bSopenharmony_ci}
117b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_dup(mat4x4 M, mat4x4 const N)
118b877906bSopenharmony_ci{
119b877906bSopenharmony_ci	int i;
120b877906bSopenharmony_ci	for(i=0; i<4; ++i)
121b877906bSopenharmony_ci		vec4_dup(M[i], N[i]);
122b877906bSopenharmony_ci}
123b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_row(vec4 r, mat4x4 const M, int i)
124b877906bSopenharmony_ci{
125b877906bSopenharmony_ci	int k;
126b877906bSopenharmony_ci	for(k=0; k<4; ++k)
127b877906bSopenharmony_ci		r[k] = M[k][i];
128b877906bSopenharmony_ci}
129b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_col(vec4 r, mat4x4 const M, int i)
130b877906bSopenharmony_ci{
131b877906bSopenharmony_ci	int k;
132b877906bSopenharmony_ci	for(k=0; k<4; ++k)
133b877906bSopenharmony_ci		r[k] = M[i][k];
134b877906bSopenharmony_ci}
135b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_transpose(mat4x4 M, mat4x4 const N)
136b877906bSopenharmony_ci{
137b877906bSopenharmony_ci    // Note: if M and N are the same, the user has to
138b877906bSopenharmony_ci    // explicitly make a copy of M and set it to N.
139b877906bSopenharmony_ci	int i, j;
140b877906bSopenharmony_ci	for(j=0; j<4; ++j)
141b877906bSopenharmony_ci		for(i=0; i<4; ++i)
142b877906bSopenharmony_ci			M[i][j] = N[j][i];
143b877906bSopenharmony_ci}
144b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_add(mat4x4 M, mat4x4 const a, mat4x4 const b)
145b877906bSopenharmony_ci{
146b877906bSopenharmony_ci	int i;
147b877906bSopenharmony_ci	for(i=0; i<4; ++i)
148b877906bSopenharmony_ci		vec4_add(M[i], a[i], b[i]);
149b877906bSopenharmony_ci}
150b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_sub(mat4x4 M, mat4x4 const a, mat4x4 const b)
151b877906bSopenharmony_ci{
152b877906bSopenharmony_ci	int i;
153b877906bSopenharmony_ci	for(i=0; i<4; ++i)
154b877906bSopenharmony_ci		vec4_sub(M[i], a[i], b[i]);
155b877906bSopenharmony_ci}
156b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_scale(mat4x4 M, mat4x4 const a, float k)
157b877906bSopenharmony_ci{
158b877906bSopenharmony_ci	int i;
159b877906bSopenharmony_ci	for(i=0; i<4; ++i)
160b877906bSopenharmony_ci		vec4_scale(M[i], a[i], k);
161b877906bSopenharmony_ci}
162b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_scale_aniso(mat4x4 M, mat4x4 const a, float x, float y, float z)
163b877906bSopenharmony_ci{
164b877906bSopenharmony_ci	vec4_scale(M[0], a[0], x);
165b877906bSopenharmony_ci	vec4_scale(M[1], a[1], y);
166b877906bSopenharmony_ci	vec4_scale(M[2], a[2], z);
167b877906bSopenharmony_ci	vec4_dup(M[3], a[3]);
168b877906bSopenharmony_ci}
169b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_mul(mat4x4 M, mat4x4 const a, mat4x4 const b)
170b877906bSopenharmony_ci{
171b877906bSopenharmony_ci	mat4x4 temp;
172b877906bSopenharmony_ci	int k, r, c;
173b877906bSopenharmony_ci	for(c=0; c<4; ++c) for(r=0; r<4; ++r) {
174b877906bSopenharmony_ci		temp[c][r] = 0.f;
175b877906bSopenharmony_ci		for(k=0; k<4; ++k)
176b877906bSopenharmony_ci			temp[c][r] += a[k][r] * b[c][k];
177b877906bSopenharmony_ci	}
178b877906bSopenharmony_ci	mat4x4_dup(M, temp);
179b877906bSopenharmony_ci}
180b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_mul_vec4(vec4 r, mat4x4 const M, vec4 const v)
181b877906bSopenharmony_ci{
182b877906bSopenharmony_ci	int i, j;
183b877906bSopenharmony_ci	for(j=0; j<4; ++j) {
184b877906bSopenharmony_ci		r[j] = 0.f;
185b877906bSopenharmony_ci		for(i=0; i<4; ++i)
186b877906bSopenharmony_ci			r[j] += M[i][j] * v[i];
187b877906bSopenharmony_ci	}
188b877906bSopenharmony_ci}
189b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_translate(mat4x4 T, float x, float y, float z)
190b877906bSopenharmony_ci{
191b877906bSopenharmony_ci	mat4x4_identity(T);
192b877906bSopenharmony_ci	T[3][0] = x;
193b877906bSopenharmony_ci	T[3][1] = y;
194b877906bSopenharmony_ci	T[3][2] = z;
195b877906bSopenharmony_ci}
196b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z)
197b877906bSopenharmony_ci{
198b877906bSopenharmony_ci	vec4 t = {x, y, z, 0};
199b877906bSopenharmony_ci	vec4 r;
200b877906bSopenharmony_ci	int i;
201b877906bSopenharmony_ci	for (i = 0; i < 4; ++i) {
202b877906bSopenharmony_ci		mat4x4_row(r, M, i);
203b877906bSopenharmony_ci		M[3][i] += vec4_mul_inner(r, t);
204b877906bSopenharmony_ci	}
205b877906bSopenharmony_ci}
206b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 const a, vec3 const b)
207b877906bSopenharmony_ci{
208b877906bSopenharmony_ci	int i, j;
209b877906bSopenharmony_ci	for(i=0; i<4; ++i) for(j=0; j<4; ++j)
210b877906bSopenharmony_ci		M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f;
211b877906bSopenharmony_ci}
212b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate(mat4x4 R, mat4x4 const M, float x, float y, float z, float angle)
213b877906bSopenharmony_ci{
214b877906bSopenharmony_ci	float s = sinf(angle);
215b877906bSopenharmony_ci	float c = cosf(angle);
216b877906bSopenharmony_ci	vec3 u = {x, y, z};
217b877906bSopenharmony_ci
218b877906bSopenharmony_ci	if(vec3_len(u) > 1e-4) {
219b877906bSopenharmony_ci		vec3_norm(u, u);
220b877906bSopenharmony_ci		mat4x4 T;
221b877906bSopenharmony_ci		mat4x4_from_vec3_mul_outer(T, u, u);
222b877906bSopenharmony_ci
223b877906bSopenharmony_ci		mat4x4 S = {
224b877906bSopenharmony_ci			{    0,  u[2], -u[1], 0},
225b877906bSopenharmony_ci			{-u[2],     0,  u[0], 0},
226b877906bSopenharmony_ci			{ u[1], -u[0],     0, 0},
227b877906bSopenharmony_ci			{    0,     0,     0, 0}
228b877906bSopenharmony_ci		};
229b877906bSopenharmony_ci		mat4x4_scale(S, S, s);
230b877906bSopenharmony_ci
231b877906bSopenharmony_ci		mat4x4 C;
232b877906bSopenharmony_ci		mat4x4_identity(C);
233b877906bSopenharmony_ci		mat4x4_sub(C, C, T);
234b877906bSopenharmony_ci
235b877906bSopenharmony_ci		mat4x4_scale(C, C, c);
236b877906bSopenharmony_ci
237b877906bSopenharmony_ci		mat4x4_add(T, T, C);
238b877906bSopenharmony_ci		mat4x4_add(T, T, S);
239b877906bSopenharmony_ci
240b877906bSopenharmony_ci		T[3][3] = 1.f;
241b877906bSopenharmony_ci		mat4x4_mul(R, M, T);
242b877906bSopenharmony_ci	} else {
243b877906bSopenharmony_ci		mat4x4_dup(R, M);
244b877906bSopenharmony_ci	}
245b877906bSopenharmony_ci}
246b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate_X(mat4x4 Q, mat4x4 const M, float angle)
247b877906bSopenharmony_ci{
248b877906bSopenharmony_ci	float s = sinf(angle);
249b877906bSopenharmony_ci	float c = cosf(angle);
250b877906bSopenharmony_ci	mat4x4 R = {
251b877906bSopenharmony_ci		{1.f, 0.f, 0.f, 0.f},
252b877906bSopenharmony_ci		{0.f,   c,   s, 0.f},
253b877906bSopenharmony_ci		{0.f,  -s,   c, 0.f},
254b877906bSopenharmony_ci		{0.f, 0.f, 0.f, 1.f}
255b877906bSopenharmony_ci	};
256b877906bSopenharmony_ci	mat4x4_mul(Q, M, R);
257b877906bSopenharmony_ci}
258b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate_Y(mat4x4 Q, mat4x4 const M, float angle)
259b877906bSopenharmony_ci{
260b877906bSopenharmony_ci	float s = sinf(angle);
261b877906bSopenharmony_ci	float c = cosf(angle);
262b877906bSopenharmony_ci	mat4x4 R = {
263b877906bSopenharmony_ci		{   c, 0.f,  -s, 0.f},
264b877906bSopenharmony_ci		{ 0.f, 1.f, 0.f, 0.f},
265b877906bSopenharmony_ci		{   s, 0.f,   c, 0.f},
266b877906bSopenharmony_ci		{ 0.f, 0.f, 0.f, 1.f}
267b877906bSopenharmony_ci	};
268b877906bSopenharmony_ci	mat4x4_mul(Q, M, R);
269b877906bSopenharmony_ci}
270b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate_Z(mat4x4 Q, mat4x4 const M, float angle)
271b877906bSopenharmony_ci{
272b877906bSopenharmony_ci	float s = sinf(angle);
273b877906bSopenharmony_ci	float c = cosf(angle);
274b877906bSopenharmony_ci	mat4x4 R = {
275b877906bSopenharmony_ci		{   c,   s, 0.f, 0.f},
276b877906bSopenharmony_ci		{  -s,   c, 0.f, 0.f},
277b877906bSopenharmony_ci		{ 0.f, 0.f, 1.f, 0.f},
278b877906bSopenharmony_ci		{ 0.f, 0.f, 0.f, 1.f}
279b877906bSopenharmony_ci	};
280b877906bSopenharmony_ci	mat4x4_mul(Q, M, R);
281b877906bSopenharmony_ci}
282b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_invert(mat4x4 T, mat4x4 const M)
283b877906bSopenharmony_ci{
284b877906bSopenharmony_ci	float s[6];
285b877906bSopenharmony_ci	float c[6];
286b877906bSopenharmony_ci	s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1];
287b877906bSopenharmony_ci	s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2];
288b877906bSopenharmony_ci	s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3];
289b877906bSopenharmony_ci	s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2];
290b877906bSopenharmony_ci	s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3];
291b877906bSopenharmony_ci	s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3];
292b877906bSopenharmony_ci
293b877906bSopenharmony_ci	c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1];
294b877906bSopenharmony_ci	c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2];
295b877906bSopenharmony_ci	c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3];
296b877906bSopenharmony_ci	c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2];
297b877906bSopenharmony_ci	c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3];
298b877906bSopenharmony_ci	c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3];
299b877906bSopenharmony_ci
300b877906bSopenharmony_ci	/* Assumes it is invertible */
301b877906bSopenharmony_ci	float idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] );
302b877906bSopenharmony_ci
303b877906bSopenharmony_ci	T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet;
304b877906bSopenharmony_ci	T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet;
305b877906bSopenharmony_ci	T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet;
306b877906bSopenharmony_ci	T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet;
307b877906bSopenharmony_ci
308b877906bSopenharmony_ci	T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet;
309b877906bSopenharmony_ci	T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet;
310b877906bSopenharmony_ci	T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet;
311b877906bSopenharmony_ci	T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet;
312b877906bSopenharmony_ci
313b877906bSopenharmony_ci	T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet;
314b877906bSopenharmony_ci	T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet;
315b877906bSopenharmony_ci	T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet;
316b877906bSopenharmony_ci	T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet;
317b877906bSopenharmony_ci
318b877906bSopenharmony_ci	T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet;
319b877906bSopenharmony_ci	T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet;
320b877906bSopenharmony_ci	T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet;
321b877906bSopenharmony_ci	T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet;
322b877906bSopenharmony_ci}
323b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_orthonormalize(mat4x4 R, mat4x4 const M)
324b877906bSopenharmony_ci{
325b877906bSopenharmony_ci	mat4x4_dup(R, M);
326b877906bSopenharmony_ci	float s = 1.f;
327b877906bSopenharmony_ci	vec3 h;
328b877906bSopenharmony_ci
329b877906bSopenharmony_ci	vec3_norm(R[2], R[2]);
330b877906bSopenharmony_ci
331b877906bSopenharmony_ci	s = vec3_mul_inner(R[1], R[2]);
332b877906bSopenharmony_ci	vec3_scale(h, R[2], s);
333b877906bSopenharmony_ci	vec3_sub(R[1], R[1], h);
334b877906bSopenharmony_ci	vec3_norm(R[1], R[1]);
335b877906bSopenharmony_ci
336b877906bSopenharmony_ci	s = vec3_mul_inner(R[0], R[2]);
337b877906bSopenharmony_ci	vec3_scale(h, R[2], s);
338b877906bSopenharmony_ci	vec3_sub(R[0], R[0], h);
339b877906bSopenharmony_ci
340b877906bSopenharmony_ci	s = vec3_mul_inner(R[0], R[1]);
341b877906bSopenharmony_ci	vec3_scale(h, R[1], s);
342b877906bSopenharmony_ci	vec3_sub(R[0], R[0], h);
343b877906bSopenharmony_ci	vec3_norm(R[0], R[0]);
344b877906bSopenharmony_ci}
345b877906bSopenharmony_ci
346b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f)
347b877906bSopenharmony_ci{
348b877906bSopenharmony_ci	M[0][0] = 2.f*n/(r-l);
349b877906bSopenharmony_ci	M[0][1] = M[0][2] = M[0][3] = 0.f;
350b877906bSopenharmony_ci
351b877906bSopenharmony_ci	M[1][1] = 2.f*n/(t-b);
352b877906bSopenharmony_ci	M[1][0] = M[1][2] = M[1][3] = 0.f;
353b877906bSopenharmony_ci
354b877906bSopenharmony_ci	M[2][0] = (r+l)/(r-l);
355b877906bSopenharmony_ci	M[2][1] = (t+b)/(t-b);
356b877906bSopenharmony_ci	M[2][2] = -(f+n)/(f-n);
357b877906bSopenharmony_ci	M[2][3] = -1.f;
358b877906bSopenharmony_ci
359b877906bSopenharmony_ci	M[3][2] = -2.f*(f*n)/(f-n);
360b877906bSopenharmony_ci	M[3][0] = M[3][1] = M[3][3] = 0.f;
361b877906bSopenharmony_ci}
362b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f)
363b877906bSopenharmony_ci{
364b877906bSopenharmony_ci	M[0][0] = 2.f/(r-l);
365b877906bSopenharmony_ci	M[0][1] = M[0][2] = M[0][3] = 0.f;
366b877906bSopenharmony_ci
367b877906bSopenharmony_ci	M[1][1] = 2.f/(t-b);
368b877906bSopenharmony_ci	M[1][0] = M[1][2] = M[1][3] = 0.f;
369b877906bSopenharmony_ci
370b877906bSopenharmony_ci	M[2][2] = -2.f/(f-n);
371b877906bSopenharmony_ci	M[2][0] = M[2][1] = M[2][3] = 0.f;
372b877906bSopenharmony_ci
373b877906bSopenharmony_ci	M[3][0] = -(r+l)/(r-l);
374b877906bSopenharmony_ci	M[3][1] = -(t+b)/(t-b);
375b877906bSopenharmony_ci	M[3][2] = -(f+n)/(f-n);
376b877906bSopenharmony_ci	M[3][3] = 1.f;
377b877906bSopenharmony_ci}
378b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f)
379b877906bSopenharmony_ci{
380b877906bSopenharmony_ci	/* NOTE: Degrees are an unhandy unit to work with.
381b877906bSopenharmony_ci	 * linmath.h uses radians for everything! */
382b877906bSopenharmony_ci	float const a = 1.f / tanf(y_fov / 2.f);
383b877906bSopenharmony_ci
384b877906bSopenharmony_ci	m[0][0] = a / aspect;
385b877906bSopenharmony_ci	m[0][1] = 0.f;
386b877906bSopenharmony_ci	m[0][2] = 0.f;
387b877906bSopenharmony_ci	m[0][3] = 0.f;
388b877906bSopenharmony_ci
389b877906bSopenharmony_ci	m[1][0] = 0.f;
390b877906bSopenharmony_ci	m[1][1] = a;
391b877906bSopenharmony_ci	m[1][2] = 0.f;
392b877906bSopenharmony_ci	m[1][3] = 0.f;
393b877906bSopenharmony_ci
394b877906bSopenharmony_ci	m[2][0] = 0.f;
395b877906bSopenharmony_ci	m[2][1] = 0.f;
396b877906bSopenharmony_ci	m[2][2] = -((f + n) / (f - n));
397b877906bSopenharmony_ci	m[2][3] = -1.f;
398b877906bSopenharmony_ci
399b877906bSopenharmony_ci	m[3][0] = 0.f;
400b877906bSopenharmony_ci	m[3][1] = 0.f;
401b877906bSopenharmony_ci	m[3][2] = -((2.f * f * n) / (f - n));
402b877906bSopenharmony_ci	m[3][3] = 0.f;
403b877906bSopenharmony_ci}
404b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_look_at(mat4x4 m, vec3 const eye, vec3 const center, vec3 const up)
405b877906bSopenharmony_ci{
406b877906bSopenharmony_ci	/* Adapted from Android's OpenGL Matrix.java.                        */
407b877906bSopenharmony_ci	/* See the OpenGL GLUT documentation for gluLookAt for a description */
408b877906bSopenharmony_ci	/* of the algorithm. We implement it in a straightforward way:       */
409b877906bSopenharmony_ci
410b877906bSopenharmony_ci	/* TODO: The negation of of can be spared by swapping the order of
411b877906bSopenharmony_ci	 *       operands in the following cross products in the right way. */
412b877906bSopenharmony_ci	vec3 f;
413b877906bSopenharmony_ci	vec3_sub(f, center, eye);
414b877906bSopenharmony_ci	vec3_norm(f, f);
415b877906bSopenharmony_ci
416b877906bSopenharmony_ci	vec3 s;
417b877906bSopenharmony_ci	vec3_mul_cross(s, f, up);
418b877906bSopenharmony_ci	vec3_norm(s, s);
419b877906bSopenharmony_ci
420b877906bSopenharmony_ci	vec3 t;
421b877906bSopenharmony_ci	vec3_mul_cross(t, s, f);
422b877906bSopenharmony_ci
423b877906bSopenharmony_ci	m[0][0] =  s[0];
424b877906bSopenharmony_ci	m[0][1] =  t[0];
425b877906bSopenharmony_ci	m[0][2] = -f[0];
426b877906bSopenharmony_ci	m[0][3] =   0.f;
427b877906bSopenharmony_ci
428b877906bSopenharmony_ci	m[1][0] =  s[1];
429b877906bSopenharmony_ci	m[1][1] =  t[1];
430b877906bSopenharmony_ci	m[1][2] = -f[1];
431b877906bSopenharmony_ci	m[1][3] =   0.f;
432b877906bSopenharmony_ci
433b877906bSopenharmony_ci	m[2][0] =  s[2];
434b877906bSopenharmony_ci	m[2][1] =  t[2];
435b877906bSopenharmony_ci	m[2][2] = -f[2];
436b877906bSopenharmony_ci	m[2][3] =   0.f;
437b877906bSopenharmony_ci
438b877906bSopenharmony_ci	m[3][0] =  0.f;
439b877906bSopenharmony_ci	m[3][1] =  0.f;
440b877906bSopenharmony_ci	m[3][2] =  0.f;
441b877906bSopenharmony_ci	m[3][3] =  1.f;
442b877906bSopenharmony_ci
443b877906bSopenharmony_ci	mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]);
444b877906bSopenharmony_ci}
445b877906bSopenharmony_ci
446b877906bSopenharmony_citypedef float quat[4];
447b877906bSopenharmony_ci#define quat_add vec4_add
448b877906bSopenharmony_ci#define quat_sub vec4_sub
449b877906bSopenharmony_ci#define quat_norm vec4_norm
450b877906bSopenharmony_ci#define quat_scale vec4_scale
451b877906bSopenharmony_ci#define quat_mul_inner vec4_mul_inner
452b877906bSopenharmony_ci
453b877906bSopenharmony_ciLINMATH_H_FUNC void quat_identity(quat q)
454b877906bSopenharmony_ci{
455b877906bSopenharmony_ci	q[0] = q[1] = q[2] = 0.f;
456b877906bSopenharmony_ci	q[3] = 1.f;
457b877906bSopenharmony_ci}
458b877906bSopenharmony_ciLINMATH_H_FUNC void quat_mul(quat r, quat const p, quat const q)
459b877906bSopenharmony_ci{
460b877906bSopenharmony_ci	vec3 w;
461b877906bSopenharmony_ci	vec3_mul_cross(r, p, q);
462b877906bSopenharmony_ci	vec3_scale(w, p, q[3]);
463b877906bSopenharmony_ci	vec3_add(r, r, w);
464b877906bSopenharmony_ci	vec3_scale(w, q, p[3]);
465b877906bSopenharmony_ci	vec3_add(r, r, w);
466b877906bSopenharmony_ci	r[3] = p[3]*q[3] - vec3_mul_inner(p, q);
467b877906bSopenharmony_ci}
468b877906bSopenharmony_ciLINMATH_H_FUNC void quat_conj(quat r, quat const q)
469b877906bSopenharmony_ci{
470b877906bSopenharmony_ci	int i;
471b877906bSopenharmony_ci	for(i=0; i<3; ++i)
472b877906bSopenharmony_ci		r[i] = -q[i];
473b877906bSopenharmony_ci	r[3] = q[3];
474b877906bSopenharmony_ci}
475b877906bSopenharmony_ciLINMATH_H_FUNC void quat_rotate(quat r, float angle, vec3 const axis) {
476b877906bSopenharmony_ci    vec3 axis_norm;
477b877906bSopenharmony_ci    vec3_norm(axis_norm, axis);
478b877906bSopenharmony_ci    float s = sinf(angle / 2);
479b877906bSopenharmony_ci    float c = cosf(angle / 2);
480b877906bSopenharmony_ci    vec3_scale(r, axis_norm, s);
481b877906bSopenharmony_ci    r[3] = c;
482b877906bSopenharmony_ci}
483b877906bSopenharmony_ciLINMATH_H_FUNC void quat_mul_vec3(vec3 r, quat const q, vec3 const v)
484b877906bSopenharmony_ci{
485b877906bSopenharmony_ci/*
486b877906bSopenharmony_ci * Method by Fabian 'ryg' Giessen (of Farbrausch)
487b877906bSopenharmony_cit = 2 * cross(q.xyz, v)
488b877906bSopenharmony_civ' = v + q.w * t + cross(q.xyz, t)
489b877906bSopenharmony_ci */
490b877906bSopenharmony_ci	vec3 t;
491b877906bSopenharmony_ci	vec3 q_xyz = {q[0], q[1], q[2]};
492b877906bSopenharmony_ci	vec3 u = {q[0], q[1], q[2]};
493b877906bSopenharmony_ci
494b877906bSopenharmony_ci	vec3_mul_cross(t, q_xyz, v);
495b877906bSopenharmony_ci	vec3_scale(t, t, 2);
496b877906bSopenharmony_ci
497b877906bSopenharmony_ci	vec3_mul_cross(u, q_xyz, t);
498b877906bSopenharmony_ci	vec3_scale(t, t, q[3]);
499b877906bSopenharmony_ci
500b877906bSopenharmony_ci	vec3_add(r, v, t);
501b877906bSopenharmony_ci	vec3_add(r, r, u);
502b877906bSopenharmony_ci}
503b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_from_quat(mat4x4 M, quat const q)
504b877906bSopenharmony_ci{
505b877906bSopenharmony_ci	float a = q[3];
506b877906bSopenharmony_ci	float b = q[0];
507b877906bSopenharmony_ci	float c = q[1];
508b877906bSopenharmony_ci	float d = q[2];
509b877906bSopenharmony_ci	float a2 = a*a;
510b877906bSopenharmony_ci	float b2 = b*b;
511b877906bSopenharmony_ci	float c2 = c*c;
512b877906bSopenharmony_ci	float d2 = d*d;
513b877906bSopenharmony_ci
514b877906bSopenharmony_ci	M[0][0] = a2 + b2 - c2 - d2;
515b877906bSopenharmony_ci	M[0][1] = 2.f*(b*c + a*d);
516b877906bSopenharmony_ci	M[0][2] = 2.f*(b*d - a*c);
517b877906bSopenharmony_ci	M[0][3] = 0.f;
518b877906bSopenharmony_ci
519b877906bSopenharmony_ci	M[1][0] = 2*(b*c - a*d);
520b877906bSopenharmony_ci	M[1][1] = a2 - b2 + c2 - d2;
521b877906bSopenharmony_ci	M[1][2] = 2.f*(c*d + a*b);
522b877906bSopenharmony_ci	M[1][3] = 0.f;
523b877906bSopenharmony_ci
524b877906bSopenharmony_ci	M[2][0] = 2.f*(b*d + a*c);
525b877906bSopenharmony_ci	M[2][1] = 2.f*(c*d - a*b);
526b877906bSopenharmony_ci	M[2][2] = a2 - b2 - c2 + d2;
527b877906bSopenharmony_ci	M[2][3] = 0.f;
528b877906bSopenharmony_ci
529b877906bSopenharmony_ci	M[3][0] = M[3][1] = M[3][2] = 0.f;
530b877906bSopenharmony_ci	M[3][3] = 1.f;
531b877906bSopenharmony_ci}
532b877906bSopenharmony_ci
533b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4o_mul_quat(mat4x4 R, mat4x4 const M, quat const q)
534b877906bSopenharmony_ci{
535b877906bSopenharmony_ci/*  XXX: The way this is written only works for orthogonal matrices. */
536b877906bSopenharmony_ci/* TODO: Take care of non-orthogonal case. */
537b877906bSopenharmony_ci	quat_mul_vec3(R[0], q, M[0]);
538b877906bSopenharmony_ci	quat_mul_vec3(R[1], q, M[1]);
539b877906bSopenharmony_ci	quat_mul_vec3(R[2], q, M[2]);
540b877906bSopenharmony_ci
541b877906bSopenharmony_ci	R[3][0] = R[3][1] = R[3][2] = 0.f;
542b877906bSopenharmony_ci	R[0][3] = M[0][3];
543b877906bSopenharmony_ci	R[1][3] = M[1][3];
544b877906bSopenharmony_ci	R[2][3] = M[2][3];
545b877906bSopenharmony_ci	R[3][3] = M[3][3];  // typically 1.0, but here we make it general
546b877906bSopenharmony_ci}
547b877906bSopenharmony_ciLINMATH_H_FUNC void quat_from_mat4x4(quat q, mat4x4 const M)
548b877906bSopenharmony_ci{
549b877906bSopenharmony_ci	float r=0.f;
550b877906bSopenharmony_ci	int i;
551b877906bSopenharmony_ci
552b877906bSopenharmony_ci	int perm[] = { 0, 1, 2, 0, 1 };
553b877906bSopenharmony_ci	int *p = perm;
554b877906bSopenharmony_ci
555b877906bSopenharmony_ci	for(i = 0; i<3; i++) {
556b877906bSopenharmony_ci		float m = M[i][i];
557b877906bSopenharmony_ci		if( m < r )
558b877906bSopenharmony_ci			continue;
559b877906bSopenharmony_ci		m = r;
560b877906bSopenharmony_ci		p = &perm[i];
561b877906bSopenharmony_ci	}
562b877906bSopenharmony_ci
563b877906bSopenharmony_ci	r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] );
564b877906bSopenharmony_ci
565b877906bSopenharmony_ci	if(r < 1e-6) {
566b877906bSopenharmony_ci		q[0] = 1.f;
567b877906bSopenharmony_ci		q[1] = q[2] = q[3] = 0.f;
568b877906bSopenharmony_ci		return;
569b877906bSopenharmony_ci	}
570b877906bSopenharmony_ci
571b877906bSopenharmony_ci	q[0] = r/2.f;
572b877906bSopenharmony_ci	q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r);
573b877906bSopenharmony_ci	q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r);
574b877906bSopenharmony_ci	q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r);
575b877906bSopenharmony_ci}
576b877906bSopenharmony_ci
577b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_arcball(mat4x4 R, mat4x4 const M, vec2 const _a, vec2 const _b, float s)
578b877906bSopenharmony_ci{
579b877906bSopenharmony_ci	vec2 a; memcpy(a, _a, sizeof(a));
580b877906bSopenharmony_ci	vec2 b; memcpy(b, _b, sizeof(b));
581b877906bSopenharmony_ci
582b877906bSopenharmony_ci	float z_a = 0.f;
583b877906bSopenharmony_ci	float z_b = 0.f;
584b877906bSopenharmony_ci
585b877906bSopenharmony_ci	if(vec2_len(a) < 1.f) {
586b877906bSopenharmony_ci		z_a = sqrtf(1.f - vec2_mul_inner(a, a));
587b877906bSopenharmony_ci	} else {
588b877906bSopenharmony_ci		vec2_norm(a, a);
589b877906bSopenharmony_ci	}
590b877906bSopenharmony_ci
591b877906bSopenharmony_ci	if(vec2_len(b) < 1.f) {
592b877906bSopenharmony_ci		z_b = sqrtf(1.f - vec2_mul_inner(b, b));
593b877906bSopenharmony_ci	} else {
594b877906bSopenharmony_ci		vec2_norm(b, b);
595b877906bSopenharmony_ci	}
596b877906bSopenharmony_ci
597b877906bSopenharmony_ci	vec3 a_ = {a[0], a[1], z_a};
598b877906bSopenharmony_ci	vec3 b_ = {b[0], b[1], z_b};
599b877906bSopenharmony_ci
600b877906bSopenharmony_ci	vec3 c_;
601b877906bSopenharmony_ci	vec3_mul_cross(c_, a_, b_);
602b877906bSopenharmony_ci
603b877906bSopenharmony_ci	float const angle = acos(vec3_mul_inner(a_, b_)) * s;
604b877906bSopenharmony_ci	mat4x4_rotate(R, M, c_[0], c_[1], c_[2], angle);
605b877906bSopenharmony_ci}
606b877906bSopenharmony_ci#endif
607