summaryrefslogtreecommitdiff
path: root/math_utils.go
blob: fac4d5da980422ad3f943afdbaf5bedaac8f7c9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package main

import "math"

// In a real application, use a dedicated math library like 'gonum/mat' or 'go-gl/mathgl'

type vec3 struct{ x, y, z float32 }
type mat4 [16]float32

func identity() mat4 {
	return mat4{
		1, 0, 0, 0,
		0, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1,
	}
}

func perspective(fovY, aspect, near, far float32) mat4 {
	f := float32(1.0 / math.Tan(float64(fovY*(math.Pi/180.0))/2.0))
	return mat4{
		f / aspect, 0, 0, 0,
		0, f, 0, 0,
		0, 0, (far + near) / (near - far), -1,
		0, 0, (2 * far * near) / (near - far), 0,
	}
}

func lookAt(eye, center, up vec3) mat4 {
	f := normalize(sub(center, eye))
	s := normalize(cross(f, up))
	u := cross(s, f)

	return mat4{
		s.x, u.x, -f.x, 0,
		s.y, u.y, -f.y, 0,
		s.z, u.z, -f.z, 0,
		-dot(s, eye), -dot(u, eye), dot(f, eye), 1,
	}
}

func rotate(m mat4, angle float32, axis vec3) mat4 {
	c := float32(math.Cos(float64(angle * (math.Pi / 180.0))))
	s := float32(math.Sin(float64(angle * (math.Pi / 180.0))))
	t := 1 - c
	x, y, z := axis.x, axis.y, axis.z

	// Normalize axis
	lenSq := x*x + y*y + z*z
	if lenSq > 0 && (lenSq < 0.9999 || lenSq > 1.0001) { // Check if not already normalized
		invLen := 1.0 / float32(math.Sqrt(float64(lenSq)))
		x *= invLen
		y *= invLen
		z *= invLen
	}

	rot := mat4{
		t*x*x + c, t*x*y - s*z, t*x*z + s*y, 0,
		t*x*y + s*z, t*y*y + c, t*y*z - s*x, 0,
		t*x*z - s*y, t*y*z + s*x, t*z*z + c, 0,
		0, 0, 0, 1,
	}
	return multiply(m, rot) // Apply rotation to existing model matrix
}

func sub(a, b vec3) vec3 { return vec3{a.x - b.x, a.y - b.y, a.z - b.z} }
func cross(a, b vec3) vec3 {
	return vec3{a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}
}
func dot(a, b vec3) float32 { return a.x*b.x + a.y*b.y + a.z*b.z }
func length(v vec3) float32 { return float32(math.Sqrt(float64(dot(v, v)))) }
func normalize(v vec3) vec3 {
	l := length(v)
	if l == 0 {
		return vec3{0, 0, 0}
	}
	return vec3{v.x / l, v.y / l, v.z / l}
}

func multiply(a, b mat4) mat4 {
	var out mat4
	for i := 0; i < 4; i++ {
		for j := 0; j < 4; j++ {
			sum := float32(0.0)
			for k := 0; k < 4; k++ {
				sum += a[i*4+k] * b[k*4+j]
			}
			out[i*4+j] = sum
		}
	}
	return out
}