1 /*
2  * No copyright claimed, Public Domain
3  */
4 
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
9 #include <stdbool.h>
10 
11 #ifndef M_PI
12 #define M_PI 3.14159265
13 #endif
14 
15 #include "arcan_math.h"
16 
17 quat default_quat;
18 
19 /* note:
20  * there's some reason and rhyme to some of the naive implementations
21  * here and why everything isn't SIMD. While profiling isn't yet in
22  * the highest of priorities, we want to the function that rely
23  * on (possibly superflous) use of these functions,
24  * and first establish is there a way to cache or omitt the call
25  * altogether rather than "hiding" the cost by making the
26  * calculation very efficient. When this subset is reduced to a minimum,
27  * the corresponding functions get their turn in vectorization
28  */
29 #ifndef ARCAN_MATH_SIMD
mult_matrix_vecf(const float * restrict matrix,const float * restrict inv,float * restrict out)30 void mult_matrix_vecf(const float* restrict matrix,
31 	const float* restrict inv, float* restrict out)
32 {
33 	int i;
34 
35 	for (i=0; i<4; i++)
36 		out[i] =
37 		inv[0] * matrix[0*4+i] +
38 		inv[1] * matrix[1*4+i] +
39 		inv[2] * matrix[2*4+i] +
40 		inv[3] * matrix[3*4+i];
41 }
42 
multiply_matrix(float * restrict dst,const float * restrict a,const float * restrict b)43 void multiply_matrix(float* restrict dst,
44 	const float* restrict a, const float* restrict b)
45 {
46 	for (int i = 0; i < 16; i+= 4)
47 		for (int j = 0; j < 4; j++)
48 			dst[i+j] =
49 				b[i]   * a[j]   +
50 				b[i+1] * a[j+4] +
51 				b[i+2] * a[j+8] +
52 				b[i+3] * a[j+12];
53 }
54 #endif
55 
scale_matrix(float * m,float xs,float ys,float zs)56 void scale_matrix(float* m, float xs, float ys, float zs)
57 {
58 	m[0] *= xs; m[4] *= ys; m[8]  *= zs;
59 	m[1] *= xs; m[5] *= ys; m[9]  *= zs;
60 	m[2] *= xs; m[6] *= ys; m[10] *= zs;
61 	m[3] *= xs; m[7] *= ys; m[11] *= zs;
62 }
63 
translate_matrix(float * m,float xt,float yt,float zt)64 void translate_matrix(float* m, float xt, float yt, float zt)
65 {
66 	m[12] += xt;
67 	m[13] += yt;
68 	m[14] += zt;
69 /*
70  *
71  *m[12] = m[0] * xt + m[4] * yt + m[8] * zt + m[12];
72  	m[13] = m[1] * xt + m[5] * yt + m[9] * zt + m[13];
73  	m[14] = m[2] * xt + m[6] * yt + m[10]* zt + m[14];
74 	m[15] = m[3] * xt + m[7] * yt + m[11]* zt + m[15];
75  */
76 }
77 
78 static float midentity[] = {
79 	1.0, 0.0, 0.0, 0.0,
80 	0.0, 1.0, 0.0, 0.0,
81 	0.0, 0.0, 1.0, 0.0,
82 	0.0, 0.0, 0.0, 1.0
83 };
84 
identity_matrix(float * m)85 void identity_matrix(float* m)
86 {
87 	memcpy(m, midentity, 16 * sizeof(float));
88 }
89 
quat_lookat(vector pos,vector dstpos)90 quat quat_lookat(vector pos, vector dstpos)
91 {
92 	vector diff = norm_vector( sub_vector(dstpos, pos) );
93 	float xang = acos( dotp_vector(diff, build_vect(1.0, 0.0, 0.0)) );
94 	float yang = acos( dotp_vector(diff, build_vect(0.0, 1.0, 0.0)) );
95 	float zang = acos( dotp_vector(diff, build_vect(0.0, 0.0, 1.0)) );
96 
97 	return build_quat_taitbryan(xang, yang, zang);
98 }
99 
100 /* replacement for gluLookAt */
matr_lookat(float * m,vector position,vector dstpos,vector up)101 void matr_lookat(float* m, vector position, vector dstpos, vector up)
102 {
103 	vector fwd, side, rup;
104 	fwd  = norm_vector( sub_vector(dstpos, position) );
105 	side = norm_vector( crossp_vector( fwd, up ) );
106 	rup  = crossp_vector( side, fwd );
107 
108 	m[0] = side.x;
109 	m[1] = rup.x;
110 	m[2] = -fwd.x;
111 
112 	m[4] = side.y;
113 	m[5] = rup.y;
114 	m[6] = -fwd.y;
115 
116 	m[8] = side.z;
117 	m[9] = rup.z;
118 	m[10] = -fwd.z;
119 
120 	m[15] = 1.0;
121 
122 	translate_matrix(m, -position.x, -position.y, -position.z);
123 }
124 
build_orthographic_matrix(float * m,const float left,const float right,const float bottom,const float top,const float nearf,const float farf)125 void build_orthographic_matrix(float* m, const float left, const float right,
126 	const float bottom, const float top, const float nearf, const float farf)
127 {
128 	float irml = 1.0 / (right - left);
129 	float itmb = 1.0 / (top - bottom);
130 	float ifmn = 1.0 / (farf - nearf);
131 
132 	m[0]  = 2.0f * irml;
133 	m[1]  = 0.0f;
134 	m[2]  = 0.0f;
135 	m[3]  = 0.0;
136 
137 	m[4]  = 0.0f;
138 	m[5]  = 2.0f * itmb;
139 	m[6]  = 0.0f;
140 	m[7]  = 0.0;
141 
142 	m[8]  = 0.0f;
143 	m[9]  = 0.0f;
144 	m[10] = 2.0f * ifmn;
145 	m[11] = 0.0;
146 
147 	m[12] = -(right+left) * irml;
148 	m[13] = -(top+bottom) * itmb;
149 	m[14] = -(farf+nearf) * ifmn;
150 	m[15] = 1.0f;
151 }
152 
build_projection_matrix(float * m,float nearv,float farv,float aspect,float fov)153 void build_projection_matrix(float* m,
154 	float nearv, float farv, float aspect, float fov)
155 {
156 	const float h = 1.0f / tan(fov * (M_PI / 360.0));
157 	float neg_depth = nearv - farv;
158 
159 	m[0]  = h / aspect; m[1]  = 0; m[2]  = 0;  m[3] = 0;
160 	m[4]  = 0; m[5]  = h; m[6]  = 0;  m[7] = 0;
161 	m[8]  = 0; m[9]  = 0; m[10] = (farv + nearv) / neg_depth; m[11] =-1;
162 	m[12] = 0; m[13] = 0; m[14] = 2.0f * (nearv * farv) / neg_depth; m[15] = 0;
163 }
164 
project_matrix(float objx,float objy,float objz,const float modelMatrix[16],const float projMatrix[16],const int viewport[4],float * winx,float * winy,float * winz)165 int project_matrix(float objx, float objy, float objz,
166 			const float modelMatrix[16], const float projMatrix[16],
167 			const int viewport[4], float *winx, float *winy, float *winz)
168 {
169 	_Alignas(16) float in[4];
170 	_Alignas(16) float out[4];
171 
172 	in[0]=objx;
173 	in[1]=objy;
174 	in[2]=objz;
175 	in[3]=1.0;
176 
177 	mult_matrix_vecf(modelMatrix, in, out);
178 	mult_matrix_vecf(projMatrix, out, in);
179 
180 	if (in[3] == 0.0)
181 		return 0;
182 
183 	in[0] /= in[3];
184 	in[1] /= in[3];
185 	in[2] /= in[3];
186 
187 /* Map x, y and z to range 0-1 */
188 	in[0] = in[0] * 0.5 + 0.5;
189 	in[1] = in[1] * 0.5 + 0.5;
190 	in[2] = in[2] * 0.5 + 0.5;
191 
192 /* Map x,y to viewport */
193 	in[0] = in[0] * viewport[2] + viewport[0];
194 	in[1] = in[1] * viewport[3] + viewport[1];
195 
196 	*winx=in[0];
197 	*winy=in[1];
198 	*winz=in[2];
199 	return 1;
200 }
201 
pinpoly(int nvert,float * vertx,float * verty,float testx,float testy)202 int pinpoly(int nvert, float *vertx, float *verty, float testx, float testy)
203 {
204 	int i, j, c = 0;
205 	for (i = 0, j = nvert-1; i < nvert; j = i++) {
206 		if ( ((verty[i]>testy) != (verty[j]>testy)) &&
207 			(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) /
208 			(verty[j]-verty[i]) + vertx[i]) )
209 			c = !c;
210 	}
211 	return c;
212 }
213 
build_vect_polar(const float phi,const float theta)214 vector build_vect_polar(const float phi, const float theta)
215 {
216 	vector res = {.x = sinf(phi) * cosf(theta),
217 		.y = sinf(phi) * sinf(theta), .z = sinf(phi)};
218 	return res;
219 }
220 
build_vect(const float x,const float y,const float z)221 vector build_vect(const float x, const float y, const float z)
222 {
223 	vector res = {.x = x, .y = y, .z = z};
224 	return res;
225 }
226 
mul_vectorf(vector a,float f)227 vector mul_vectorf(vector a, float f)
228 {
229 	vector res = {.x = a.x * f, .y = a.y * f, .z = a.z * f};
230 	return res;
231 }
232 
build_quat(float angdeg,float vx,float vy,float vz)233 quat build_quat(float angdeg, float vx, float vy, float vz)
234 {
235 	quat ret;
236 	float ang = angdeg / 180.f * M_PI;
237 	float res = sinf(ang / 2.0f);
238 
239 	ret.w = cosf(ang / 2.0f);
240 	ret.x = vx * res;
241 	ret.y = vy * res;
242 	ret.z = vz * res;
243 
244 	return ret;
245 }
246 
len_vector(vector invect)247 float len_vector(vector invect)
248 {
249 	return sqrt(invect.x * invect.x +
250 		invect.y * invect.y + invect.z * invect.z);
251 }
252 
crossp_vector(vector a,vector b)253 vector crossp_vector(vector a, vector b)
254 {
255 	vector res = {
256 		.x = a.y * b.z - a.z * b.y,
257 		.y = a.z * b.x - a.x * b.z,
258 		.z = a.x * b.y - a.y * b.x
259 	};
260 	return res;
261 }
262 
dotp_vector(vector a,vector b)263 float dotp_vector(vector a, vector b)
264 {
265 	return a.x * b.x + a.y * b.y + a.z * b.z;
266 }
267 
sub_vector(vector a,vector b)268 vector sub_vector(vector a, vector b)
269 {
270 	vector res = {.x = a.x - b.x,
271 	.y = a.y - b.y,
272 	.z = a.z - b.z};
273 
274 	return res;
275 }
276 
add_vector(vector a,vector b)277 vector add_vector(vector a, vector b)
278 {
279 	vector res = {.x = a.x + b.x,
280 	.y = a.y + b.y,
281 	.z = a.z + b.z};
282 
283 	return res;
284 }
285 
mul_vector(vector a,vector b)286 vector mul_vector(vector a, vector b)
287 {
288 	vector res = {
289 		.x = a.x * b.x,
290 		.y = a.y * b.y,
291 		.z = a.z * b.z
292 	};
293 
294 	return res;
295 }
296 
norm_vector(vector invect)297 vector norm_vector(vector invect){
298 	vector empty = {.x = 0.0, .y = 0.0, .z = 0.0};
299 	float len = len_vector(invect);
300 	if (len < EPSILON)
301 		return empty;
302 
303 	vector res = {
304 		.x = invect.x / len,
305 		.y = invect.y / len,
306 		.z = invect.z / len
307 	};
308 
309 	return res;
310 }
311 
inv_quat(quat src)312 quat inv_quat(quat src)
313 {
314 	quat res = {.x = -src.x, .y = -src.y, .z = -src.z, .w = src.w };
315 	return res;
316 }
317 
len_quat(quat src)318 float len_quat(quat src)
319 {
320 	return sqrt(src.x * src.x + src.y *
321 		src.y + src.z * src.z + src.w * src.w);
322 }
323 
norm_quat(quat src)324 quat norm_quat(quat src)
325 {
326 	float val = src.x * src.x + src.y *
327 		src.y + src.z * src.z + src.w * src.w;
328 
329 	if (val > 0.99999 && val < 1.000001)
330 		return src;
331 
332 	val = sqrtf(val);
333 	quat res = {.x = src.x / val, .y = src.y / val,
334 		.z = src.z / val, .w = src.w / val};
335 	return res;
336 }
337 
div_quatf(quat a,float v)338 quat div_quatf(quat a, float v)
339 {
340 	quat res = {
341 		.x = a.x / v,
342 		.y = a.y / v,
343 		.z = a.z / v,
344 		.w = a.z / v
345 	};
346 	return res;
347 }
348 
mul_quatf(quat a,float v)349 quat mul_quatf(quat a, float v)
350 {
351 	quat res = {
352 		.x = a.x * v,
353 		.y = a.y * v,
354 		.z = a.z * v,
355 		.w = a.w * v
356 	};
357 	return res;
358 }
359 
mul_quat(quat a,quat b)360 quat mul_quat(quat a, quat b)
361 {
362 	quat res;
363 	res.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
364 	res.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
365 	res.y = a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z;
366 	res.z = a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x;
367 	return res;
368 }
369 
add_quat(quat a,quat b)370 quat add_quat(quat a, quat b)
371 {
372 	quat res;
373 	res.x = a.x + b.x;
374 	res.y = a.y + b.y;
375 	res.z = a.z + b.z;
376 	res.w = a.w + b.w;
377 
378 	return res;
379 }
380 
dot_quat(quat a,quat b)381 float dot_quat(quat a, quat b)
382 {
383 	return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
384 }
385 
angle_quat(quat a)386 vector angle_quat(quat a)
387 {
388 	float sqw = a.w*a.w;
389 	float sqx = a.x*a.x;
390 	float sqy = a.y*a.y;
391 	float sqz = a.z*a.z;
392 
393 	vector euler;
394 	euler.x = atan2f(2.f * (a.x*a.y + a.z*a.w), sqx - sqy - sqz + sqw);
395 	euler.y = asinf(-2.f * (a.x*a.z - a.y*a.w));
396 	euler.z = atan2f(2.f * (a.y*a.z + a.x*a.w), -sqx - sqy + sqz + sqw);
397 
398 	float mpi = 180.0 / M_PI;
399 	euler.x *= mpi;
400 	euler.y *= mpi;
401 	euler.z *= mpi;
402 
403 	return euler;
404 }
405 
lerp_vector(vector a,vector b,float fact)406 vector lerp_vector(vector a, vector b, float fact)
407 {
408 	vector res;
409 	res.x = a.x + fact * (b.x - a.x);
410 	res.y = a.y + fact * (b.y - a.y);
411 	res.z = a.z + fact * (b.z - a.z);
412 	return res;
413 }
414 
interp_1d_sine(float sv,float ev,float fract)415 float interp_1d_sine(float sv, float ev, float fract)
416 {
417 	return sv + (ev - sv) * sinf(0.5 * fract * M_PI);
418 }
419 
interp_1d_linear(float sv,float ev,float fract)420 float interp_1d_linear(float sv, float ev, float fract)
421 {
422 	return sv + (ev - sv) * fract;
423 }
424 
interp_1d_smoothstep(float sv,float ev,float fract)425 float interp_1d_smoothstep(float sv, float ev, float fract)
426 {
427 	float res = (fract - 0.1) / (0.9 - 0.1);
428 	if (res < 0)
429 		res = 0.0;
430 	else if (res > 1.0)
431 		res = 1.0;
432 	res = res * res * (3.0 - 2.0 * res);
433 	return sv + res * (ev - sv);
434 }
435 
interp_3d_smoothstep(vector sv,vector ev,float fract)436 vector interp_3d_smoothstep(vector sv, vector ev, float fract)
437 {
438 	return (vector){
439 		.x = interp_1d_smoothstep(sv.x, ev.x, fract),
440 		.y = interp_1d_smoothstep(sv.y, ev.y, fract),
441 		.z = interp_1d_smoothstep(sv.z, ev.z, fract)
442 	};
443 }
444 
interp_3d_linear(vector sv,vector ev,float fract)445 vector interp_3d_linear(vector sv, vector ev, float fract)
446 {
447 	vector res;
448 	res.x = sv.x + (ev.x - sv.x) * fract;
449 	res.y = sv.y + (ev.y - sv.y) * fract;
450 	res.z = sv.z + (ev.z - sv.z) * fract;
451 	return res;
452 }
453 
interp_1d_expout(float sv,float ev,float fract)454 float interp_1d_expout(float sv, float ev, float fract)
455 {
456 	return fract < EPSILON ? sv :
457 		sv + (ev - sv) * (1.0 - powf(2.0, -10.0 * fract));
458 }
459 
interp_1d_expin(float sv,float ev,float fract)460 float interp_1d_expin(float sv, float ev, float fract)
461 {
462 	return fract < EPSILON ? sv :
463 		sv + (ev - sv) * powf(2, 10 * (fract - 1.0));
464 }
465 
interp_1d_expinout(float sv,float ev,float fract)466 float interp_1d_expinout(float sv, float ev, float fract)
467 {
468 	return fract < EPSILON ? sv :
469 			fract > 1.0 - EPSILON ? ev :
470 				fract < 0.5 ?
471 					sv + (ev - sv) * ( 0.5 * powf(2, (20 * fract) - 10)) :
472 					sv + (ev - sv) * ((-0.5 * powf(2, (-20 * fract) + 10)) + 1);
473 }
474 
interp_3d_expin(vector sv,vector ev,float fract)475 vector interp_3d_expin(vector sv, vector ev, float fract)
476 {
477 	vector res;
478 
479 	res.x = fract < EPSILON ? sv.x :
480 		sv.x + (ev.x - sv.x) * powf(2, 10 * (fract - 1.0));
481 
482 	res.y = fract < EPSILON ? sv.x :
483 		sv.y + (ev.y - sv.y) * powf(2, 10 * (fract - 1.0));
484 
485 	res.z = fract < EPSILON ? sv.x :
486 		sv.z + (ev.z - sv.z) * powf(2, 10 * (fract - 1.0));
487 
488 	return res;
489 }
490 
interp_3d_expinout(vector sv,vector ev,float fract)491 vector interp_3d_expinout(vector sv, vector ev, float fract)
492 {
493 	vector res;
494 	res.x = fract < EPSILON ? sv.x :
495 			fract > 1.0 - EPSILON ? ev.x :
496 				fract < 0.5 ?
497 					sv.x + (ev.x - sv.x) * ( 0.5 * powf(2, (20 * fract) - 10)) :
498 					sv.x + (ev.x - sv.x) * ((-0.5 * powf(2, (-20 * fract) + 10)) + 1);
499 
500 	res.y = fract < EPSILON ? sv.y :
501 			fract > 1.0 - EPSILON ? ev.y :
502 				fract < 0.5 ?
503 					sv.y + (ev.y - sv.y) * ( 0.5 * powf(2, (20 * fract) - 10)) :
504 					sv.y + (ev.y - sv.y) * ((-0.5 * powf(2, (-20 * fract) + 10)) + 1);
505 
506 	res.z = fract < EPSILON ? sv.z :
507 			fract > 1.0 - EPSILON ? ev.z :
508 				fract < 0.5 ?
509 					sv.z + (ev.z - sv.z) * ( 0.5 * powf(2, (20 * fract) - 10)) :
510 					sv.z + (ev.z - sv.z) * ((-0.5 * powf(2, (-20 * fract) + 10)) + 1);
511 
512 	return res;
513 }
514 
interp_3d_expout(vector sv,vector ev,float fract)515 vector interp_3d_expout(vector sv, vector ev, float fract)
516 {
517 	vector res;
518 
519 	res.x = fract < EPSILON ? sv.x :
520 		sv.x + (ev.x - sv.x) * (1.0 - powf(2.0, -10.0 * fract));
521 
522 	res.y = fract < EPSILON ? sv.x :
523 		sv.y + (ev.y - sv.y) * (1.0 - powf(2.0, -10.0 * fract));
524 
525 	res.z = fract < EPSILON ? sv.x :
526 		sv.z + (ev.z - sv.z) * (1.0 - powf(2.0, -10.0 * fract));
527 
528 	return res;
529 }
530 
interp_3d_sine(vector sv,vector ev,float fract)531 vector interp_3d_sine(vector sv, vector ev, float fract)
532 {
533 	vector res;
534 	res.x = sv.x + (ev.x - sv.x) * sinf(0.5 * fract * M_PI);
535 	res.y = sv.y + (ev.y - sv.y) * sinf(0.5 * fract * M_PI);
536 	res.z = sv.z + (ev.z - sv.z) * sinf(0.5 * fract * M_PI);
537 	return res;
538 }
539 
slerp_quatfl(quat a,quat b,float fact,bool r360)540 static inline quat slerp_quatfl(quat a, quat b, float fact, bool r360)
541 {
542 	float weight_a, weight_b;
543 	bool flip = false;
544 
545 /* r360 if delta > 180degrees) */
546 	float ct = dot_quat(a, b);
547 	if (r360 && ct > 1.0){
548 		ct   = -ct;
549 		flip = true;
550 	}
551 
552 	float th  = acos(ct);
553 	float sth = sin(th);
554 
555 	if (sth > 0.005f){
556 		weight_a = sin( (1.0f - fact) * th) / sth;
557 		weight_b = sin( fact * th   )       / sth;
558 	}
559 	else {
560 /* small steps, only linear */
561 		weight_a = 1.0f - fact;
562 		weight_b = fact;
563 	}
564 
565 	if (flip)
566 		weight_b = -weight_b;
567 
568 	return add_quat(mul_quatf(a, weight_a), mul_quatf(b, weight_b));
569 }
570 
nlerp_quatfl(quat a,quat b,float fact,bool r360)571 static inline quat nlerp_quatfl(quat a, quat b, float fact, bool r360)
572 {
573 	float tinv = 1.0f - fact;
574 	quat rq;
575 
576 	if (r360 && dot_quat(a, b) < 0.0f)
577 		rq = add_quat(mul_quatf(a, tinv), mul_quatf(a, -fact));
578 	else
579 		rq = add_quat(mul_quatf(a, tinv), mul_quatf(b,  fact));
580 
581 	return norm_quat(rq);
582 }
583 
slerp_quat180(quat a,quat b,float fact)584 quat slerp_quat180(quat a, quat b, float fact){
585 	return slerp_quatfl(a, b, fact, false);
586 }
587 
slerp_quat360(quat a,quat b,float fact)588 quat slerp_quat360(quat a, quat b, float fact){
589 	return slerp_quatfl(a, b, fact, true );
590 }
591 
nlerp_quat180(quat a,quat b,float fact)592 quat nlerp_quat180(quat a, quat b, float fact){
593 	return nlerp_quatfl(a, b, fact, false);
594 }
595 
nlerp_quat360(quat a,quat b,float fact)596 quat nlerp_quat360(quat a, quat b, float fact){
597 	return nlerp_quatfl(a, b, fact, true );
598 }
599 
matr_rotatef(float ang,float * dmatr)600 float* matr_rotatef(float ang, float* dmatr)
601 {
602 	float cv = cosf(ang);
603 	float sf = sinf(ang);
604 	memcpy(dmatr, midentity, 16 * sizeof(float));
605 	dmatr[0] = cv;
606 	dmatr[5] = cv;
607 	dmatr[1] = sf;
608 	dmatr[4] = -sf;
609 	return dmatr;
610 }
611 
matr_quatf(quat a,float * dmatr)612 float* matr_quatf(quat a, float* dmatr)
613 {
614 	if (dmatr){
615 		dmatr[0] = 1.0f - 2.0f * (a.y * a.y + a.z * a.z);
616 		dmatr[1] = 2.0f * (a.x * a.y + a.z * a.w);
617 		dmatr[2] = 2.0f * (a.x * a.z - a.y * a.w);
618 		dmatr[3] = 0.0f;
619 		dmatr[4] = 2.0f * (a.x * a.y - a.z * a.w);
620 		dmatr[5] = 1.0f - 2.0f * (a.x * a.x + a.z * a.z);
621 		dmatr[6] = 2.0f * (a.z * a.y + a.x * a.w);
622 		dmatr[7] = 0.0f;
623 		dmatr[8] = 2.0f * (a.x * a.z + a.y * a.w);
624 		dmatr[9] = 2.0f * (a.y * a.z - a.x * a.w);
625 		dmatr[10]= 1.0f - 2.0f * (a.x * a.x + a.y * a.y);
626 		dmatr[11]= 0.0f;
627 		dmatr[12]= 0.0f;
628 		dmatr[13]= 0.0f;
629 		dmatr[14]= 0.0f;
630 		dmatr[15]= 1.0f;
631 	}
632 	return dmatr;
633 }
634 
635 /*
636  * Plucked from MESA
637  */
matr_invf(const float * restrict m,float * restrict out)638 bool matr_invf(const float* restrict m, float* restrict out)
639 {
640 	float inv[16], det;
641 	int i;
642 
643 	inv[0] =
644 		m[5]  * m[10] * m[15] -
645 		m[5]  * m[11] * m[14] -
646 		m[9]  * m[6]  * m[15] +
647 		m[9]  * m[7]  * m[14] +
648 		m[13] * m[6]  * m[11] -
649 		m[13] * m[7]  * m[10];
650 
651 	inv[4] =
652 		-m[4] * m[10] * m[15] +
653 		 m[4]  * m[11] * m[14] +
654 		 m[8]  * m[6]  * m[15] -
655 		 m[8]  * m[7]  * m[14] -
656 		 m[12] * m[6]  * m[11] +
657 		 m[12] * m[7]  * m[10];
658 
659 	inv[8] =
660 		m[4]  * m[9]  * m[15] -
661 		m[4]  * m[11] * m[13] -
662 		m[8]  * m[5]  * m[15] +
663 		m[8]  * m[7]  * m[13] +
664 		m[12] * m[5]  * m[11] -
665 		m[12] * m[7]  * m[9];
666 
667 	inv[12] =
668 		-m[4]  * m[9]  * m[14] +
669 		 m[4]  * m[10] * m[13] +
670 		 m[8]  * m[5]  * m[14] -
671 		 m[8]  * m[6]  * m[13] -
672 		 m[12] * m[5]  * m[10] +
673 		 m[12] * m[6]  * m[9];
674 
675 	inv[1] =
676 		-m[1] * m[10] * m[15] +
677 		 m[1]  * m[11] * m[14] +
678 		 m[9]  * m[2]  * m[15] -
679 		 m[9]  * m[3]  * m[14] -
680 		 m[13] * m[2]  * m[11] +
681 		 m[13] * m[3]  * m[10];
682 
683 	inv[5] =
684 		m[0]  * m[10] * m[15] -
685 		m[0]  * m[11] * m[14] -
686 		m[8]  * m[2]  * m[15] +
687 		m[8]  * m[3]  * m[14] +
688 		m[12] * m[2]  * m[11] -
689 		m[12] * m[3]  * m[10];
690 
691 	inv[9] =
692 		-m[0]  * m[9]  * m[15] +
693 		 m[0]  * m[11] * m[13] +
694 		 m[8]  * m[1]  * m[15] -
695 		 m[8]  * m[3]  * m[13] -
696 		 m[12] * m[1]  * m[11] +
697 		 m[12] * m[3]  * m[9];
698 
699 	inv[13] =
700 		m[0]  * m[9] * m[14] -
701 		m[0]  * m[10] * m[13] -
702 		m[8]  * m[1] * m[14] +
703 		m[8]  * m[2] * m[13] +
704 		m[12] * m[1] * m[10] -
705 		m[12] * m[2] * m[9];
706 
707 	inv[2] =
708 		m[1]  * m[6] * m[15] -
709 		m[1]  * m[7] * m[14] -
710 		m[5]  * m[2] * m[15] +
711 		m[5]  * m[3] * m[14] +
712 		m[13] * m[2] * m[7] -
713 		m[13] * m[3] * m[6];
714 
715 	inv[6] =
716 		-m[0]  * m[6] * m[15] +
717 		 m[0]  * m[7] * m[14] +
718 		 m[4]  * m[2] * m[15] -
719 		 m[4]  * m[3] * m[14] -
720 		 m[12] * m[2] * m[7] +
721 		 m[12] * m[3] * m[6];
722 
723 	inv[10] =
724 		m[0]  * m[5] * m[15] -
725 		m[0]  * m[7] * m[13] -
726 		m[4]  * m[1] * m[15] +
727 		m[4]  * m[3] * m[13] +
728 		m[12] * m[1] * m[7] -
729 		m[12] * m[3] * m[5];
730 
731 	inv[14] =
732 		-m[0] * m[5] * m[14] +
733 		 m[0]  * m[6] * m[13] +
734 		 m[4]  * m[1] * m[14] -
735 		 m[4]  * m[2] * m[13] -
736 		 m[12] * m[1] * m[6] +
737 		 m[12] * m[2] * m[5];
738 
739 	inv[3] =
740 		-m[1] * m[6] * m[11] +
741 		 m[1] * m[7] * m[10] +
742 		 m[5] * m[2] * m[11] -
743 		 m[5] * m[3] * m[10] -
744 		 m[9] * m[2] * m[7] +
745 		 m[9] * m[3] * m[6];
746 
747 	inv[7] =
748 		m[0] * m[6] * m[11] -
749 		m[0] * m[7] * m[10] -
750 		m[4] * m[2] * m[11] +
751 		m[4] * m[3] * m[10] +
752 		m[8] * m[2] * m[7] -
753 		m[8] * m[3] * m[6];
754 
755 	inv[11] =
756 		-m[0] * m[5] * m[11] +
757 		 m[0] * m[7] * m[9] +
758 		 m[4] * m[1] * m[11] -
759 		 m[4] * m[3] * m[9] -
760 		 m[8] * m[1] * m[7] +
761 		 m[8] * m[3] * m[5];
762 
763 	inv[15] =
764 		m[0] * m[5] * m[10] -
765 		m[0] * m[6] * m[9] -
766 		m[4] * m[1] * m[10] +
767 		m[4] * m[2] * m[9] +
768 		m[8] * m[1] * m[6] -
769 		m[8] * m[2] * m[5];
770 
771 	det =
772 		m[0] * inv[0] + m[1] * inv[4] +
773 		m[2] * inv[8] + m[3] * inv[12];
774 
775 	if (det == 0)
776 		return false;
777 
778 	det = 1.0 / det;
779 
780 	for (i = 0; i < 16; i++)
781 		out[i] = inv[i] * det;
782 
783 	return true;
784 }
785 
matr_quat(quat a,double * dmatr)786 double* matr_quat(quat a, double* dmatr)
787 {
788 	if (dmatr){
789 		dmatr[0] = 1.0f - 2.0f * (a.y * a.y + a.z * a.z);
790 		dmatr[1] = 2.0f * (a.x * a.y + a.z * a.w);
791 		dmatr[2] = 2.0f * (a.x * a.z - a.y * a.w);
792 		dmatr[3] = 0.0f;
793 		dmatr[4] = 2.0f * (a.x * a.y - a.z * a.w);
794 		dmatr[5] = 1.0f - 2.0f * (a.x * a.x + a.z * a.z);
795 		dmatr[6] = 2.0f * (a.z * a.y + a.x * a.w);
796 		dmatr[7] = 0.0f;
797 		dmatr[8] = 2.0f * (a.x * a.z + a.y * a.w);
798 		dmatr[9] = 2.0f * (a.y * a.z - a.x * a.w);
799 		dmatr[10]= 1.0f - 2.0f * (a.x * a.x + a.y * a.y);
800 		dmatr[11]= 0.0f;
801 		dmatr[12]= 0.0f;
802 		dmatr[13]= 0.0f;
803 		dmatr[14]= 0.0f;
804 		dmatr[15]= 1.0f;
805 	}
806 	return dmatr;
807 }
808 
build_quat_taitbryan(float roll,float pitch,float yaw)809 quat build_quat_taitbryan(float roll, float pitch, float yaw)
810 {
811 	roll  = fmodf(roll + 180.f, 360.f) - 180.f;
812 	pitch = fmodf(pitch+ 180.f, 360.f) - 180.f;
813 	yaw   = fmodf(yaw  + 180.f, 360.f) - 180.f;
814 
815 	quat res = mul_quat( mul_quat( build_quat(pitch, 1.0, 0.0, 0.0),
816 		build_quat(yaw, 0.0, 1.0, 0.0)), build_quat(roll, 0.0, 0.0, 1.0));
817 	return res;
818 }
819 
update_view(orientation * dst,float roll,float pitch,float yaw)820 void update_view(orientation* dst, float roll, float pitch, float yaw)
821 {
822 	dst->pitchf = pitch;
823 	dst->rollf = roll;
824 	dst->yawf = yaw;
825 	quat pitchq = build_quat(pitch, 1.0, 0.0, 0.0);
826 	quat rollq  = build_quat(yaw, 0.0, 1.0, 0.0);
827 	quat yawq   = build_quat(roll, 0.0, 0.0, 1.0);
828 	quat res = mul_quat( mul_quat(pitchq, yawq), rollq );
829 	matr_quatf(res, dst->matr);
830 }
831 
taitbryan_forwardv(float roll,float pitch,float yaw)832 vector taitbryan_forwardv(float roll, float pitch, float yaw)
833 {
834 	_Alignas(16) float dmatr[16];
835 
836 	quat pitchq = build_quat(pitch, 1.0, 0.0, 0.0);
837 	quat yawq   = build_quat(yaw,   0.0, 1.0, 0.0);
838 
839 	matr_quatf(pitchq, dmatr);
840 
841 	vector view;
842 	view.y = -dmatr[9];
843 	quat res = mul_quat(pitchq, yawq);
844 	matr_quatf(res, dmatr);
845 	view.x = -dmatr[8];
846 	view.z = dmatr[10];
847 
848 	return view;
849 }
850 
normalize_plane(float * pl)851 static inline void normalize_plane(float* pl)
852 {
853 	float mag = 1.0f / sqrtf(pl[0] * pl[0] + pl[1] * pl[1] + pl[2] * pl[2]);
854 	pl[0] *= mag;
855 	pl[1] *= mag;
856 	pl[2] *= mag;
857 	pl[3] *= mag;
858 }
859 
frustum_point(const float frustum[6][4],const float x,const float y,const float z)860 bool frustum_point(const float frustum[6][4],
861 	const float x, const float y, const float z)
862 {
863 	for (int i = 0; i < 6; i++)
864 		if (frustum[i][0] * x +
865 				frustum[i][1] * y +
866 				frustum[i][2] * z +
867 				frustum[i][3] <= 0.0f)
868 			return false;
869 
870 	return true;
871 }
872 
frustum_aabb(const float frustum[6][4],const float x1,const float y1,const float z1,const float x2,const float y2,const float z2)873 enum cstate frustum_aabb(const float frustum[6][4],
874 	const float x1, const float y1, const float z1,
875 	const float x2, const float y2, const float z2)
876 {
877 	enum cstate res = inside;
878 	for (int i = 0; i < 6; i++){
879 		if (frustum[i][0] * x1 + frustum[i][1] * y1 +
880 			frustum[i][2] * z1 + frustum[i][3] > 0.0f)
881 			continue;
882 
883 		res = intersect;
884 
885 		if (frustum[i][0] * x2 + frustum[i][1] * y1 +
886 			frustum[i][2] * z1 + frustum[i][3] > 0.0f)
887 			continue;
888 
889 		if (frustum[i][0] * x1 + frustum[i][1] * y2 +
890 			frustum[i][2] * z1 + frustum[i][3] > 0.0f)
891 			continue;
892 
893 		if (frustum[i][0] * x2 + frustum[i][1] * y2 +
894 			frustum[i][2] * z1 + frustum[i][3] > 0.0f)
895 			continue;
896 
897 		if (frustum[i][0] * x1 + frustum[i][1] * y1 +
898 			frustum[i][2] * z2 + frustum[i][3] > 0.0f)
899 			continue;
900 
901 		if (frustum[i][0] * x2 + frustum[i][1] * y1 +
902 			frustum[i][2] * z2 + frustum[i][3] > 0.0f)
903 			continue;
904 
905 		if (frustum[i][0] * x1 + frustum[i][1] * y2 +
906 			frustum[i][2] * z2 + frustum[i][3] > 0.0f)
907 			continue;
908 
909 		if (frustum[i][0] * x2 + frustum[i][1] * y2 +
910 			frustum[i][2] * z2 + frustum[i][3] > 0.0f)
911 			continue;
912 	}
913 
914 	return res;
915 }
916 
frustum_sphere(const float frustum[6][4],const float x,const float y,const float z,const float radius)917 enum cstate frustum_sphere(const float frustum[6][4],
918 	const float x, const float y, const float z, const float radius)
919 {
920 	for (int i = 0; i < 6; i++){
921 		float dist =
922 			frustum[i][0] * x +
923 			frustum[i][1] * y +
924 			frustum[i][2] * z +
925 			frustum[i][3];
926 
927 		if (dist < -radius)
928 			return outside;
929 
930 		else if (fabs(dist) < radius)
931 			return intersect;
932 	}
933 
934 	return inside;
935 }
936 
update_frustum(float * prjm,float * mvm,float frustum[6][4])937 void update_frustum(float* prjm, float* mvm, float frustum[6][4])
938 {
939 	float mmr[16];
940 /* multiply modelview with projection */
941 	multiply_matrix(mmr, mvm, prjm);
942 
943 /* extract and normalize planes */
944 	frustum[0][0] = mmr[3]  + mmr[0]; // left
945 	frustum[0][1] = mmr[7]  + mmr[4];
946 	frustum[0][2] = mmr[11] + mmr[8];
947 	frustum[0][3] = mmr[15] + mmr[12];
948 	normalize_plane(frustum[0]);
949 
950 	frustum[1][0] = mmr[3]  - mmr[0]; // right
951 	frustum[1][1] = mmr[7]  - mmr[4];
952 	frustum[1][2] = mmr[11] - mmr[8];
953 	frustum[1][3] = mmr[15] - mmr[12];
954 	normalize_plane(frustum[1]);
955 
956 	frustum[2][0] = mmr[3]  - mmr[1]; // top
957 	frustum[2][1] = mmr[7]  - mmr[5];
958 	frustum[2][2] = mmr[11] - mmr[9];
959 	frustum[2][3] = mmr[15] - mmr[13];
960 	normalize_plane(frustum[2]);
961 
962 	frustum[3][0] = mmr[3]  + mmr[1]; // bottom
963 	frustum[3][1] = mmr[7]  + mmr[5];
964 	frustum[3][2] = mmr[11] + mmr[9];
965 	frustum[3][3] = mmr[15] + mmr[13];
966 	normalize_plane(frustum[3]);
967 
968 	frustum[4][0] = mmr[3]  + mmr[2]; // near
969 	frustum[4][1] = mmr[7]  + mmr[6];
970 	frustum[4][2] = mmr[11] + mmr[10];
971 	frustum[4][3] = mmr[15] + mmr[14];
972 	normalize_plane(frustum[4]);
973 
974 	frustum[5][0] = mmr[3]  - mmr[2]; // far
975 	frustum[5][1] = mmr[7]  - mmr[6];
976 	frustum[5][2] = mmr[11] - mmr[10];
977 	frustum[5][3] = mmr[15] - mmr[14];
978 	normalize_plane(frustum[5]);
979 }
980 
arcan_math_init()981 void arcan_math_init()
982 {
983 	default_quat = build_quat_taitbryan(0, 0, 0);
984 }
985 
ray_plane(vector * pos,vector * dir,vector * plane_pos,vector * plane_normal,vector * intersect)986 bool ray_plane(vector* pos, vector* dir,
987 	vector* plane_pos, vector* plane_normal, vector* intersect)
988 {
989 	float den = dotp_vector(*plane_normal, *dir);
990 	if (den > EPSILON){
991 		vector diff = sub_vector(*pos, *plane_pos);
992 		float tt = dotp_vector(diff, *plane_normal);
993 		*intersect = add_vector(mul_vectorf(*dir, tt), *pos);
994 		return tt >= 0;
995 	}
996 
997 	return false;
998 }
999 
ray_sphere(const vector * ray_pos,const vector * ray_dir,const vector * sphere_pos,float sphere_rad,float * d1,float * d2)1000 bool ray_sphere(const vector* ray_pos, const vector* ray_dir,
1001 	const vector* sphere_pos, float sphere_rad, float* d1, float *d2)
1002 {
1003 	float den, b;
1004 	vector delta = sub_vector(*ray_pos, *sphere_pos);
1005 	b = -1.0 * dotp_vector(delta, *ray_dir);
1006 	den = b * b - dotp_vector(delta, delta) + sphere_rad * sphere_rad;
1007 	if (den < 0)
1008 		return false;
1009 
1010 	den = sqrtf(den);
1011 
1012 	*d1 = b - den;
1013 	*d2 = b + den;
1014 
1015 	if (*d2 < 0)
1016 		return false;
1017 
1018 	if (*d1 < 0)
1019 		*d1 = 0;
1020 
1021 	return true;
1022 }
1023 
unproject_matrix(float dev_x,float dev_y,float dev_z,const float * restrict view,const float * restrict proj)1024 vector unproject_matrix(float dev_x, float dev_y, float dev_z,
1025 	const float* restrict view, const float* restrict proj)
1026 {
1027 /* combine modelview and projection, then invert */
1028 	_Alignas(16) float invm[16];
1029 	_Alignas(16) float vpm[16];
1030 	multiply_matrix(vpm, proj, view);
1031 	matr_invf(vpm, invm);
1032 
1033 /* x y z should be device coordinates (-1..1) */
1034 	_Alignas(16) float wndv[4] = {dev_x, dev_y, dev_z, 1.0};
1035 	_Alignas(16) float upv[4];
1036 /* transform device coordinates */
1037 
1038 	mult_matrix_vecf(invm, wndv, upv);
1039 
1040 	upv[3] = 1.0 / upv[3];
1041 
1042 	vector vs = {
1043 		.x = upv[0] * upv[3],
1044 		.y = upv[1] * upv[3],
1045 		.z = upv[2] * upv[3]
1046 	};
1047 
1048 	return vs;
1049 }
1050 
dev_coord(float * out_x,float * out_y,float * out_z,int x,int y,int w,int h,float near,float far)1051 void dev_coord(float* out_x, float* out_y, float* out_z,
1052 	int x, int y, int w, int h, float near, float far)
1053 {
1054 	*out_x = (2.0 * (float) x ) / (float) w - 1.0;
1055 	*out_y = 1.0 - (2.0 * (float) y ) / (float) h;
1056 	*out_z = (0.0 - near) / (far - near);
1057 }
1058 
1059