| 1 | module m4 |
| 2 | |
| 3 | /********************************************************************** |
| 4 | * Simple vector/matrix graphic utility |
| 5 | * Copyright (c) 2021 Dario Deledda. All rights reserved. |
| 6 | * Use of this source code is governed by an MIT license |
| 7 | * that can be found in the LICENSE file. |
| 8 | **********************************************************************/ |
| 9 | import math |
| 10 | |
| 11 | // Translate degrees to radians |
| 12 | @[inline] |
| 13 | pub fn rad(deg f32) f32 { |
| 14 | return (math.pi / 180.0) * deg |
| 15 | } |
| 16 | |
| 17 | // Translate radians to degrees |
| 18 | @[inline] |
| 19 | pub fn deg(grad f32) f32 { |
| 20 | return (180.0 / math.pi) * grad |
| 21 | } |
| 22 | |
| 23 | // calculate the Orthographic projection matrix |
| 24 | pub fn ortho(left f32, right f32, bottom f32, top f32, z_near f32, z_far f32) Mat4 { |
| 25 | rml := right - left |
| 26 | rpl := right + left |
| 27 | tmb := top - bottom |
| 28 | tpb := top + bottom |
| 29 | fmn := z_far - z_near |
| 30 | fpn := z_far + z_near |
| 31 | // vfmt off |
| 32 | if fmn != 0 { |
| 33 | return Mat4{ |
| 34 | e: [ |
| 35 | 2 / rml, 0, 0, -(rpl / rml), |
| 36 | 0 , 2 / tmb, 0, -(tpb / tmb), |
| 37 | 0 , 0, 2 / fmn, -(fpn / fmn), |
| 38 | 0 , 0, 0, 1, |
| 39 | ]! |
| 40 | } |
| 41 | } |
| 42 | return Mat4{ |
| 43 | e: [ |
| 44 | 2 / rml, 0, 0, -(rpl / rml), |
| 45 | 0, 2 / tmb, 0, -(tpb / tmb), |
| 46 | 0, 0, 0, 0, |
| 47 | 0, 0, 0, 1, |
| 48 | ]! |
| 49 | } |
| 50 | // vfmt on |
| 51 | } |
| 52 | |
| 53 | // Calculate the perspective matrix using (fov:fov, ar:aspect_ratio ,n:near_pane, f:far_plane) as parameters |
| 54 | pub fn perspective(fov f32, ar f32, n f32, f f32) Mat4 { |
| 55 | ctan := f32(1.0 / math.tan(fov * (f32(math.pi) / 360.0))) // for the FOV we use 360 instead 180 |
| 56 | // vfmt off |
| 57 | return Mat4{ |
| 58 | e: [ |
| 59 | ctan / ar, 0, 0, 0, |
| 60 | 0, ctan, 0, 0, |
| 61 | 0, 0, (n + f) / (n - f), -1.0, |
| 62 | 0, 0, (2.0 * n * f) / (n - f), 0, |
| 63 | ]! |
| 64 | } |
| 65 | // vfmt on |
| 66 | } |
| 67 | |
| 68 | // Calculate the look-at matrix |
| 69 | pub fn look_at(eye Vec4, center Vec4, up Vec4) Mat4 { |
| 70 | f := (center - eye).normalize3() |
| 71 | s := (f % up).normalize3() |
| 72 | u := (s % f) |
| 73 | // vfmt off |
| 74 | return Mat4{e: [ |
| 75 | s.e[0], u.e[0], -f.e[0], 0, |
| 76 | s.e[1], u.e[1], -f.e[1], 0, |
| 77 | s.e[2], u.e[2], -f.e[2], 0, |
| 78 | -(s * eye), -(u * eye), f * eye, 1, |
| 79 | ]!} |
| 80 | // vfmt on |
| 81 | } |
| 82 | |
| 83 | // Get the complete transformation matrix for GLSL demos |
| 84 | pub fn calc_tr_matrices(w f32, h f32, rx f32, ry f32, in_scale f32) Mat4 { |
| 85 | proj := perspective(60, w / h, 0.01, 10.0) |
| 86 | // vfmt off |
| 87 | view := look_at( |
| 88 | Vec4{ e: [f32(0.0), 1.5, 6, 0]! }, |
| 89 | Vec4{ e: [f32(0), 0, 0, 0]!}, |
| 90 | Vec4{ e: [f32(0), 1.0, 0, 0]!} |
| 91 | ) |
| 92 | view_proj := view * proj |
| 93 | |
| 94 | rxm := rotate(rad(rx), Vec4{ e: [f32(1), 0, 0, 0]! }) |
| 95 | rym := rotate(rad(ry), Vec4{ e: [f32(0), 1, 0, 0]! }) |
| 96 | scale_m := scale(Vec4{ e: [in_scale, in_scale, in_scale, 1]! }) |
| 97 | // vfmt on |
| 98 | |
| 99 | model := rym * rxm |
| 100 | res := (scale_m * model) * view_proj |
| 101 | return res |
| 102 | } |
| 103 | |