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  }