1 module raymath;
2 
3 import raylib;
4 
5 /**********************************************************************************************
6 *
7 *   raymath v1.2 - Math functions to work with Vector3, Matrix and Quaternions
8 *
9 *   CONFIGURATION:
10 *
11 *   #define RAYMATH_IMPLEMENTATION
12 *       Generates the implementation of the library into the included file.
13 *       If not defined, the library is in header only mode and can be included in other headers
14 *       or source files without problems. But only ONE file should hold the implementation.
15 *
16 *   #define RAYMATH_HEADER_ONLY
17 *       Define static inline functions code, so #include header suffices for use.
18 *       This may use up lots of memory.
19 *
20 *   #define RAYMATH_STANDALONE
21 *       Avoid raylib.h header inclusion in this file.
22 *       Vector3 and Matrix data types are defined internally in raymath module.
23 *
24 *
25 *   LICENSE: zlib/libpng
26 *
27 *   Copyright (c) 2015-2020 Ramon Santamaria (@raysan5)
28 *
29 *   This software is provided "as-is", without any express or implied warranty. In no event
30 *   will the authors be held liable for any damages arising from the use of this software.
31 *
32 *   Permission is granted to anyone to use this software for any purpose, including commercial
33 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
34 *
35 *     1. The origin of this software must not be misrepresented; you must not claim that you
36 *     wrote the original software. If you use this software in a product, an acknowledgment
37 *     in the product documentation would be appreciated but is not required.
38 *
39 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
40 *     as being the original software.
41 *
42 *     3. This notice may not be removed or altered from any source distribution.
43 *
44 **********************************************************************************************/
45 
46 extern (C) @nogc nothrow:
47 
48 //#define RAYMATH_STANDALONE      // NOTE: To use raymath as standalone lib, just uncomment this line
49 //#define RAYMATH_HEADER_ONLY     // NOTE: To compile functions as static inline, uncomment this line
50 
51 import raylib; // Required for structs: Vector3, Matrix
52 
53 //----------------------------------------------------------------------------------
54 // Defines and Macros
55 //----------------------------------------------------------------------------------
56 
57 // Return float vector for Matrix
58 
59 extern (D) auto MatrixToFloat(T)(auto ref T mat)
60 {
61     return MatrixToFloatV(mat).v;
62 }
63 
64 // Return float vector for Vector3
65 
66 extern (D) auto Vector3ToFloat(T)(auto ref T vec)
67 {
68     return Vector3ToFloatV(vec).v;
69 }
70 
71 // NOTE: Helper types to be used instead of array return types for *ToFloat functions
72 struct float3
73 {
74     float[3] v;
75 }
76 
77 struct float16
78 {
79     float[16] v;
80 }
81 
82 import core.stdc.math; // Required for: sinf(), cosf(), sqrtf(), tan(), fabs()
83 
84 pragma(inline, true):
85 
86 //----------------------------------------------------------------------------------
87 // Module Functions Definition - Utils math
88 //----------------------------------------------------------------------------------
89 
90 // Clamp float value
91 static float Clamp(float value, float min, float max)
92 {
93     float result = (value < min)? min : value;
94 
95     if (result > max) result = max;
96 
97     return result;
98 }
99 
100 // Calculate linear interpolation between two floats
101 static float Lerp(float start, float end, float amount)
102 {
103     float result = start + amount*(end - start);
104 
105     return result;
106 }
107 
108 // Normalize input value within input range
109 static float Normalize(float value, float start, float end)
110 {
111     float result = (value - start)/(end - start);
112 
113     return result;
114 }
115 
116 // Remap input value within input range to output range
117 static float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
118 {
119     float result =(value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart;
120 
121     return result;
122 }
123 
124 //----------------------------------------------------------------------------------
125 // Module Functions Definition - Vector2 math
126 //----------------------------------------------------------------------------------
127 
128 // Vector with components value 0.0f
129 static Vector2 Vector2Zero()
130 {
131     Vector2 result = { 0.0f, 0.0f };
132 
133     return result;
134 }
135 
136 // Vector with components value 1.0f
137 static Vector2 Vector2One()
138 {
139     Vector2 result = { 1.0f, 1.0f };
140 
141     return result;
142 }
143 
144 // Add two vectors (v1 + v2)
145 static Vector2 Vector2Add(Vector2 v1, Vector2 v2)
146 {
147     Vector2 result = { v1.x + v2.x, v1.y + v2.y };
148 
149     return result;
150 }
151 
152 // Add vector and float value
153 static Vector2 Vector2AddValue(Vector2 v, float add)
154 {
155     Vector2 result = { v.x + add, v.y + add };
156 
157     return result;
158 }
159 
160 // Subtract two vectors (v1 - v2)
161 static Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
162 {
163     Vector2 result = { v1.x - v2.x, v1.y - v2.y };
164 
165     return result;
166 }
167 
168 // Subtract vector by float value
169 static Vector2 Vector2SubtractValue(Vector2 v, float sub)
170 {
171     Vector2 result = { v.x - sub, v.y - sub };
172 
173     return result;
174 }
175 
176 // Calculate vector length
177 static float Vector2Length(Vector2 v)
178 {
179     float result = sqrtf((v.x*v.x) + (v.y*v.y));
180 
181     return result;
182 }
183 
184 // Calculate vector square length
185 static float Vector2LengthSqr(Vector2 v)
186 {
187     float result = (v.x*v.x) + (v.y*v.y);
188 
189     return result;
190 }
191 
192 // Calculate two vectors dot product
193 static float Vector2DotProduct(Vector2 v1, Vector2 v2)
194 {
195     float result = (v1.x*v2.x + v1.y*v2.y);
196 
197     return result;
198 }
199 
200 // Calculate distance between two vectors
201 static float Vector2Distance(Vector2 v1, Vector2 v2)
202 {
203     float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));
204 
205     return result;
206 }
207 
208 // Calculate angle from two vectors in X-axis
209 static float Vector2Angle(Vector2 v1, Vector2 v2)
210 {
211     float result = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
212 
213     if (result < 0) result += 360.0f;
214 
215     return result;
216 }
217 
218 // Scale vector (multiply by value)
219 static Vector2 Vector2Scale(Vector2 v, float scale)
220 {
221     Vector2 result = { v.x*scale, v.y*scale };
222 
223     return result;
224 }
225 
226 // Multiply vector by vector
227 static Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)
228 {
229     Vector2 result = { v1.x*v2.x, v1.y*v2.y };
230 
231     return result;
232 }
233 
234 // Negate vector
235 static Vector2 Vector2Negate(Vector2 v)
236 {
237     Vector2 result = { -v.x, -v.y };
238 
239     return result;
240 }
241 
242 // Divide vector by vector
243 static Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
244 {
245     Vector2 result = { v1.x/v2.x, v1.y/v2.y };
246 
247     return result;
248 }
249 
250 // Normalize provided vector
251 static Vector2 Vector2Normalize(Vector2 v)
252 {
253     Vector2 result = { 0 };
254     float length = sqrtf((v.x*v.x) + (v.y*v.y));
255 
256     if (length > 0)
257     {
258         result.x = v.x*1.0f/length;
259         result.y = v.y*1.0f/length;
260     }
261 
262     return result;
263 }
264 
265 // Calculate linear interpolation between two vectors
266 static Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
267 {
268     Vector2 result = { 0 };
269 
270     result.x = v1.x + amount*(v2.x - v1.x);
271     result.y = v1.y + amount*(v2.y - v1.y);
272 
273     return result;
274 }
275 
276 // Calculate reflected vector to normal
277 static Vector2 Vector2Reflect(Vector2 v, Vector2 normal)
278 {
279     Vector2 result = { 0 };
280 
281     float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product
282 
283     result.x = v.x - (2.0f*normal.x)*dotProduct;
284     result.y = v.y - (2.0f*normal.y)*dotProduct;
285 
286     return result;
287 }
288 
289 // Rotate vector by angle
290 static Vector2 Vector2Rotate(Vector2 v, float angle)
291 {
292     Vector2 result = { 0 };
293 
294     result.x = v.x*cosf(angle) - v.y*sinf(angle);
295     result.y = v.x*sinf(angle) + v.y*cosf(angle);
296 
297     return result;
298 }
299 
300 // Move Vector towards target
301 static Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
302 {
303     Vector2 result = { 0 };
304 
305     float dx = target.x - v.x;
306     float dy = target.y - v.y;
307     float value = (dx*dx) + (dy*dy);
308 
309     if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target;
310 
311     float dist = sqrtf(value);
312 
313     result.x = v.x + dx/dist*maxDistance;
314     result.y = v.y + dy/dist*maxDistance;
315 
316     return result;
317 }
318 
319 //----------------------------------------------------------------------------------
320 // Module Functions Definition - Vector3 math
321 //----------------------------------------------------------------------------------
322 
323 // Vector with components value 0.0f
324 static Vector3 Vector3Zero()
325 {
326     Vector3 result = { 0.0f, 0.0f, 0.0f };
327 
328     return result;
329 }
330 
331 // Vector with components value 1.0f
332 static Vector3 Vector3One()
333 {
334     Vector3 result = { 1.0f, 1.0f, 1.0f };
335 
336     return result;
337 }
338 
339 // Add two vectors
340 static Vector3 Vector3Add(Vector3 v1, Vector3 v2)
341 {
342     Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
343 
344     return result;
345 }
346 
347 // Add vector and float value
348 static Vector3 Vector3AddValue(Vector3 v, float add)
349 {
350     Vector3 result = { v.x + add, v.y + add, v.z + add };
351 
352     return result;
353 }
354 
355 // Subtract two vectors
356 static Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
357 {
358     Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
359 
360     return result;
361 }
362 
363 // Subtract vector by float value
364 static Vector3 Vector3SubtractValue(Vector3 v, float sub)
365 {
366     Vector3 result = { v.x - sub, v.y - sub, v.z - sub };
367 
368     return result;
369 }
370 
371 // Multiply vector by scalar
372 static Vector3 Vector3Scale(Vector3 v, float scalar)
373 {
374     Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar };
375 
376     return result;
377 }
378 
379 // Multiply vector by vector
380 static Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)
381 {
382     Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z };
383 
384     return result;
385 }
386 
387 // Calculate two vectors cross product
388 static Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)
389 {
390     Vector3 result = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x };
391 
392     return result;
393 }
394 
395 // Calculate one vector perpendicular vector
396 static Vector3 Vector3Perpendicular(Vector3 v)
397 {
398     Vector3 result = { 0 };
399 
400     float min = cast(float) fabs(v.x);
401     Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f};
402 
403     if (fabs(v.y) < min)
404     {
405         min = cast(float) fabs(v.y);
406         Vector3 tmp = {0.0f, 1.0f, 0.0f};
407         cardinalAxis = tmp;
408     }
409 
410     if (fabs(v.z) < min)
411     {
412         Vector3 tmp = {0.0f, 0.0f, 1.0f};
413         cardinalAxis = tmp;
414     }
415 
416     // Cross product between vectors
417     result.x = v.y*cardinalAxis.z - v.z*cardinalAxis.y;
418     result.y = v.z*cardinalAxis.x - v.x*cardinalAxis.z;
419     result.z = v.x*cardinalAxis.y - v.y*cardinalAxis.x;
420 
421     return result;
422 }
423 
424 // Calculate vector length
425 static float Vector3Length(const Vector3 v)
426 {
427     float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
428 
429     return result;
430 }
431 
432 // Calculate vector square length
433 static float Vector3LengthSqr(const Vector3 v)
434 {
435     float result = v.x*v.x + v.y*v.y + v.z*v.z;
436 
437     return result;
438 }
439 
440 // Calculate two vectors dot product
441 static float Vector3DotProduct(Vector3 v1, Vector3 v2)
442 {
443     float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
444 
445     return result;
446 }
447 
448 // Calculate distance between two vectors
449 static float Vector3Distance(Vector3 v1, Vector3 v2)
450 {
451     float result = 0.0f;
452 
453     float dx = v2.x - v1.x;
454     float dy = v2.y - v1.y;
455     float dz = v2.z - v1.z;
456     result = sqrtf(dx*dx + dy*dy + dz*dz);
457 
458     return result;
459 }
460 
461 // Calculate angle between two vectors in XY and XZ
462 static Vector2 Vector3Angle(Vector3 v1, Vector3 v2)
463 {
464     Vector2 result = { 0 };
465 
466     float dx = v2.x - v1.x;
467     float dy = v2.y - v1.y;
468     float dz = v2.z - v1.z;
469 
470     result.x = atan2f(dx, dz);                      // Angle in XZ
471     result.y = atan2f(dy, sqrtf(dx*dx + dz*dz));    // Angle in XY
472 
473     return result;
474 }
475 
476 // Negate provided vector (invert direction)
477 static Vector3 Vector3Negate(Vector3 v)
478 {
479     Vector3 result = { -v.x, -v.y, -v.z };
480 
481     return result;
482 }
483 
484 // Divide vector by vector
485 static Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
486 {
487     Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
488 
489     return result;
490 }
491 
492 // Normalize provided vector
493 static Vector3 Vector3Normalize(Vector3 v)
494 {
495     Vector3 result = v;
496 
497     float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
498     if (length == 0.0f) length = 1.0f;
499     float ilength = 1.0f/length;
500 
501     result.x *= ilength;
502     result.y *= ilength;
503     result.z *= ilength;
504 
505     return result;
506 }
507 
508 // Orthonormalize provided vectors
509 // Makes vectors normalized and orthogonal to each other
510 // Gram-Schmidt function implementation
511 static void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2)
512 {
513     float length = 0.0f;
514     float ilength = 0.0f;
515 
516     // Vector3Normalize(*v1);
517     Vector3 v = *v1;
518     length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
519     if (length == 0.0f) length = 1.0f;
520     ilength = 1.0f/length;
521     v1.x *= ilength;
522     v1.y *= ilength;
523     v1.z *= ilength;
524 
525     // Vector3CrossProduct(*v1, *v2)
526     Vector3 vn1 = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x };
527 
528     // Vector3Normalize(vn1);
529     v = vn1;
530     length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
531     if (length == 0.0f) length = 1.0f;
532     ilength = 1.0f/length;
533     vn1.x *= ilength;
534     vn1.y *= ilength;
535     vn1.z *= ilength;
536 
537     // Vector3CrossProduct(vn1, *v1)
538     Vector3 vn2 = { vn1.y*v1.z - vn1.z*v1.y, vn1.z*v1.x - vn1.x*v1.z, vn1.x*v1.y - vn1.y*v1.x };
539 
540     *v2 = vn2;
541 }
542 
543 // Transforms a Vector3 by a given Matrix
544 static Vector3 Vector3Transform(Vector3 v, Matrix mat)
545 {
546     Vector3 result = { 0 };
547 
548     float x = v.x;
549     float y = v.y;
550     float z = v.z;
551 
552     result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;
553     result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;
554     result.z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14;
555 
556     return result;
557 }
558 
559 // Transform a vector by quaternion rotation
560 static Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)
561 {
562     Vector3 result = { 0 };
563 
564     result.x = v.x*(q.x*q.x + q.w*q.w - q.y*q.y - q.z*q.z) + v.y*(2*q.x*q.y - 2*q.w*q.z) + v.z*(2*q.x*q.z + 2*q.w*q.y);
565     result.y = v.x*(2*q.w*q.z + 2*q.x*q.y) + v.y*(q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z) + v.z*(-2*q.w*q.x + 2*q.y*q.z);
566     result.z = v.x*(-2*q.w*q.y + 2*q.x*q.z) + v.y*(2*q.w*q.x + 2*q.y*q.z)+ v.z*(q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z);
567 
568     return result;
569 }
570 
571 // Calculate linear interpolation between two vectors
572 static Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
573 {
574     Vector3 result = { 0 };
575 
576     result.x = v1.x + amount*(v2.x - v1.x);
577     result.y = v1.y + amount*(v2.y - v1.y);
578     result.z = v1.z + amount*(v2.z - v1.z);
579 
580     return result;
581 }
582 
583 // Calculate reflected vector to normal
584 static Vector3 Vector3Reflect(Vector3 v, Vector3 normal)
585 {
586     Vector3 result = { 0 };
587 
588     // I is the original vector
589     // N is the normal of the incident plane
590     // R = I - (2*N*(DotProduct[I, N]))
591 
592     float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z);
593 
594     result.x = v.x - (2.0f*normal.x)*dotProduct;
595     result.y = v.y - (2.0f*normal.y)*dotProduct;
596     result.z = v.z - (2.0f*normal.z)*dotProduct;
597 
598     return result;
599 }
600 
601 // Get min value for each pair of components
602 static Vector3 Vector3Min(Vector3 v1, Vector3 v2)
603 {
604     Vector3 result = { 0 };
605 
606     result.x = fminf(v1.x, v2.x);
607     result.y = fminf(v1.y, v2.y);
608     result.z = fminf(v1.z, v2.z);
609 
610     return result;
611 }
612 
613 // Get max value for each pair of components
614 static Vector3 Vector3Max(Vector3 v1, Vector3 v2)
615 {
616     Vector3 result = { 0 };
617 
618     result.x = fmaxf(v1.x, v2.x);
619     result.y = fmaxf(v1.y, v2.y);
620     result.z = fmaxf(v1.z, v2.z);
621 
622     return result;
623 }
624 
625 // Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)
626 // NOTE: Assumes P is on the plane of the triangle
627 static Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
628 {
629     Vector3 result = { 0 };
630 
631     Vector3 v0 = { b.x - a.x, b.y - a.y, b.z - a.z };   // Vector3Subtract(b, a)
632     Vector3 v1 = { c.x - a.x, c.y - a.y, c.z - a.z };   // Vector3Subtract(c, a)
633     Vector3 v2 = { p.x - a.x, p.y - a.y, p.z - a.z };   // Vector3Subtract(p, a)
634     float d00 = (v0.x*v0.x + v0.y*v0.y + v0.z*v0.z);    // Vector3DotProduct(v0, v0)
635     float d01 = (v0.x*v1.x + v0.y*v1.y + v0.z*v1.z);    // Vector3DotProduct(v0, v1)
636     float d11 = (v1.x*v1.x + v1.y*v1.y + v1.z*v1.z);    // Vector3DotProduct(v1, v1)
637     float d20 = (v2.x*v0.x + v2.y*v0.y + v2.z*v0.z);    // Vector3DotProduct(v2, v0)
638     float d21 = (v2.x*v1.x + v2.y*v1.y + v2.z*v1.z);    // Vector3DotProduct(v2, v1)
639 
640     float denom = d00*d11 - d01*d01;
641 
642     result.y = (d11*d20 - d01*d21)/denom;
643     result.z = (d00*d21 - d01*d20)/denom;
644     result.x = 1.0f - (result.z + result.y);
645 
646     return result;
647 }
648 
649 // Projects a Vector3 from screen space into object space
650 // NOTE: We are avoiding calling other raymath functions despite available
651 static Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
652 {
653     Vector3 result = { 0 };
654 
655     // Calculate unproject matrix (multiply view patrix by projection matrix) and invert it
656     Matrix matViewProj = {      // MatrixMultiply(view, projection);
657         view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12,
658         view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13,
659         view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14,
660         view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15,
661         view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12,
662         view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13,
663         view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14,
664         view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15,
665         view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12,
666         view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13,
667         view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14,
668         view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15,
669         view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12,
670         view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13,
671         view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14,
672         view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 };
673 
674     // Calculate inverted matrix . MatrixInvert(matViewProj);
675     // Cache the matrix values (speed optimization)
676     float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3;
677     float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7;
678     float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11;
679     float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15;
680 
681     float b00 = a00*a11 - a01*a10;
682     float b01 = a00*a12 - a02*a10;
683     float b02 = a00*a13 - a03*a10;
684     float b03 = a01*a12 - a02*a11;
685     float b04 = a01*a13 - a03*a11;
686     float b05 = a02*a13 - a03*a12;
687     float b06 = a20*a31 - a21*a30;
688     float b07 = a20*a32 - a22*a30;
689     float b08 = a20*a33 - a23*a30;
690     float b09 = a21*a32 - a22*a31;
691     float b10 = a21*a33 - a23*a31;
692     float b11 = a22*a33 - a23*a32;
693 
694     // Calculate the invert determinant (inlined to avoid double-caching)
695     float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
696 
697     Matrix matViewProjInv = {
698         (a11*b11 - a12*b10 + a13*b09)*invDet,
699         (-a01*b11 + a02*b10 - a03*b09)*invDet,
700         (a31*b05 - a32*b04 + a33*b03)*invDet,
701         (-a21*b05 + a22*b04 - a23*b03)*invDet,
702         (-a10*b11 + a12*b08 - a13*b07)*invDet,
703         (a00*b11 - a02*b08 + a03*b07)*invDet,
704         (-a30*b05 + a32*b02 - a33*b01)*invDet,
705         (a20*b05 - a22*b02 + a23*b01)*invDet,
706         (a10*b10 - a11*b08 + a13*b06)*invDet,
707         (-a00*b10 + a01*b08 - a03*b06)*invDet,
708         (a30*b04 - a31*b02 + a33*b00)*invDet,
709         (-a20*b04 + a21*b02 - a23*b00)*invDet,
710         (-a10*b09 + a11*b07 - a12*b06)*invDet,
711         (a00*b09 - a01*b07 + a02*b06)*invDet,
712         (-a30*b03 + a31*b01 - a32*b00)*invDet,
713         (a20*b03 - a21*b01 + a22*b00)*invDet };
714 
715     // Create quaternion from source point
716     Quaternion quat = { source.x, source.y, source.z, 1.0f };
717 
718     // Multiply quat point by unproject matrix
719     Quaternion qtransformed = {     // QuaternionTransform(quat, matViewProjInv)
720         matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,
721         matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,
722         matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w,
723         matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w };
724 
725     // Normalized world points in vectors
726     result.x = qtransformed.x/qtransformed.w;
727     result.y = qtransformed.y/qtransformed.w;
728     result.z = qtransformed.z/qtransformed.w;
729 
730     return result;
731 }
732 
733 // Get Vector3 as float array
734 static float3 Vector3ToFloatV(Vector3 v)
735 {
736     float3 buffer = { 0 };
737 
738     buffer.v[0] = v.x;
739     buffer.v[1] = v.y;
740     buffer.v[2] = v.z;
741 
742     return buffer;
743 }
744 
745 //----------------------------------------------------------------------------------
746 // Module Functions Definition - Matrix math
747 //----------------------------------------------------------------------------------
748 
749 // Compute matrix determinant
750 static float MatrixDeterminant(Matrix mat)
751 {
752     float result = 0.0f;
753 
754     // Cache the matrix values (speed optimization)
755     float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
756     float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
757     float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
758     float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
759 
760     result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
761              a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
762              a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
763              a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
764              a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
765              a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
766 
767     return result;
768 }
769 
770 // Get the trace of the matrix (sum of the values along the diagonal)
771 static float MatrixTrace(Matrix mat)
772 {
773     float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15);
774 
775     return result;
776 }
777 
778 // Transposes provided matrix
779 static Matrix MatrixTranspose(Matrix mat)
780 {
781     Matrix result = { 0 };
782 
783     result.m0 = mat.m0;
784     result.m1 = mat.m4;
785     result.m2 = mat.m8;
786     result.m3 = mat.m12;
787     result.m4 = mat.m1;
788     result.m5 = mat.m5;
789     result.m6 = mat.m9;
790     result.m7 = mat.m13;
791     result.m8 = mat.m2;
792     result.m9 = mat.m6;
793     result.m10 = mat.m10;
794     result.m11 = mat.m14;
795     result.m12 = mat.m3;
796     result.m13 = mat.m7;
797     result.m14 = mat.m11;
798     result.m15 = mat.m15;
799 
800     return result;
801 }
802 
803 // Invert provided matrix
804 static Matrix MatrixInvert(Matrix mat)
805 {
806     Matrix result = { 0 };
807 
808     // Cache the matrix values (speed optimization)
809     float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
810     float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
811     float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
812     float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
813 
814     float b00 = a00*a11 - a01*a10;
815     float b01 = a00*a12 - a02*a10;
816     float b02 = a00*a13 - a03*a10;
817     float b03 = a01*a12 - a02*a11;
818     float b04 = a01*a13 - a03*a11;
819     float b05 = a02*a13 - a03*a12;
820     float b06 = a20*a31 - a21*a30;
821     float b07 = a20*a32 - a22*a30;
822     float b08 = a20*a33 - a23*a30;
823     float b09 = a21*a32 - a22*a31;
824     float b10 = a21*a33 - a23*a31;
825     float b11 = a22*a33 - a23*a32;
826 
827     // Calculate the invert determinant (inlined to avoid double-caching)
828     float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
829 
830     result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet;
831     result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet;
832     result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet;
833     result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet;
834     result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet;
835     result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet;
836     result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet;
837     result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet;
838     result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet;
839     result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet;
840     result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet;
841     result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet;
842     result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet;
843     result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet;
844     result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet;
845     result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet;
846 
847     return result;
848 }
849 
850 // Normalize provided matrix
851 static Matrix MatrixNormalize(Matrix mat)
852 {
853     Matrix result = { 0 };
854 
855     // Cache the matrix values (speed optimization)
856     float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
857     float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
858     float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
859     float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
860 
861     // MatrixDeterminant(mat)
862     float det = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
863                 a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
864                 a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
865                 a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
866                 a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
867                 a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
868 
869     result.m0 = mat.m0/det;
870     result.m1 = mat.m1/det;
871     result.m2 = mat.m2/det;
872     result.m3 = mat.m3/det;
873     result.m4 = mat.m4/det;
874     result.m5 = mat.m5/det;
875     result.m6 = mat.m6/det;
876     result.m7 = mat.m7/det;
877     result.m8 = mat.m8/det;
878     result.m9 = mat.m9/det;
879     result.m10 = mat.m10/det;
880     result.m11 = mat.m11/det;
881     result.m12 = mat.m12/det;
882     result.m13 = mat.m13/det;
883     result.m14 = mat.m14/det;
884     result.m15 = mat.m15/det;
885 
886     return result;
887 }
888 
889 // Get identity matrix
890 static Matrix MatrixIdentity()
891 {
892     Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
893                       0.0f, 1.0f, 0.0f, 0.0f,
894                       0.0f, 0.0f, 1.0f, 0.0f,
895                       0.0f, 0.0f, 0.0f, 1.0f };
896 
897     return result;
898 }
899 
900 // Add two matrices
901 static Matrix MatrixAdd(Matrix left, Matrix right)
902 {
903     Matrix result = { 0 };
904 
905     result.m0 = left.m0 + right.m0;
906     result.m1 = left.m1 + right.m1;
907     result.m2 = left.m2 + right.m2;
908     result.m3 = left.m3 + right.m3;
909     result.m4 = left.m4 + right.m4;
910     result.m5 = left.m5 + right.m5;
911     result.m6 = left.m6 + right.m6;
912     result.m7 = left.m7 + right.m7;
913     result.m8 = left.m8 + right.m8;
914     result.m9 = left.m9 + right.m9;
915     result.m10 = left.m10 + right.m10;
916     result.m11 = left.m11 + right.m11;
917     result.m12 = left.m12 + right.m12;
918     result.m13 = left.m13 + right.m13;
919     result.m14 = left.m14 + right.m14;
920     result.m15 = left.m15 + right.m15;
921 
922     return result;
923 }
924 
925 // Subtract two matrices (left - right)
926 static Matrix MatrixSubtract(Matrix left, Matrix right)
927 {
928     Matrix result = { 0 };
929 
930     result.m0 = left.m0 - right.m0;
931     result.m1 = left.m1 - right.m1;
932     result.m2 = left.m2 - right.m2;
933     result.m3 = left.m3 - right.m3;
934     result.m4 = left.m4 - right.m4;
935     result.m5 = left.m5 - right.m5;
936     result.m6 = left.m6 - right.m6;
937     result.m7 = left.m7 - right.m7;
938     result.m8 = left.m8 - right.m8;
939     result.m9 = left.m9 - right.m9;
940     result.m10 = left.m10 - right.m10;
941     result.m11 = left.m11 - right.m11;
942     result.m12 = left.m12 - right.m12;
943     result.m13 = left.m13 - right.m13;
944     result.m14 = left.m14 - right.m14;
945     result.m15 = left.m15 - right.m15;
946 
947     return result;
948 }
949 
950 // Get two matrix multiplication
951 // NOTE: When multiplying matrices... the order matters!
952 static Matrix MatrixMultiply(Matrix left, Matrix right)
953 {
954     Matrix result = { 0 };
955 
956     result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
957     result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
958     result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
959     result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;
960     result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;
961     result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;
962     result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;
963     result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;
964     result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;
965     result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;
966     result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;
967     result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;
968     result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;
969     result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
970     result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
971     result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
972 
973     return result;
974 }
975 
976 // Get translation matrix
977 static Matrix MatrixTranslate(float x, float y, float z)
978 {
979     Matrix result = { 1.0f, 0.0f, 0.0f, x,
980                       0.0f, 1.0f, 0.0f, y,
981                       0.0f, 0.0f, 1.0f, z,
982                       0.0f, 0.0f, 0.0f, 1.0f };
983 
984     return result;
985 }
986 
987 // Create rotation matrix from axis and angle
988 // NOTE: Angle should be provided in radians
989 static Matrix MatrixRotate(Vector3 axis, float angle)
990 {
991     Matrix result = { 0 };
992 
993     float x = axis.x, y = axis.y, z = axis.z;
994 
995     float lengthSquared = x*x + y*y + z*z;
996 
997     if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f))
998     {
999         float ilength = 1.0f/sqrtf(lengthSquared);
1000         x *= ilength;
1001         y *= ilength;
1002         z *= ilength;
1003     }
1004 
1005     float sinres = sinf(angle);
1006     float cosres = cosf(angle);
1007     float t = 1.0f - cosres;
1008 
1009     result.m0 = x*x*t + cosres;
1010     result.m1 = y*x*t + z*sinres;
1011     result.m2 = z*x*t - y*sinres;
1012     result.m3 = 0.0f;
1013 
1014     result.m4 = x*y*t - z*sinres;
1015     result.m5 = y*y*t + cosres;
1016     result.m6 = z*y*t + x*sinres;
1017     result.m7 = 0.0f;
1018 
1019     result.m8 = x*z*t + y*sinres;
1020     result.m9 = y*z*t - x*sinres;
1021     result.m10 = z*z*t + cosres;
1022     result.m11 = 0.0f;
1023 
1024     result.m12 = 0.0f;
1025     result.m13 = 0.0f;
1026     result.m14 = 0.0f;
1027     result.m15 = 1.0f;
1028 
1029     return result;
1030 }
1031 
1032 // Get x-rotation matrix (angle in radians)
1033 static Matrix MatrixRotateX(float angle)
1034 {
1035     Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1036                       0.0f, 1.0f, 0.0f, 0.0f,
1037                       0.0f, 0.0f, 1.0f, 0.0f,
1038                       0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1039 
1040     float cosres = cosf(angle);
1041     float sinres = sinf(angle);
1042 
1043     result.m5 = cosres;
1044     result.m6 = -sinres;
1045     result.m9 = sinres;
1046     result.m10 = cosres;
1047 
1048     return result;
1049 }
1050 
1051 // Get y-rotation matrix (angle in radians)
1052 static Matrix MatrixRotateY(float angle)
1053 {
1054     Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1055                       0.0f, 1.0f, 0.0f, 0.0f,
1056                       0.0f, 0.0f, 1.0f, 0.0f,
1057                       0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1058 
1059     float cosres = cosf(angle);
1060     float sinres = sinf(angle);
1061 
1062     result.m0 = cosres;
1063     result.m2 = sinres;
1064     result.m8 = -sinres;
1065     result.m10 = cosres;
1066 
1067     return result;
1068 }
1069 
1070 // Get z-rotation matrix (angle in radians)
1071 static Matrix MatrixRotateZ(float angle)
1072 {
1073     Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1074                       0.0f, 1.0f, 0.0f, 0.0f,
1075                       0.0f, 0.0f, 1.0f, 0.0f,
1076                       0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1077 
1078     float cosres = cosf(angle);
1079     float sinres = sinf(angle);
1080 
1081     result.m0 = cosres;
1082     result.m1 = -sinres;
1083     result.m4 = sinres;
1084     result.m5 = cosres;
1085 
1086     return result;
1087 }
1088 
1089 
1090 // Get xyz-rotation matrix (angles in radians)
1091 static Matrix MatrixRotateXYZ(Vector3 ang)
1092 {
1093     Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1094                       0.0f, 1.0f, 0.0f, 0.0f,
1095                       0.0f, 0.0f, 1.0f, 0.0f,
1096                       0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1097 
1098     float cosz = cosf(-ang.z);
1099     float sinz = sinf(-ang.z);
1100     float cosy = cosf(-ang.y);
1101     float siny = sinf(-ang.y);
1102     float cosx = cosf(-ang.x);
1103     float sinx = sinf(-ang.x);
1104 
1105     result.m0 = cosz*cosy;
1106     result.m4 = (cosz*siny*sinx) - (sinz*cosx);
1107     result.m8 = (cosz*siny*cosx) + (sinz*sinx);
1108 
1109     result.m1 = sinz*cosy;
1110     result.m5 = (sinz*siny*sinx) + (cosz*cosx);
1111     result.m9 = (sinz*siny*cosx) - (cosz*sinx);
1112 
1113     result.m2 = -siny;
1114     result.m6 = cosy*sinx;
1115     result.m10= cosy*cosx;
1116 
1117     return result;
1118 }
1119 
1120 // Get zyx-rotation matrix (angles in radians)
1121 static Matrix MatrixRotateZYX(Vector3 ang)
1122 {
1123     Matrix result = { 0 };
1124 
1125     float cz = cosf(ang.z);
1126     float sz = sinf(ang.z);
1127     float cy = cosf(ang.y);
1128     float sy = sinf(ang.y);
1129     float cx = cosf(ang.x);
1130     float sx = sinf(ang.x);
1131 
1132     result.m0 = cz*cy;
1133     result.m1 = cz*sy*sx - cx*sz;
1134     result.m2 = sz*sx + cz*cx*sy;
1135     result.m3 = 0;
1136 
1137     result.m4 = cy*sz;
1138     result.m5 = cz*cx + sz*sy*sx;
1139     result.m6 = cx*sz*sy - cz*sx;
1140     result.m7 = 0;
1141 
1142     result.m8 = -sy;
1143     result.m9 = cy*sx;
1144     result.m10 = cy*cx;
1145     result.m11 = 0;
1146 
1147     result.m12 = 0;
1148     result.m13 = 0;
1149     result.m14 = 0;
1150     result.m15 = 1;
1151 
1152     return result;
1153 }
1154 
1155 // Get scaling matrix
1156 static Matrix MatrixScale(float x, float y, float z)
1157 {
1158     Matrix result = { x, 0.0f, 0.0f, 0.0f,
1159                       0.0f, y, 0.0f, 0.0f,
1160                       0.0f, 0.0f, z, 0.0f,
1161                       0.0f, 0.0f, 0.0f, 1.0f };
1162 
1163     return result;
1164 }
1165 
1166 // Get perspective projection matrix
1167 static Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)
1168 {
1169     Matrix result = { 0 };
1170 
1171     float rl = cast(float)(right - left);
1172     float tb = cast(float)(top - bottom);
1173     float fn = cast(float)(far - near);
1174 
1175     result.m0 = (cast(float)near*2.0f)/rl;
1176     result.m1 = 0.0f;
1177     result.m2 = 0.0f;
1178     result.m3 = 0.0f;
1179 
1180     result.m4 = 0.0f;
1181     result.m5 = (cast(float)near*2.0f)/tb;
1182     result.m6 = 0.0f;
1183     result.m7 = 0.0f;
1184 
1185     result.m8 = (cast(float)right + cast(float)left)/rl;
1186     result.m9 = (cast(float)top + cast(float)bottom)/tb;
1187     result.m10 = -(cast(float)far + cast(float)near)/fn;
1188     result.m11 = -1.0f;
1189 
1190     result.m12 = 0.0f;
1191     result.m13 = 0.0f;
1192     result.m14 = -(cast(float)far*cast(float)near*2.0f)/fn;
1193     result.m15 = 0.0f;
1194 
1195     return result;
1196 }
1197 
1198 // Get perspective projection matrix
1199 // NOTE: Angle should be provided in radians
1200 static Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
1201 {
1202     Matrix result = { 0 };
1203 
1204     double top = near*tan(fovy*0.5);
1205     double bottom = -top;
1206     double right = top*aspect;
1207     double left = -right;
1208 
1209     // MatrixFrustum(-right, right, -top, top, near, far);
1210     float rl = cast(float)(right - left);
1211     float tb = cast(float)(top - bottom);
1212     float fn = cast(float)(far - near);
1213 
1214     result.m0 = (cast(float)near*2.0f)/rl;
1215     result.m5 = (cast(float)near*2.0f)/tb;
1216     result.m8 = (cast(float)right + cast(float)left)/rl;
1217     result.m9 = (cast(float)top + cast(float)bottom)/tb;
1218     result.m10 = -(cast(float)far + cast(float)near)/fn;
1219     result.m11 = -1.0f;
1220     result.m14 = -(cast(float)far*cast(float)near*2.0f)/fn;
1221 
1222     return result;
1223 }
1224 
1225 // Get orthographic projection matrix
1226 static Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far)
1227 {
1228     Matrix result = { 0 };
1229 
1230     float rl = cast(float)(right - left);
1231     float tb = cast(float)(top - bottom);
1232     float fn = cast(float)(far - near);
1233 
1234     result.m0 = 2.0f/rl;
1235     result.m1 = 0.0f;
1236     result.m2 = 0.0f;
1237     result.m3 = 0.0f;
1238     result.m4 = 0.0f;
1239     result.m5 = 2.0f/tb;
1240     result.m6 = 0.0f;
1241     result.m7 = 0.0f;
1242     result.m8 = 0.0f;
1243     result.m9 = 0.0f;
1244     result.m10 = -2.0f/fn;
1245     result.m11 = 0.0f;
1246     result.m12 = -(cast(float)left + cast(float)right)/rl;
1247     result.m13 = -(cast(float)top + cast(float)bottom)/tb;
1248     result.m14 = -(cast(float)far + cast(float)near)/fn;
1249     result.m15 = 1.0f;
1250 
1251     return result;
1252 }
1253 
1254 // Get camera look-at matrix (view matrix)
1255 static Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
1256 {
1257     Matrix result = { 0 };
1258 
1259     float length = 0.0f;
1260     float ilength = 0.0f;
1261 
1262     // Vector3Subtract(eye, target)
1263     Vector3 vz = { eye.x - target.x, eye.y - target.y, eye.z - target.z };
1264 
1265     // Vector3Normalize(vz)
1266     Vector3 v = vz;
1267     length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
1268     if (length == 0.0f) length = 1.0f;
1269     ilength = 1.0f/length;
1270     vz.x *= ilength;
1271     vz.y *= ilength;
1272     vz.z *= ilength;
1273 
1274     // Vector3CrossProduct(up, vz)
1275     Vector3 vx = { up.y*vz.z - up.z*vz.y, up.z*vz.x - up.x*vz.z, up.x*vz.y - up.y*vz.x };
1276 
1277     // Vector3Normalize(x)
1278     v = vx;
1279     length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
1280     if (length == 0.0f) length = 1.0f;
1281     ilength = 1.0f/length;
1282     vx.x *= ilength;
1283     vx.y *= ilength;
1284     vx.z *= ilength;
1285 
1286     // Vector3CrossProduct(vz, vx)
1287     Vector3 vy = { vz.y*vx.z - vz.z*vx.y, vz.z*vx.x - vz.x*vx.z, vz.x*vx.y - vz.y*vx.x };
1288 
1289     result.m0 = vx.x;
1290     result.m1 = vy.x;
1291     result.m2 = vz.x;
1292     result.m3 = 0.0f;
1293     result.m4 = vx.y;
1294     result.m5 = vy.y;
1295     result.m6 = vz.y;
1296     result.m7 = 0.0f;
1297     result.m8 = vx.z;
1298     result.m9 = vy.z;
1299     result.m10 = vz.z;
1300     result.m11 = 0.0f;
1301     result.m12 = -(vx.x*eye.x + vx.y*eye.y + vx.z*eye.z);   // Vector3DotProduct(vx, eye)
1302     result.m13 = -(vy.x*eye.x + vy.y*eye.y + vy.z*eye.z);   // Vector3DotProduct(vy, eye)
1303     result.m14 = -(vz.x*eye.x + vz.y*eye.y + vz.z*eye.z);   // Vector3DotProduct(vz, eye)
1304     result.m15 = 1.0f;
1305 
1306     return result;
1307 }
1308 
1309 // Get float array of matrix data
1310 static float16 MatrixToFloatV(Matrix mat)
1311 {
1312     float16 result = { 0 };
1313 
1314     result.v[0] = mat.m0;
1315     result.v[1] = mat.m1;
1316     result.v[2] = mat.m2;
1317     result.v[3] = mat.m3;
1318     result.v[4] = mat.m4;
1319     result.v[5] = mat.m5;
1320     result.v[6] = mat.m6;
1321     result.v[7] = mat.m7;
1322     result.v[8] = mat.m8;
1323     result.v[9] = mat.m9;
1324     result.v[10] = mat.m10;
1325     result.v[11] = mat.m11;
1326     result.v[12] = mat.m12;
1327     result.v[13] = mat.m13;
1328     result.v[14] = mat.m14;
1329     result.v[15] = mat.m15;
1330 
1331     return result;
1332 }
1333 
1334 //----------------------------------------------------------------------------------
1335 // Module Functions Definition - Quaternion math
1336 //----------------------------------------------------------------------------------
1337 
1338 // Add two quaternions
1339 static Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)
1340 {
1341     Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w};
1342 
1343     return result;
1344 }
1345 
1346 // Add quaternion and float value
1347 static Quaternion QuaternionAddValue(Quaternion q, float add)
1348 {
1349     Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add};
1350 
1351     return result;
1352 }
1353 
1354 // Subtract two quaternions
1355 static Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)
1356 {
1357     Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w};
1358 
1359     return result;
1360 }
1361 
1362 // Subtract quaternion and float value
1363 static Quaternion QuaternionSubtractValue(Quaternion q, float sub)
1364 {
1365     Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub};
1366 
1367     return result;
1368 }
1369 
1370 // Get identity quaternion
1371 static Quaternion QuaternionIdentity()
1372 {
1373     Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
1374 
1375     return result;
1376 }
1377 
1378 // Computes the length of a quaternion
1379 static float QuaternionLength(Quaternion q)
1380 {
1381     float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
1382 
1383     return result;
1384 }
1385 
1386 // Normalize provided quaternion
1387 static Quaternion QuaternionNormalize(Quaternion q)
1388 {
1389     Quaternion result = { 0 };
1390 
1391     float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
1392     if (length == 0.0f) length = 1.0f;
1393     float ilength = 1.0f/length;
1394 
1395     result.x = q.x*ilength;
1396     result.y = q.y*ilength;
1397     result.z = q.z*ilength;
1398     result.w = q.w*ilength;
1399 
1400     return result;
1401 }
1402 
1403 // Invert provided quaternion
1404 static Quaternion QuaternionInvert(Quaternion q)
1405 {
1406     Quaternion result = q;
1407 
1408     float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
1409     float lengthSq = length*length;
1410 
1411     if (lengthSq != 0.0)
1412     {
1413         float invLength = 1.0f/lengthSq;
1414 
1415         result.x *= -invLength;
1416         result.y *= -invLength;
1417         result.z *= -invLength;
1418         result.w *= invLength;
1419     }
1420 
1421     return result;
1422 }
1423 
1424 // Calculate two quaternion multiplication
1425 static Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
1426 {
1427     Quaternion result = { 0 };
1428 
1429     float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w;
1430     float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w;
1431 
1432     result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby;
1433     result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz;
1434     result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx;
1435     result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz;
1436 
1437     return result;
1438 }
1439 
1440 // Scale quaternion by float value
1441 static Quaternion QuaternionScale(Quaternion q, float mul)
1442 {
1443     Quaternion result = { 0 };
1444 
1445     float qax = q.x, qay = q.y, qaz = q.z, qaw = q.w;
1446 
1447     result.x = qax*mul + qaw*mul + qay*mul - qaz*mul;
1448     result.y = qay*mul + qaw*mul + qaz*mul - qax*mul;
1449     result.z = qaz*mul + qaw*mul + qax*mul - qay*mul;
1450     result.w = qaw*mul - qax*mul - qay*mul - qaz*mul;
1451 
1452     return result;
1453 }
1454 
1455 // Divide two quaternions
1456 static Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)
1457 {
1458     Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w };
1459 
1460     return result;
1461 }
1462 
1463 // Calculate linear interpolation between two quaternions
1464 static Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
1465 {
1466     Quaternion result = { 0 };
1467 
1468     result.x = q1.x + amount*(q2.x - q1.x);
1469     result.y = q1.y + amount*(q2.y - q1.y);
1470     result.z = q1.z + amount*(q2.z - q1.z);
1471     result.w = q1.w + amount*(q2.w - q1.w);
1472 
1473     return result;
1474 }
1475 
1476 // Calculate slerp-optimized interpolation between two quaternions
1477 static Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)
1478 {
1479     Quaternion result = { 0 };
1480 
1481     // QuaternionLerp(q1, q2, amount)
1482     result.x = q1.x + amount*(q2.x - q1.x);
1483     result.y = q1.y + amount*(q2.y - q1.y);
1484     result.z = q1.z + amount*(q2.z - q1.z);
1485     result.w = q1.w + amount*(q2.w - q1.w);
1486 
1487     // QuaternionNormalize(q);
1488     Quaternion q = result;
1489     float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
1490     if (length == 0.0f) length = 1.0f;
1491     float ilength = 1.0f/length;
1492 
1493     result.x = q.x*ilength;
1494     result.y = q.y*ilength;
1495     result.z = q.z*ilength;
1496     result.w = q.w*ilength;
1497 
1498     return result;
1499 }
1500 
1501 // Calculates spherical linear interpolation between two quaternions
1502 static Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
1503 {
1504     Quaternion result = { 0 };
1505 
1506     float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
1507 
1508     if (cosHalfTheta < 0)
1509     {
1510         q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w;
1511         cosHalfTheta = -cosHalfTheta;
1512     }
1513 
1514     if (fabs(cosHalfTheta) >= 1.0f) result = q1;
1515     else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
1516     else
1517     {
1518         float halfTheta = acosf(cosHalfTheta);
1519         float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
1520 
1521         if (fabs(sinHalfTheta) < 0.001f)
1522         {
1523             result.x = (q1.x*0.5f + q2.x*0.5f);
1524             result.y = (q1.y*0.5f + q2.y*0.5f);
1525             result.z = (q1.z*0.5f + q2.z*0.5f);
1526             result.w = (q1.w*0.5f + q2.w*0.5f);
1527         }
1528         else
1529         {
1530             float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta;
1531             float ratioB = sinf(amount*halfTheta)/sinHalfTheta;
1532 
1533             result.x = (q1.x*ratioA + q2.x*ratioB);
1534             result.y = (q1.y*ratioA + q2.y*ratioB);
1535             result.z = (q1.z*ratioA + q2.z*ratioB);
1536             result.w = (q1.w*ratioA + q2.w*ratioB);
1537         }
1538     }
1539 
1540     return result;
1541 }
1542 
1543 // Calculate quaternion based on the rotation from one vector to another
1544 static Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
1545 {
1546     Quaternion result = { 0 };
1547 
1548     float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z);    // Vector3DotProduct(from, to)
1549     Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to)
1550 
1551     result.x = cross.x;
1552     result.y = cross.y;
1553     result.z = cross.z;
1554     result.w = 1.0f + cos2Theta;
1555 
1556     // QuaternionNormalize(q);
1557     // NOTE: Normalize to essentially nlerp the original and identity to 0.5
1558     Quaternion q = result;
1559     float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
1560     if (length == 0.0f) length = 1.0f;
1561     float ilength = 1.0f/length;
1562 
1563     result.x = q.x*ilength;
1564     result.y = q.y*ilength;
1565     result.z = q.z*ilength;
1566     result.w = q.w*ilength;
1567 
1568     return result;
1569 }
1570 
1571 // Get a quaternion for a given rotation matrix
1572 static Quaternion QuaternionFromMatrix(Matrix mat)
1573 {
1574     Quaternion result = { 0 };
1575 
1576     if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10))
1577     {
1578         float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2;
1579 
1580         result.x = 0.25f*s;
1581         result.y = (mat.m4 + mat.m1)/s;
1582         result.z = (mat.m2 + mat.m8)/s;
1583         result.w = (mat.m9 - mat.m6)/s;
1584     }
1585     else if (mat.m5 > mat.m10)
1586     {
1587         float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2;
1588         result.x = (mat.m4 + mat.m1)/s;
1589         result.y = 0.25f*s;
1590         result.z = (mat.m9 + mat.m6)/s;
1591         result.w = (mat.m2 - mat.m8)/s;
1592     }
1593     else
1594     {
1595         float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2;
1596         result.x = (mat.m2 + mat.m8)/s;
1597         result.y = (mat.m9 + mat.m6)/s;
1598         result.z = 0.25f*s;
1599         result.w = (mat.m4 - mat.m1)/s;
1600     }
1601 
1602     return result;
1603 }
1604 
1605 // Get a matrix for a given quaternion
1606 static Matrix QuaternionToMatrix(Quaternion q)
1607 {
1608     Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
1609                       0.0f, 1.0f, 0.0f, 0.0f,
1610                       0.0f, 0.0f, 1.0f, 0.0f,
1611                       0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
1612 
1613     float a2 = q.x*q.x;
1614     float b2 = q.y*q.y;
1615     float c2 = q.z*q.z;
1616     float ac = q.x*q.z;
1617     float ab = q.x*q.y;
1618     float bc = q.y*q.z;
1619     float ad = q.w*q.x;
1620     float bd = q.w*q.y;
1621     float cd = q.w*q.z;
1622 
1623     result.m0 = 1 - 2*(b2 + c2);
1624     result.m1 = 2*(ab + cd);
1625     result.m2 = 2*(ac - bd);
1626 
1627     result.m4 = 2*(ab - cd);
1628     result.m5 = 1 - 2*(a2 + c2);
1629     result.m6 = 2*(bc + ad);
1630 
1631     result.m8 = 2*(ac + bd);
1632     result.m9 = 2*(bc - ad);
1633     result.m10 = 1 - 2*(a2 + b2);
1634 
1635     return result;
1636 }
1637 
1638 // Get rotation quaternion for an angle and axis
1639 // NOTE: angle must be provided in radians
1640 static Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
1641 {
1642     Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
1643 
1644     float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
1645 
1646     if (axisLength != 0.0f)
1647     {
1648         angle *= 0.5f;
1649 
1650         float length = 0.0f;
1651         float ilength = 0.0f;
1652 
1653         // Vector3Normalize(axis)
1654         Vector3 v = axis;
1655         length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
1656         if (length == 0.0f) length = 1.0f;
1657         ilength = 1.0f/length;
1658         axis.x *= ilength;
1659         axis.y *= ilength;
1660         axis.z *= ilength;
1661 
1662         float sinres = sinf(angle);
1663         float cosres = cosf(angle);
1664 
1665         result.x = axis.x*sinres;
1666         result.y = axis.y*sinres;
1667         result.z = axis.z*sinres;
1668         result.w = cosres;
1669 
1670         // QuaternionNormalize(q);
1671         Quaternion q = result;
1672         length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
1673         if (length == 0.0f) length = 1.0f;
1674         ilength = 1.0f/length;
1675         result.x = q.x*ilength;
1676         result.y = q.y*ilength;
1677         result.z = q.z*ilength;
1678         result.w = q.w*ilength;
1679     }
1680 
1681     return result;
1682 }
1683 
1684 // Get the rotation angle and axis for a given quaternion
1685 static void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
1686 {
1687     if (fabs(q.w) > 1.0f)
1688     {
1689         // QuaternionNormalize(q);
1690         float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
1691         if (length == 0.0f) length = 1.0f;
1692         float ilength = 1.0f/length;
1693 
1694         q.x = q.x*ilength;
1695         q.y = q.y*ilength;
1696         q.z = q.z*ilength;
1697         q.w = q.w*ilength;
1698     }
1699 
1700     Vector3 resAxis = { 0.0f, 0.0f, 0.0f };
1701     float resAngle = 2.0f*acosf(q.w);
1702     float den = sqrtf(1.0f - q.w*q.w);
1703 
1704     if (den > 0.0001f)
1705     {
1706         resAxis.x = q.x/den;
1707         resAxis.y = q.y/den;
1708         resAxis.z = q.z/den;
1709     }
1710     else
1711     {
1712         // This occurs when the angle is zero.
1713         // Not a problem: just set an arbitrary normalized axis.
1714         resAxis.x = 1.0f;
1715     }
1716 
1717     *outAxis = resAxis;
1718     *outAngle = resAngle;
1719 }
1720 
1721 // Get the quaternion equivalent to Euler angles
1722 // NOTE: Rotation order is ZYX
1723 static Quaternion QuaternionFromEuler(float pitch, float yaw, float roll)
1724 {
1725     Quaternion result = { 0 };
1726 
1727     float x0 = cosf(pitch*0.5f);
1728     float x1 = sinf(pitch*0.5f);
1729     float y0 = cosf(yaw*0.5f);
1730     float y1 = sinf(yaw*0.5f);
1731     float z0 = cosf(roll*0.5f);
1732     float z1 = sinf(roll*0.5f);
1733 
1734     result.x = x1*y0*z0 - x0*y1*z1;
1735     result.y = x0*y1*z0 + x1*y0*z1;
1736     result.z = x0*y0*z1 - x1*y1*z0;
1737     result.w = x0*y0*z0 + x1*y1*z1;
1738 
1739     return result;
1740 }
1741 
1742 // Get the Euler angles equivalent to quaternion (roll, pitch, yaw)
1743 // NOTE: Angles are returned in a Vector3 struct in radians
1744 static Vector3 QuaternionToEuler(Quaternion q)
1745 {
1746     Vector3 result = { 0 };
1747 
1748     // Roll (x-axis rotation)
1749     float x0 = 2.0f*(q.w*q.x + q.y*q.z);
1750     float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y);
1751     result.x = atan2f(x0, x1);
1752 
1753     // Pitch (y-axis rotation)
1754     float y0 = 2.0f*(q.w*q.y - q.z*q.x);
1755     y0 = y0 > 1.0f ? 1.0f : y0;
1756     y0 = y0 < -1.0f ? -1.0f : y0;
1757     result.y = asinf(y0);
1758 
1759     // Yaw (z-axis rotation)
1760     float z0 = 2.0f*(q.w*q.z + q.x*q.y);
1761     float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z);
1762     result.z = atan2f(z0, z1);
1763 
1764     return result;
1765 }
1766 
1767 // Transform a quaternion given a transformation matrix
1768 static Quaternion QuaternionTransform(Quaternion q, Matrix mat)
1769 {
1770     Quaternion result = { 0 };
1771 
1772     result.x = mat.m0*q.x + mat.m4*q.y + mat.m8*q.z + mat.m12*q.w;
1773     result.y = mat.m1*q.x + mat.m5*q.y + mat.m9*q.z + mat.m13*q.w;
1774     result.z = mat.m2*q.x + mat.m6*q.y + mat.m10*q.z + mat.m14*q.w;
1775     result.w = mat.m3*q.x + mat.m7*q.y + mat.m11*q.z + mat.m15*q.w;
1776 
1777     return result;
1778 }