github.com/primecitizens/pcz/std@v0.2.1/math/matrix/mat4.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 4 // Code adapted from https://github.com/greggman/wgpu-matrix 5 // 6 // Copyright (c) 2022 Gregg Tavares 7 // SPDX-License-Identifier: MIT 8 9 package matrix 10 11 import ( 12 "unsafe" 13 14 "github.com/primecitizens/pcz/std/core/num" 15 "github.com/primecitizens/pcz/std/math" 16 ) 17 18 // Mat4 is a 4x4 matrix in row major order. 19 // 20 // m[4*r + c] is the element in the r'th row and c'th column. 21 type Mat4[T num.Real] [16]T 22 23 func (m *Mat4[T]) SetIdentity() *Mat4[T] { 24 *m = Mat4[T]{ 25 1, 0, 0, 0, 26 0, 1, 0, 0, 27 0, 0, 1, 0, 28 0, 0, 0, 1, 29 } 30 return m 31 } 32 33 func (m *Mat4[T]) Translate(v Vec3[T]) *Mat4[T] { 34 *(*[4]T)(unsafe.Pointer(&m[12])) = [4]T{ 35 m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12], 36 m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13], 37 m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14], 38 m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15], 39 } 40 return m 41 } 42 43 func (m *Mat4[T]) Mul(x Mat4[T]) *Mat4[T] { 44 *m = Mat4[T]{ 45 m[0]*x[0] + m[4]*x[1] + m[8]*x[2] + m[12]*x[3], 46 m[1]*x[0] + m[5]*x[1] + m[9]*x[2] + m[13]*x[3], 47 m[2]*x[0] + m[6]*x[1] + m[10]*x[2] + m[14]*x[3], 48 m[3]*x[0] + m[7]*x[1] + m[11]*x[2] + m[15]*x[3], 49 50 m[0]*x[4] + m[4]*x[5] + m[8]*x[6] + m[12]*x[7], 51 m[1]*x[4] + m[5]*x[5] + m[9]*x[6] + m[13]*x[7], 52 m[2]*x[4] + m[6]*x[5] + m[10]*x[6] + m[14]*x[7], 53 m[3]*x[4] + m[7]*x[5] + m[11]*x[6] + m[15]*x[7], 54 55 m[0]*x[8] + m[4]*x[9] + m[8]*x[10] + m[12]*x[11], 56 m[1]*x[8] + m[5]*x[9] + m[9]*x[10] + m[13]*x[11], 57 m[2]*x[8] + m[6]*x[9] + m[10]*x[10] + m[14]*x[11], 58 m[3]*x[8] + m[7]*x[9] + m[11]*x[10] + m[15]*x[11], 59 60 m[0]*x[12] + m[4]*x[13] + m[8]*x[14] + m[12]*x[15], 61 m[1]*x[12] + m[5]*x[13] + m[9]*x[14] + m[13]*x[15], 62 m[2]*x[12] + m[6]*x[13] + m[10]*x[14] + m[14]*x[15], 63 m[3]*x[12] + m[7]*x[13] + m[11]*x[14] + m[15]*x[15], 64 } 65 return m 66 } 67 68 func (m Mat4[T]) MulV(x Mat4[T]) Mat4[T] { 69 return Mat4[T]{ 70 m[0]*x[0] + m[4]*x[1] + m[8]*x[2] + m[12]*x[3], 71 m[1]*x[0] + m[5]*x[1] + m[9]*x[2] + m[13]*x[3], 72 m[2]*x[0] + m[6]*x[1] + m[10]*x[2] + m[14]*x[3], 73 m[3]*x[0] + m[7]*x[1] + m[11]*x[2] + m[15]*x[3], 74 75 m[0]*x[4] + m[4]*x[5] + m[8]*x[6] + m[12]*x[7], 76 m[1]*x[4] + m[5]*x[5] + m[9]*x[6] + m[13]*x[7], 77 m[2]*x[4] + m[6]*x[5] + m[10]*x[6] + m[14]*x[7], 78 m[3]*x[4] + m[7]*x[5] + m[11]*x[6] + m[15]*x[7], 79 80 m[0]*x[8] + m[4]*x[9] + m[8]*x[10] + m[12]*x[11], 81 m[1]*x[8] + m[5]*x[9] + m[9]*x[10] + m[13]*x[11], 82 m[2]*x[8] + m[6]*x[9] + m[10]*x[10] + m[14]*x[11], 83 m[3]*x[8] + m[7]*x[9] + m[11]*x[10] + m[15]*x[11], 84 85 m[0]*x[12] + m[4]*x[13] + m[8]*x[14] + m[12]*x[15], 86 m[1]*x[12] + m[5]*x[13] + m[9]*x[14] + m[13]*x[15], 87 m[2]*x[12] + m[6]*x[13] + m[10]*x[14] + m[14]*x[15], 88 m[3]*x[12] + m[7]*x[13] + m[11]*x[14] + m[15]*x[15], 89 } 90 } 91 92 func (m *Mat4[T]) MulScalar(x T) *Mat4[T] { 93 *m = Mat4[T]{ 94 m[0] * x, m[1] * x, m[2] * x, m[3] * x, 95 m[4] * x, m[5] * x, m[6] * x, m[7] * x, 96 m[8] * x, m[9] * x, m[10] * x, m[11] * x, 97 m[12] * x, m[13] * x, m[14] * x, m[15] * x, 98 } 99 return m 100 } 101 102 func (m *Mat4[T]) Rotate(rad float64, axis Vec3[T]) *Mat4[T] { 103 x := float64(axis[0]) 104 y := float64(axis[1]) 105 z := float64(axis[2]) 106 n := math.Sqrt(x*x + y*y + z*z) 107 x /= n 108 y /= n 109 z /= n 110 111 xx := x * x 112 yy := y * y 113 zz := z * z 114 c := math.Cos(rad) 115 s := math.Sin(rad) 116 oneMinusCosine := 1 - c 117 118 r00 := xx + (1-xx)*c 119 r01 := x*y*oneMinusCosine + z*s 120 r02 := x*z*oneMinusCosine - y*s 121 r10 := x*y*oneMinusCosine - z*s 122 r11 := yy + (1-yy)*c 123 r12 := y*z*oneMinusCosine + x*s 124 r20 := x*z*oneMinusCosine + y*s 125 r21 := y*z*oneMinusCosine - x*s 126 r22 := zz + (1-zz)*c 127 128 *(*[12]T)(unsafe.Pointer(m)) = [12]T{ 129 T(r00*float64(m[0]) + r01*float64(m[4]) + r02*float64(m[8])), 130 T(r00*float64(m[1]) + r01*float64(m[5]) + r02*float64(m[9])), 131 T(r00*float64(m[2]) + r01*float64(m[6]) + r02*float64(m[10])), 132 T(r00*float64(m[3]) + r01*float64(m[7]) + r02*float64(m[11])), 133 134 T(r10*float64(m[0]) + r11*float64(m[4]) + r12*float64(m[8])), 135 T(r10*float64(m[1]) + r11*float64(m[5]) + r12*float64(m[9])), 136 T(r10*float64(m[2]) + r11*float64(m[6]) + r12*float64(m[10])), 137 T(r10*float64(m[3]) + r11*float64(m[7]) + r12*float64(m[11])), 138 139 T(r20*float64(m[0]) + r21*float64(m[4]) + r22*float64(m[8])), 140 T(r20*float64(m[1]) + r21*float64(m[5]) + r22*float64(m[9])), 141 T(r20*float64(m[2]) + r21*float64(m[6]) + r22*float64(m[10])), 142 T(r20*float64(m[3]) + r21*float64(m[7]) + r22*float64(m[11])), 143 } 144 145 return m 146 } 147 148 func (m *Mat4[T]) SetRotationX(rad float64) *Mat4[T] { 149 c := math.Cos(rad) 150 s := math.Sin(rad) 151 152 *m = Mat4[T]{ 153 1, 0, 0, 0, 154 0, T(c), T(s), 0, 155 0, T(-s), T(c), 0, 156 0, 0, 0, 1, 157 } 158 159 return m 160 } 161 162 func (m *Mat4[T]) RotateX(rad float64) *Mat4[T] { 163 c := math.Cos(rad) 164 s := math.Sin(rad) 165 166 *(*[8]T)(unsafe.Pointer(&m[4])) = [8]T{ 167 T(c*float64(m[4]) + s*float64(m[8])), 168 T(c*float64(m[5]) + s*float64(m[9])), 169 T(c*float64(m[6]) + s*float64(m[10])), 170 T(c*float64(m[7]) + s*float64(m[11])), 171 172 T(c*float64(m[8]) - s*float64(m[4])), 173 T(c*float64(m[9]) - s*float64(m[5])), 174 T(c*float64(m[10]) - s*float64(m[6])), 175 T(c*float64(m[11]) - s*float64(m[7])), 176 } 177 178 return m 179 } 180 181 func (m *Mat4[T]) SetRotationY(rad float64) *Mat4[T] { 182 c := math.Cos(rad) 183 s := math.Sin(rad) 184 185 *m = Mat4[T]{ 186 T(c), 0, T(-s), 0, 187 0, 1, 0, 0, 188 T(s), 0, T(c), 0, 189 0, 0, 0, 1, 190 } 191 192 return m 193 } 194 195 func (m *Mat4[T]) RotateY(rad float64) *Mat4[T] { 196 c := math.Cos(rad) 197 s := math.Sin(rad) 198 199 m0 := *(*[4]T)(unsafe.Pointer(&m[0])) 200 201 *(*[4]T)(unsafe.Pointer(&m[0])) = [4]T{ 202 T(c*float64(m0[0]) - s*float64(m[8])), 203 T(c*float64(m0[1]) - s*float64(m[9])), 204 T(c*float64(m0[2]) - s*float64(m[10])), 205 T(c*float64(m0[3]) - s*float64(m[11])), 206 } 207 208 *(*[4]T)(unsafe.Pointer(&m[8])) = [4]T{ 209 T(c*float64(m[8]) + s*float64(m0[0])), 210 T(c*float64(m[9]) + s*float64(m0[1])), 211 T(c*float64(m[10]) + s*float64(m0[2])), 212 T(c*float64(m[11]) + s*float64(m0[3])), 213 } 214 215 return m 216 } 217 218 func (m *Mat4[T]) SetRotationZ(rad float64) *Mat4[T] { 219 c := math.Cos(rad) 220 s := math.Sin(rad) 221 222 *m = Mat4[T]{ 223 T(c), T(-s), 0, 0, 224 T(s), T(c), 0, 0, 225 0, 0, 1, 0, 226 0, 0, 0, 1, 227 } 228 229 return m 230 } 231 232 func (m *Mat4[T]) RotateZ(rad float64) *Mat4[T] { 233 c := math.Cos(rad) 234 s := math.Sin(rad) 235 236 *(*[8]T)(unsafe.Pointer(m)) = [8]T{ 237 T(c*float64(m[0]) + s*float64(m[4])), 238 T(c*float64(m[1]) + s*float64(m[5])), 239 T(c*float64(m[2]) + s*float64(m[6])), 240 T(c*float64(m[3]) + s*float64(m[7])), 241 242 T(c*float64(m[4]) - s*float64(m[0])), 243 T(c*float64(m[5]) - s*float64(m[1])), 244 T(c*float64(m[6]) - s*float64(m[2])), 245 T(c*float64(m[7]) - s*float64(m[3])), 246 } 247 248 return m 249 } 250 251 func SetPerspective4[T num.Int | num.Float]( 252 m *Mat4[T], fieldOfViewYInRadians, aspect, zNear, zFar float64, 253 ) *Mat4[T] { 254 var ( 255 f = math.Tan(math.Pi*0.5 - 0.5*fieldOfViewYInRadians) 256 257 e10, e14 T 258 ) 259 260 if math.IsInf(zFar, 0) { 261 e10 = -1 262 e14 = T(-zNear) 263 } else { 264 rangeInv := 1 / (zNear - zFar) 265 e10 = T(zFar * rangeInv) 266 e14 = T(zFar * zNear * rangeInv) 267 } 268 269 *m = Mat4[T]{ 270 T(f / aspect), 0, 0, 0, 271 0, T(f), 0, 0, 272 0, 0, e10, -1, 273 0, 0, e14, 0, 274 } 275 276 return m 277 }