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