atomes 1.1.14
atomes: an atomic scale modeling tool box
Loading...
Searching...
No Matches
math_3d.h
Go to the documentation of this file.
1/* This file is part of the 'atomes' software
2
3'atomes' is free software: you can redistribute it and/or modify it under the terms
4of the GNU Affero General Public License as published by the Free Software Foundation,
5either version 3 of the License, or (at your option) any later version.
6
7'atomes' is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9See the GNU General Public License for more details.
10
11You should have received a copy of the GNU Affero General Public License along with 'atomes'.
12If not, see <https://www.gnu.org/licenses/>
13
14Copyright (C) 2022-2024 by CNRS and University of Strasbourg */
15
24/*
25* This header file: 'math_3d.h'
26*
27* Contains:
28
29 - Functions for OpenGL math
30
31*/
32
33/* The following was adapted from the file Math 3D v1.0
34By Stephan Soller <stephan.soller@helionweb.de> and Tobias Malmsheimer
35The original file was modified and completed to match 'atomes' needs. */
36
37/*
38Math 3D is a compact C99 library meant to be used with OpenGL. It provides basic
393D vector and 4x4 matrix operations as well as functions to create transformation
40and projection matrices. The OpenGL binary layout is used so you can just upload
41vectors and matrices into shaders and work with them without any conversions.
42
43It's an stb style single header file library. Define MATH_3D_IMPLEMENTATION
44before you include this file in *one* C file to create the implementation.
45
46
47QUICK NOTES
48
49- If not explicitly stated by a parameter name all angles are in radians.
50- The matrices use column-major indices. This is the same as in OpenGL and GLSL.
51 The matrix documentation below for details.
52- Matrices are passed by value. This is probably a bit inefficient but
53 simplifies code quite a bit. Most operations will be inlined by the compiler
54 anyway so the difference shouldn't matter that much. A matrix fits into 4 of
55 the 16 SSE2 registers anyway. If profiling shows significant slowdowns the
56 matrix type might change but ease of use is more important than every last
57 percent of performance.
58- When combining matrices with multiplication the effects apply right to left.
59 This is the convention used in mathematics and OpenGL. Source:
60 https://en.wikipedia.org/wiki/Transformation_matrix#Composing_and_inverting_transformations
61 Direct3D does it differently.
62- The `m4_mul_pos()` and `m4_mul_dir()` functions do a correct perspective
63 divide (division by w) when necessary. This is a bit slower but ensures that
64 the functions will properly work with projection matrices. If profiling shows
65 this is a bottleneck special functions without perspective division can be
66 added. But the normal multiplications should avoid any surprises.
67- The library consistently uses a right-handed coordinate system. The old
68 `glOrtho()` broke that rule and `m4_ortho()` has be slightly modified so you
69 can always think of right-handed cubes that are projected into OpenGLs
70 normalized device coordinates.
71- Special care has been taken to document all complex operations and important
72 sources. Most code is covered by test cases that have been manually calculated
73 and checked on the whiteboard. Since indices and math code is prone to be
74 confusing we used pair programming to avoid mistakes.
75
76
77FURTHER IDEAS
78
79These are ideas for future work on the library. They're implemented as soon as
80there is a proper use case and we can find good names for them.
81
82- bool v3_is_null(vec3_t v, float epsilon)
83 To check if the length of a vector is smaller than `epsilon`.
84- vec3_t v3_length_default(vec3_t v, float default_length, float epsilon)
85 Returns `default_length` if the length of `v` is smaller than `epsilon`.
86 Otherwise same as `v3_length()`.
87- vec3_t v3_norm_default(vec3_t v, vec3_t default_vector, float epsilon)
88 Returns `default_vector` if the length of `v` is smaller than `epsilon`.
89 Otherwise the same as `v3_norm()`.
90- mat4_t m4_invert(mat4_t matrix)
91 Matrix inversion that works with arbitrary matrices. `m4_invert_affine()` can
92 already invert translation, rotation, scaling, mirroring, reflection and
93 shearing matrices. So a general inversion might only be useful to invert
94 projection matrices for picking. But with orthographic and perspective
95 projection it's probably simpler to calculate the ray into the scene directly
96 based on the screen coordinates.
97
98
99VERSION HISTORY
100
101v1.0 2016-02-15 Initial release
102
103**/
104
105#ifndef MATH_3D_H_
106#define MATH_3D_H_
107
108#include <math.h>
109#include <stdio.h>
110
111
112// Define PI directly because we would need to define the _BSD_SOURCE or
113// _XOPEN_SOURCE feature test macros to get it from math.h. That would be a
114// rather harsh dependency. So we define it directly if necessary.
115#ifndef M_PI
116#define M_PI 3.14159265358979323846
117#endif
118
119
120//
121// 3D vectors
122//
123// Use the `vec3()` function to create vectors. All other vector functions start
124// with the `v3_` prefix.
125//
126// The binary layout is the same as in GLSL and everything else (just 3 floats).
127// So you can just upload the vectors into shaders as they are.
128//
129
130typedef struct { float x, y, z; } vec3_t;
131static inline vec3_t vec3(float x, float y, float z) { return (vec3_t){ x, y, z }; }
132static inline vec3_t v3_add (vec3_t a, vec3_t b) { return (vec3_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
133static inline vec3_t v3_adds (vec3_t a, float s) { return (vec3_t){ a.x + s, a.y + s, a.z + s }; }
134static inline vec3_t v3_sub (vec3_t a, vec3_t b) { return (vec3_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
135static inline vec3_t v3_subs (vec3_t a, float s) { return (vec3_t){ a.x - s, a.y - s, a.z - s }; }
136static inline vec3_t v3_mul (vec3_t a, vec3_t b) { return (vec3_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
137static inline vec3_t v3_muls (vec3_t a, float s) { return (vec3_t){ a.x * s, a.y * s, a.z * s }; }
138static inline vec3_t v3_div (vec3_t a, vec3_t b) { return (vec3_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
139static inline vec3_t v3_divs (vec3_t a, float s) { return (vec3_t){ a.x / s, a.y / s, a.z / s }; }
140static inline float v3_length(vec3_t v) { return sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); }
141static inline vec3_t v3_norm (vec3_t v);
142static inline float v3_dot (vec3_t a, vec3_t b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
143static inline vec3_t v3_proj (vec3_t v, vec3_t onto);
144static inline vec3_t v3_cross (vec3_t a, vec3_t b);
145static inline float v3_angle_between(vec3_t a, vec3_t b);
146
147
148/* Sébastien Le Roux - quaternions - 6/02/2017 */
149typedef struct { float w, x, y, z; } vec4_t;
150static inline vec4_t vec4(float w, float x, float y, float z) { return (vec4_t){ w, x, y, z }; }
151static inline vec4_t v4_add (vec4_t a, vec4_t b) { return (vec4_t){ a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z }; }
152static inline vec4_t v4_adds (vec4_t a, float s) { return (vec4_t){ a.w + s, a.x + s, a.y + s, a.z + s }; }
153static inline vec4_t v4_sub (vec4_t a, vec4_t b) { return (vec4_t){ a.w - b.w, a.x - b.x, a.y - b.y, a.z - b.z }; }
154static inline vec4_t v4_subs (vec4_t a, float s) { return (vec4_t){ a.w - s, a.x - s, a.y - s, a.z - s }; }
155static inline vec4_t v4_mul (vec4_t a, vec4_t b) { return (vec4_t){ a.w * b.w, a.x * b.x, a.y * b.y, a.z * b.z }; }
156static inline vec4_t v4_muls (vec4_t a, float s) { return (vec4_t){ a.w * s, a.x * s, a.y * s, a.z * s }; }
157static inline vec4_t v4_div (vec4_t a, vec4_t b) { return (vec4_t){ a.w / b.w, a.x / b.x, a.y / b.y, a.z / b.z }; }
158static inline vec4_t v4_divs (vec4_t a, float s) { return (vec4_t){ a.w / s, a.x / s, a.y / s, a.z / s }; }
159static inline float v4_length(vec4_t v) { return sqrtf(v.w*v.w + v.x*v.x + v.y*v.y + v.z*v.z); }
160static inline vec4_t v4_norm (vec4_t v);
161static inline vec4_t v4_mul (vec4_t a, vec4_t b);
162
163//
164// 4x4 matrices
165//
166// Use the `mat4()` function to create a matrix. You can write the matrix
167// members in the same way as you would write them on paper or on a whiteboard:
168//
169// mat4_t m = mat4(
170// 1, 0, 0, 7,
171// 0, 1, 0, 5,
172// 0, 0, 1, 3,
173// 0, 0, 0, 1
174// )
175//
176// This creates a matrix that translates points by vec3(7, 5, 3). All other
177// matrix functions start with the `m4_` prefix. Among them functions to create
178// identity, translation, rotation, scaling and projection matrices.
179//
180// The matrix is stored in column-major order, just as OpenGL expects. Members
181// can be accessed by indices or member names. When you write a matrix on paper
182// or on the whiteboard the indices and named members correspond to these
183// positions:
184//
185// | m[0][0] m[1][0] m[2][0] m[3][0] |
186// | m[0][1] m[1][1] m[2][1] m[3][1] |
187// | m[0][2] m[1][2] m[2][2] m[3][2] |
188// | m[0][3] m[1][3] m[2][3] m[3][3] |
189//
190// | m00 m10 m20 m30 |
191// | m01 m11 m21 m31 |
192// | m02 m12 m22 m32 |
193// | m03 m13 m23 m33 |
194//
195// The first index or number in a name denotes the column, the second the row.
196// So m[i][j] denotes the member in the ith column and the jth row. This is the
197// same as in GLSL (source: GLSL v1.3 specification, 5.6 Matrix Components).
198//
199
200typedef union {
201 // The first index is the column index, the second the row index. The memory
202 // layout of nested arrays in C matches the memory layout expected by OpenGL.
203 float m[4][4];
204 // OpenGL expects the first 4 floats to be the first column of the matrix.
205 // So we need to define the named members column by column for the names to
206 // match the memory locations of the array elements.
207 struct {
208 float m00, m01, m02, m03;
209 float m10, m11, m12, m13;
210 float m20, m21, m22, m23;
211 float m30, m31, m32, m33;
212 };
213} mat4_t;
214
215static inline mat4_t mat4(
216 float m00, float m10, float m20, float m30,
217 float m01, float m11, float m21, float m31,
218 float m02, float m12, float m22, float m32,
219 float m03, float m13, float m23, float m33
220);
221
222static inline mat4_t m4_identity ();
223static inline mat4_t m4_translation (vec3_t offset);
224static inline mat4_t m4_scaling (vec3_t scale);
225static inline mat4_t m4_rotation_x (float angle_in_rad);
226static inline mat4_t m4_rotation_y (float angle_in_rad);
227static inline mat4_t m4_rotation_z (float angle_in_rad);
228static inline mat4_t m4_rotation (float angle_in_rad, vec3_t axis);
229
230//
231// Sébastien Le Roux - Quaternions - 6/02/2017
232//
233static inline vec4_t axis_to_quat (vec3_t axis, float angle_in_rad);
234static inline mat4_t m4_quat_rotation (vec4_t q);
235
236static inline mat4_t m4_ortho (float left, float right, float bottom, float top, float back, float front);
237static inline mat4_t m4_perspective (float vertical_field_of_view_in_deg, float aspect_ratio, float near_view_distance, float far_view_distance);
238static inline mat4_t m4_frustum (float left, float right, float bottom, float top, float front, float back);
239static inline mat4_t m4_look_at (vec3_t from, vec3_t to, vec3_t up);
240
241static inline mat4_t m4_transpose (mat4_t matrix);
242static inline mat4_t m4_mul (mat4_t a, mat4_t b);
243static inline mat4_t m43_mul(mat4_t a, mat4_t b);
244static inline mat4_t m4_invert_affine(mat4_t matrix);
245static inline mat4_t m4_translate (mat4_t matrix, vec3_t translation);
246static inline vec3_t m4_mul_pos (mat4_t matrix, vec3_t position);
247static inline vec3_t m4_mul_coord (mat4_t matrix, vec3_t position);
248static inline vec3_t m4_mul_abc (mat4_t matrix, vec3_t position);
249static inline vec3_t m4_mul_dir (mat4_t matrix, vec3_t direction);
250
251static inline void m4_print (mat4_t matrix);
252static inline void m4_printp (mat4_t matrix, int width, int precision);
253static inline void m4_fprint (FILE* stream, mat4_t matrix);
254static inline void m4_fprintp (FILE* stream, mat4_t matrix, int width, int precision);
255
256
257
258//
259// 3D vector functions header implementation
260//
261
262static inline vec3_t v3_norm(vec3_t v) {
263 float len = v3_length(v);
264 if (len > 0.0)
265 return (vec3_t){ v.x / len, v.y / len, v.z / len };
266 else
267 return (vec3_t){ 0, 0, 0};
268}
269
270static inline vec3_t v3_proj(vec3_t v, vec3_t onto) {
271 return v3_muls(onto, v3_dot(v, onto) / v3_dot(onto, onto));
272}
273
274static inline vec3_t v3_cross(vec3_t a, vec3_t b) {
275 return (vec3_t){
276 a.y * b.z - a.z * b.y,
277 a.z * b.x - a.x * b.z,
278 a.x * b.y - a.y * b.x
279 };
280}
281
282static inline float v3_angle_between(vec3_t a, vec3_t b) {
283 return acosf( v3_dot(a, b) / (v3_length(a) * v3_length(b)) );
284}
285
286//
287// Sébastien Le Roux - Quaternions - 6/02/2017
288//
289
290static inline vec4_t v4_norm(vec4_t v) {
291 float len = v4_length(v);
292 if (len > 0.0)
293 return (vec4_t){ v.w / len, v.x / len, v.y / len , v.z / len};
294 else
295 return (vec4_t){ 0, 0, 0, 0};
296}
297
298static inline vec4_t q4_mul(vec4_t a, vec4_t b) {
299 return (vec4_t){
300 a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x,
301 a.z * b.x + a.x * b.z + a.y * b.w - a.w * b.y,
302 a.z * b.y + a.y * b.z + a.w * b.x - a.x * b.w,
303 a.z * b.z - (a.w * b.w + a.x * b.x + a.y * b.y)};
304}
305
306
307//
308// Matrix functions header implementation
309//
310
311static inline mat4_t mat4(
312 float m00, float m10, float m20, float m30,
313 float m01, float m11, float m21, float m31,
314 float m02, float m12, float m22, float m32,
315 float m03, float m13, float m23, float m33
316) {
317 return (mat4_t){
318 .m[0][0] = m00, .m[1][0] = m10, .m[2][0] = m20, .m[3][0] = m30,
319 .m[0][1] = m01, .m[1][1] = m11, .m[2][1] = m21, .m[3][1] = m31,
320 .m[0][2] = m02, .m[1][2] = m12, .m[2][2] = m22, .m[3][2] = m32,
321 .m[0][3] = m03, .m[1][3] = m13, .m[2][3] = m23, .m[3][3] = m33
322 };
323}
324
325static inline mat4_t m4_identity() {
326 return mat4(
327 1, 0, 0, 0,
328 0, 1, 0, 0,
329 0, 0, 1, 0,
330 0, 0, 0, 1
331 );
332}
333
334static inline mat4_t m4_translation(vec3_t offset) {
335 return mat4(
336 1, 0, 0, offset.x,
337 0, 1, 0, offset.y,
338 0, 0, 1, offset.z,
339 0, 0, 0, 1
340 );
341}
342
343static inline mat4_t m4_scaling(vec3_t scale) {
344 float x = scale.x, y = scale.y, z = scale.z;
345 return mat4(
346 x, 0, 0, 0,
347 0, y, 0, 0,
348 0, 0, z, 0,
349 0, 0, 0, 1
350 );
351}
352
353static inline mat4_t m4_rotation_x(float angle_in_rad) {
354 float s = sinf(angle_in_rad), c = cosf(angle_in_rad);
355 return mat4(
356 1, 0, 0, 0,
357 0, c, -s, 0,
358 0, s, c, 0,
359 0, 0, 0, 1
360 );
361}
362
363static inline mat4_t m4_rotation_y(float angle_in_rad) {
364 float s = sinf(angle_in_rad), c = cosf(angle_in_rad);
365 return mat4(
366 c, 0, s, 0,
367 0, 1, 0, 0,
368 -s, 0, c, 0,
369 0, 0, 0, 1
370 );
371}
372
373static inline mat4_t m4_rotation_z(float angle_in_rad) {
374 float s = sinf(angle_in_rad), c = cosf(angle_in_rad);
375 return mat4(
376 c, -s, 0, 0,
377 s, c, 0, 0,
378 0, 0, 1, 0,
379 0, 0, 0, 1
380 );
381}
382
383static inline mat4_t m4_transpose(mat4_t matrix) {
384 return mat4(
385 matrix.m00, matrix.m01, matrix.m02, matrix.m03,
386 matrix.m10, matrix.m11, matrix.m12, matrix.m13,
387 matrix.m20, matrix.m21, matrix.m22, matrix.m23,
388 matrix.m30, matrix.m31, matrix.m32, matrix.m33
389 );
390}
391
402static inline mat4_t m4_mul(mat4_t a, mat4_t b) {
403 mat4_t result;
404 int i, j, k;
405 for(i = 0; i < 4; i++) {
406 for(j = 0; j < 4; j++) {
407 float sum = 0;
408 for(k = 0; k < 4; k++) {
409 sum += a.m[k][j] * b.m[i][k];
410 }
411 result.m[i][j] = sum;
412 }
413 }
414
415 return result;
416}
417
418static inline mat4_t m43_mul(mat4_t a, mat4_t b) {
419 mat4_t result;
420 int i, j, k;
421 for(i = 0; i < 4; i++) {
422 for(j = 0; j < 3; j++) {
423 float sum = 0;
424 for(k = 0; k < 4; k++) {
425 sum += a.m[k][j] * b.m[i][k];
426 }
427 result.m[i][j] = sum;
428 //if (i < 3 && result.m[i][j] != 0.0) result.m[i][j] /= fabs(sum);
429 }
430 }
431 result.m03 = result.m13 = result.m23 = result.m33 = 0.0;
432 return result;
433}
434
435#endif // MATH_3D_HEADER
436
437
438#ifndef MATH_3D_IMPLEMENTATION
439
440#define MATH_3D_IMPLEMENTATION
441
450static inline mat4_t m4_rotation (float angle_in_rad, vec3_t axis) {
451 vec3_t normalized_axis = v3_norm(axis);
452 float x = normalized_axis.x, y = normalized_axis.y, z = normalized_axis.z;
453 float c = cosf(angle_in_rad), s = sinf(angle_in_rad);
454
455 return mat4(
456 c + x*x*(1-c), x*y*(1-c) - z*s, x*z*(1-c) + y*s, 0,
457 y*x*(1-c) + z*s, c + y*y*(1-c), y*z*(1-c) - x*s, 0,
458 z*x*(1-c) - y*s, z*y*(1-c) + x*s, c + z*z*(1-c), 0,
459 0, 0, 0, 1
460 );
461}
462
463/*
464 Sébastien Le Roux 08/07/2022
465 Rotation 3D, on x, y and z, providing angles in degrees [ 0 - 90 ]
466*/
467static inline mat4_t m4_rotation_anti_xyz (float alpha, float beta, float gamma) {
468 mat4_t rot = m4_identity ();
469 vec4_t qr;
470 double pi = 3.141592653589793238462643383279502884197;
471 vec3_t ax[3];
472 ax[0] = vec3(1.0,0.0,0.0);
473 ax[1] = vec3(0.0,1.0,0.0);
474 ax[2] = vec3(0.0,0.0,1.0);
475 qr = axis_to_quat (ax[2], - gamma*pi/90.0);
476 rot = m4_mul (rot, m4_quat_rotation (qr));
477 qr = axis_to_quat (ax[1], - beta*pi/90.0);
478 rot = m4_mul (rot, m4_quat_rotation (qr));
479 qr = axis_to_quat (ax[0], - alpha*pi/90.0);
480 rot = m4_mul (rot, m4_quat_rotation (qr));
481 return rot;
482}
483
484static inline mat4_t m4_rotation_xyz (float alpha, float beta, float gamma) {
485 mat4_t rot = m4_identity ();
486 vec4_t qr;
487 double pi = 3.141592653589793238462643383279502884197;
488 vec3_t ax[3];
489 ax[0] = vec3(1.0,0.0,0.0);
490 ax[1] = vec3(0.0,1.0,0.0);
491 ax[2] = vec3(0.0,0.0,1.0);
492 qr = axis_to_quat (ax[0], alpha*pi/90.0);
493 rot = m4_mul (rot, m4_quat_rotation (qr));
494 qr = axis_to_quat (ax[1], beta*pi/90.0);
495 rot = m4_mul (rot, m4_quat_rotation (qr));
496 qr = axis_to_quat (ax[2], gamma*pi/90.0);
497 rot = m4_mul (rot, m4_quat_rotation (qr));
498 return rot;
499}
500/*
501 Sébastien Le Roux 06/02/2017
502 Quaternion rotation
503*/
504static inline vec4_t axis_to_quat (vec3_t axis, float angle_in_rad)
505{
506 vec4_t qr;
507 float half_angle = angle_in_rad/2.0;
508 float n = sinf(half_angle)/v3_length(axis);
509 qr.w = axis.x * n;
510 qr.x = axis.y * n;
511 qr.y = axis.z * n;
512 qr.z = cosf(half_angle);
513 return v4_norm (qr);
514}
515
516static inline vec4_t m4_mul_v4 (mat4_t mat, vec4_t vec) {
517 int i;
518 float out[4];
519 float in[4] = {vec.w, vec.x, vec.y, vec.z};
520 for (i=0; i<4; i++)
521 {
522 out[i] = in[0] * mat.m[0][i] + in[1] * mat.m[1][i] + in[2] * mat.m[2][i] + in[3] * mat.m[3][i];
523 }
524 return vec4(out[0], out[1], out[2], out[3]);
525}
526
527static inline mat4_t m4_quat_rotation (vec4_t q) {
528// I consider that the quaternion is already normalized
529// vec4_t n_quat = v4_norm(q);
530 return mat4(
531 1.0 - 2.0 * (q.x * q.x + q.y * q.y), 2.0 * (q.w * q.x + q.y * q.z), 2.0 * (q.y * q.w - q.x * q.z), 0,
532 2.0 * (q.w * q.x - q.y * q.z), 1.0 - 2.0 * (q.y * q.y + q.w * q.w), 2.0 * (q.x * q.y + q.w * q.z), 0,
533 2.0 * (q.y * q.w + q.x * q.z), 2.0 * (q.x * q.y - q.w * q.z), 1.0 - 2.0 * (q.x * q.x + q.w * q.w), 0,
534 0, 0, 0, 1
535 );
536}
537
538static inline vec3_t v3_project (vec3_t worldpos, vec4_t viewport, mat4_t projection) {
539
540 mat4_t mod = m4_mul(projection, m4_translation(worldpos));
541 vec4_t out = m4_mul_v4 (mod, vec4(0.0, 0.0, 0.0, 1.0));
542 if (out.z != 0.0)
543 {
544 out.z = 1.0 / out.z;
545 out.w = out.z * out.w + 1.0;
546 out.x = out.z * out.x + 1.0;
547 out.y = out.z * out.y + 1.0;
548 return vec3(out.w*viewport.y + viewport.w, out.x*viewport.z + viewport.x, out.y);
549 }
550 else
551 {
552 return vec3 (0.0, 0.0, -1.0);
553 }
554}
555
556static inline vec3_t v3_un_project (vec3_t winpos, vec4_t viewport, mat4_t projection) {
557
558 vec3_t in = vec3 (2.0*(winpos.x-viewport.w)/viewport.y - 1.0,
559 2.0*((viewport.z-winpos.y)-viewport.x)/viewport.z - 1.0,
560 2.0*winpos.z-1.0);
561 return m4_mul_pos (m4_invert_affine(projection), in);
562}
563
564
592static inline mat4_t m4_ortho(float left, float right, float bottom, float top, float back, float front) {
593 float l = left, r = right, b = bottom, t = top, n = front, f = back;
594 float tx = -(r + l) / (r - l);
595 float ty = -(t + b) / (t - b);
596 float tz = -(f + n) / (f - n);
597 return mat4(
598 2 / (r - l), 0, 0, tx,
599 0, 2 / (t - b), 0, ty,
600 0, 0, 2 / (f - n), tz,
601 0, 0, 0, 1
602 );
603}
604
625static inline mat4_t m4_perspective(float vertical_field_of_view_in_deg, float aspect_ratio, float near_view_distance, float far_view_distance) {
626 float fovy_in_rad = vertical_field_of_view_in_deg / 180 * M_PI;
627 float f = 1.0f / tanf(fovy_in_rad / 2.0f);
628 float ar = aspect_ratio;
629 float nd = near_view_distance, fd = far_view_distance;
630
631 return mat4(
632 f / ar, 0, 0, 0,
633 0, f, 0, 0,
634 0, 0, (fd+nd)/(nd-fd), (2*fd*nd)/(nd-fd),
635 0, 0, -1, 0
636 );
637}
638
644static inline mat4_t m4_frustum (float left, float right, float bottom, float top, float front, float back) {
645 float n = 2.0f * front;
646 float l = right - left;
647 float p = top - bottom;
648 float a = (right + left) / l;
649 float b = (top + bottom) / p;
650 float c = -(back + front) / (back - front);
651 float d = - back * n / (back - front);
652
653 return mat4(
654 n / l, 0, a, 0,
655 0, n / p, b, 0,
656 0, 0, c, d,
657 0, 0, -1, 0
658 );
659}
660
661
698static inline mat4_t m4_look_at(vec3_t from, vec3_t to, vec3_t up) {
699 vec3_t z = v3_muls(v3_norm(v3_sub(to, from)), -1);
700 vec3_t x = v3_norm(v3_cross(up, z));
701 vec3_t y = v3_cross(z, x);
702
703 return mat4(
704 x.x, x.y, x.z, -v3_dot(from, x),
705 y.x, y.y, y.z, -v3_dot(from, y),
706 z.x, z.y, z.z, -v3_dot(from, z),
707 0, 0, 0, 1
708 );
709}
710
711
742static inline mat4_t m4_invert_affine(mat4_t matrix) {
743 // Create shorthands to access matrix members
744 float m00 = matrix.m00, m10 = matrix.m10, m20 = matrix.m20, m30 = matrix.m30;
745 float m01 = matrix.m01, m11 = matrix.m11, m21 = matrix.m21, m31 = matrix.m31;
746 float m02 = matrix.m02, m12 = matrix.m12, m22 = matrix.m22, m32 = matrix.m32;
747
748 // Invert 3x3 part of the 4x4 matrix that contains the rotation, etc.
749 // That part is called R from here on.
750
751 // Calculate cofactor matrix of R
752 float c00 = m11*m22 - m12*m21, c10 = -(m01*m22 - m02*m21), c20 = m01*m12 - m02*m11;
753 float c01 = -(m10*m22 - m12*m20), c11 = m00*m22 - m02*m20, c21 = -(m00*m12 - m02*m10);
754 float c02 = m10*m21 - m11*m20, c12 = -(m00*m21 - m01*m20), c22 = m00*m11 - m01*m10;
755
756 // Caclculate the determinant by using the already calculated determinants
757 // in the cofactor matrix.
758 // Second sign is already minus from the cofactor matrix.
759 float det = m00*c00 + m10*c10 + m20 * c20;
760 if (fabsf(det) == 0.0000)
761 return m4_identity();
762
763 // Calcuate inverse of R by dividing the transposed cofactor matrix by the
764 // determinant.
765 float i00 = c00 / det, i10 = c01 / det, i20 = c02 / det;
766 float i01 = c10 / det, i11 = c11 / det, i21 = c12 / det;
767 float i02 = c20 / det, i12 = c21 / det, i22 = c22 / det;
768
769 // Combine the inverted R with the inverted translation
770 return mat4(
771 i00, i10, i20, -(i00*m30 + i10*m31 + i20*m32),
772 i01, i11, i21, -(i01*m30 + i11*m31 + i21*m32),
773 i02, i12, i22, -(i02*m30 + i12*m31 + i22*m32),
774 0, 0, 0, 1
775 );
776}
777
778
779static inline mat4_t m4_translate (mat4_t matrix, vec3_t translation) {
780 return mat4(
781 matrix.m00, matrix.m10, matrix.m20, matrix.m30 + translation.x,
782 matrix.m01, matrix.m11, matrix.m21, matrix.m31 + translation.y,
783 matrix.m02, matrix.m12, matrix.m22, matrix.m32 + translation.z,
784 matrix.m03, matrix.m13, matrix.m23, matrix.m33
785 );
786}
787
795static inline vec3_t m4_mul_pos(mat4_t matrix, vec3_t position) {
796 vec3_t result = vec3(
797 matrix.m00 * position.x + matrix.m10 * position.y + matrix.m20 * position.z + matrix.m30,
798 matrix.m01 * position.x + matrix.m11 * position.y + matrix.m21 * position.z + matrix.m31,
799 matrix.m02 * position.x + matrix.m12 * position.y + matrix.m22 * position.z + matrix.m32
800 );
801
802 float w = matrix.m03 * position.x + matrix.m13 * position.y + matrix.m23 * position.z + matrix.m33;
803 if (w != 0.0) return vec3(result.x / w, result.y / w, result.z / w);
804 return result;
805}
806
807static inline vec3_t m4_mul_coord(mat4_t matrix, vec3_t position) {
808 vec3_t result = vec3(
809 matrix.m00 * position.x + matrix.m10 * position.y + matrix.m20 * position.z + matrix.m30,
810 matrix.m01 * position.x + matrix.m11 * position.y + matrix.m21 * position.z + matrix.m31,
811 matrix.m02 * position.x + matrix.m12 * position.y + matrix.m22 * position.z + matrix.m32
812 );
813 return result;
814}
815static inline vec3_t m4_mul_abc(mat4_t matrix, vec3_t direction) {
816 vec3_t result = vec3(
817 matrix.m00 * direction.x + matrix.m10 * direction.y + matrix.m20 * direction.z,
818 matrix.m01 * direction.x + matrix.m11 * direction.y + matrix.m21 * direction.z,
819 matrix.m02 * direction.x + matrix.m12 * direction.y + matrix.m22 * direction.z
820 );
821 return result;
822}
823
835static inline vec3_t m4_mul_dir(mat4_t matrix, vec3_t direction) {
836 vec3_t result = vec3(
837 matrix.m00 * direction.x + matrix.m10 * direction.y + matrix.m20 * direction.z,
838 matrix.m01 * direction.x + matrix.m11 * direction.y + matrix.m21 * direction.z,
839 matrix.m02 * direction.x + matrix.m12 * direction.y + matrix.m22 * direction.z
840 );
841
842 float w = matrix.m03 * direction.x + matrix.m13 * direction.y + matrix.m23 * direction.z;
843 if (w != 0.0) return vec3(result.x / w, result.y / w, result.z / w);
844 return result;
845}
846
847static inline void m4_print(mat4_t matrix) {
848 m4_fprintp(stdout, matrix, 6, 4);
849}
850
851static inline void m4_printp(mat4_t matrix, int width, int precision) {
852 m4_fprintp(stdout, matrix, width, precision);
853}
854
855static inline void m4_fprint(FILE* stream, mat4_t matrix) {
856 m4_fprintp(stream, matrix, 6, 2);
857}
858
859static inline void m4_fprintp(FILE* stream, mat4_t matrix, int width, int precision) {
860 mat4_t m = matrix;
861 int w = width, p = precision;
862 int r;
863 for(r = 0; r < 4; r++) {
864 fprintf(stream, "| %*.*f %*.*f %*.*f %*.*f |\n",
865 w, p, m.m[0][r], w, p, m.m[1][r], w, p, m.m[2][r], w, p, m.m[3][r]
866 );
867 }
868}
869
870#endif // MATH_3D_IMPLEMENTATION
gchar * axis[3]
Definition w_axis.c:65
double scale(double axe)
find appropriate major tick spacing based on axis length
Definition curve.c:204
double ax
Definition curve.c:70
dint up
double pi
Definition global.c:195
position
Definition m_proj.c:47
#define M_PI
Definition math_3d.h:116
double precision w
double precision, dimension(:), allocatable s
double z
Definition ogl_draw.c:57
double y
Definition ogl_draw.c:57
double x
Definition ogl_draw.c:57
float y
Definition math_3d.h:130
float x
Definition math_3d.h:130
float z
Definition math_3d.h:130
float w
Definition math_3d.h:149
float y
Definition math_3d.h:149
float x
Definition math_3d.h:149
float z
Definition math_3d.h:149
int b
Definition tab-1.c:95
int c
Definition tab-1.c:95
int d
Definition tab-1.c:95
int a
Definition tab-1.c:95
float m11
Definition math_3d.h:209
float m30
Definition math_3d.h:211
float m22
Definition math_3d.h:210
float m00
Definition math_3d.h:208
float m23
Definition math_3d.h:210
float m01
Definition math_3d.h:208
float m[4][4]
Definition math_3d.h:203
float m21
Definition math_3d.h:210
float m33
Definition math_3d.h:211
float m32
Definition math_3d.h:211
float m10
Definition math_3d.h:209
float m13
Definition math_3d.h:209
float m02
Definition math_3d.h:208
float m03
Definition math_3d.h:208
float m12
Definition math_3d.h:209
float m31
Definition math_3d.h:211
float m20
Definition math_3d.h:210