mirror of
https://github.com/bloeys/gglm.git
synced 2025-12-29 13:38:20 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2de2e9696a | |||
| 81c22bfe4d | |||
| 9d9bcdfc05 | |||
| 710cca385f | |||
| 390222a18d | |||
| 2bdd7b2d02 | |||
| 61b2298cb1 | |||
| 62a2e4d7aa | |||
| 5980c50ced | |||
| 5f43d7da88 | |||
| 4a7e66c0b9 | |||
| 0bf7a06315 | |||
| ad5d2c49c8 | |||
| b2e9c48114 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -12,4 +12,5 @@
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
vendor/
|
||||
.vscode
|
||||
|
||||
@ -1,2 +1,8 @@
|
||||
# gglm
|
||||
An OpenGL focused Go mathematics inspired by the C++ glm (OpenGL Mathematics) library
|
||||
|
||||
Fast Go OpenGL Mathematics library inspired by the c++ library [glm](https://github.com/g-truc/glm).
|
||||
|
||||
## Notes
|
||||
|
||||
You can check compiler inlining decisions using `go run -gcflags "-m" .`. Some functions look a bit weird compared to similar ones
|
||||
because we are trying to reduce function complexity so the compiler inlines.
|
||||
|
||||
7
gglm/constants.go
Executable file
7
gglm/constants.go
Executable file
@ -0,0 +1,7 @@
|
||||
package gglm
|
||||
|
||||
const (
|
||||
Pi float32 = 3.14159265359
|
||||
Deg2Rad float32 = Pi / 180
|
||||
Rad2Deg float32 = 180 / Pi
|
||||
)
|
||||
@ -1,5 +1,7 @@
|
||||
package gglm
|
||||
|
||||
import "math"
|
||||
|
||||
func DotVec2(v1, v2 *Vec2) float32 {
|
||||
return v1.X()*v2.X() + v1.Y()*v2.Y()
|
||||
}
|
||||
@ -21,3 +23,86 @@ func Cross(v1, v2 *Vec3) *Vec3 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//DistVec2 returns euclidean distance between v1 and v2
|
||||
func DistVec2(v1, v2 *Vec2) float32 {
|
||||
x := v1.X() - v2.X()
|
||||
y := v1.Y() - v2.Y()
|
||||
return float32(math.Sqrt(float64(x*x + y*y)))
|
||||
}
|
||||
|
||||
//DistVec3 returns euclidean distance between v1 and v2
|
||||
func DistVec3(v1, v2 *Vec3) float32 {
|
||||
x := v1.X() - v2.X()
|
||||
y := v1.Y() - v2.Y()
|
||||
z := v1.Z() - v2.Z()
|
||||
return float32(math.Sqrt(float64(x*x + y*y + z*z)))
|
||||
}
|
||||
|
||||
//DistVec4 returns euclidean distance between v1 and v2
|
||||
func DistVec4(v1, v2 *Vec4) float32 {
|
||||
|
||||
//Using X() etc won't let the function inline
|
||||
x := v1.Data[0] - v2.Data[0]
|
||||
y := v1.Data[1] - v2.Data[1]
|
||||
z := v1.Data[2] - v2.Data[2]
|
||||
w := v1.Data[3] - v2.Data[3]
|
||||
return float32(math.Sqrt(float64(x*x + y*y + z*z + w*w)))
|
||||
}
|
||||
|
||||
//DistVec2 returns the squared euclidean distance between v1 and v2 (avoids a sqrt)
|
||||
func SqrDistVec2(v1, v2 *Vec2) float32 {
|
||||
x := v1.X() - v2.X()
|
||||
y := v1.Y() - v2.Y()
|
||||
return x*x + y*y
|
||||
}
|
||||
|
||||
//DistVec3 returns the squared euclidean distance between v1 and v2 (avoids a sqrt)
|
||||
func SqrDistVec3(v1, v2 *Vec3) float32 {
|
||||
x := v1.X() - v2.X()
|
||||
y := v1.Y() - v2.Y()
|
||||
z := v1.Z() - v2.Z()
|
||||
return x*x + y*y + z*z
|
||||
}
|
||||
|
||||
//DistVec4 returns the squared euclidean distance between v1 and v2 (avoids a sqrt)
|
||||
func SqrDistVec4(v1, v2 *Vec4) float32 {
|
||||
x := v1.Data[0] - v2.Data[0]
|
||||
y := v1.Data[1] - v2.Data[1]
|
||||
z := v1.Data[2] - v2.Data[2]
|
||||
w := v1.Data[3] - v2.Data[3]
|
||||
return x*x + y*y + z*z + w*w
|
||||
}
|
||||
|
||||
//ReflectVec2 returns the reflected vector of the incoming vector 'v', and the surface normal 'n'.
|
||||
//
|
||||
//Note: n must be normalized or you will get wrong results
|
||||
func ReflectVec2(v, n *Vec2) *Vec2 {
|
||||
|
||||
//reflectedVec = v − 2*dot(v, norm)*norm
|
||||
d := 2 * (v.Data[0]*n.Data[0] + v.Data[1]*n.Data[1])
|
||||
|
||||
return &Vec2{
|
||||
Data: [2]float32{
|
||||
v.Data[0] - d*n.Data[0],
|
||||
v.Data[1] - d*n.Data[1],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//ReflectVec3 returns the reflected vector of the incoming vector 'v', and the surface normal 'n'.
|
||||
//
|
||||
//Note: n must be normalized or you will get wrong results
|
||||
func ReflectVec3(v, n *Vec3) *Vec3 {
|
||||
|
||||
//reflectedVec = v − 2*dot(v, norm)*norm
|
||||
d := 2 * (v.Data[0]*n.Data[0] + v.Data[1]*n.Data[1] + v.Data[2]*n.Data[2])
|
||||
|
||||
return &Vec3{
|
||||
Data: [3]float32{
|
||||
v.Data[0] - d*n.Data[0],
|
||||
v.Data[1] - d*n.Data[1],
|
||||
v.Data[2] - d*n.Data[2],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
139
gglm/geometric_test.go
Executable file
139
gglm/geometric_test.go
Executable file
@ -0,0 +1,139 @@
|
||||
package gglm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
func TestDotVec2(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
v2 := gglm.Vec2{Data: [2]float32{3, 4}}
|
||||
ans := float32(11)
|
||||
|
||||
res := gglm.DotVec2(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDotVec3(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec3{Data: [3]float32{1, 2, 3}}
|
||||
v2 := gglm.Vec3{Data: [3]float32{4, 5, 6}}
|
||||
ans := float32(32)
|
||||
|
||||
res := gglm.DotVec3(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDotVec4(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec4{Data: [4]float32{1, 2, 3, 4}}
|
||||
v2 := gglm.Vec4{Data: [4]float32{5, 6, 7, 8}}
|
||||
ans := float32(70)
|
||||
|
||||
res := gglm.DotVec4(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDistVec2(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
v2 := gglm.Vec2{Data: [2]float32{3, 4}}
|
||||
ans := float32(2.828427)
|
||||
|
||||
res := gglm.DistVec2(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDistVec3(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec3{Data: [3]float32{1, 2, 3}}
|
||||
v2 := gglm.Vec3{Data: [3]float32{4, 5, 6}}
|
||||
ans := float32(5.196152)
|
||||
|
||||
res := gglm.DistVec3(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDistVec4(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec4{Data: [4]float32{1, 2, 3, 4}}
|
||||
v2 := gglm.Vec4{Data: [4]float32{5, 6, 7, 8}}
|
||||
ans := float32(8)
|
||||
|
||||
res := gglm.DistVec4(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqrDistVec2(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
v2 := gglm.Vec2{Data: [2]float32{3, 4}}
|
||||
ans := float32(8)
|
||||
|
||||
res := gglm.SqrDistVec2(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqrDistVec3(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec3{Data: [3]float32{1, 2, 3}}
|
||||
v2 := gglm.Vec3{Data: [3]float32{4, 5, 6}}
|
||||
ans := float32(27)
|
||||
|
||||
res := gglm.SqrDistVec3(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqrDistVec4(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec4{Data: [4]float32{1, 2, 3, 4}}
|
||||
v2 := gglm.Vec4{Data: [4]float32{5, 6, 7, 8}}
|
||||
ans := float32(64)
|
||||
|
||||
res := gglm.SqrDistVec4(&v1, &v2)
|
||||
if res != ans {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReflectVec2(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
n := gglm.Vec2{Data: [2]float32{0, 1}}
|
||||
ans := gglm.Vec2{Data: [2]float32{1, -2}}
|
||||
|
||||
res := gglm.ReflectVec2(&v1, &n)
|
||||
if !res.Eq(&ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReflectVec3(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec3{Data: [3]float32{1, 2, 3}}
|
||||
n := gglm.Vec3{Data: [3]float32{0, 1, 0}}
|
||||
ans := gglm.Vec3{Data: [3]float32{1, -2, 3}}
|
||||
|
||||
res := gglm.ReflectVec3(&v1, &n)
|
||||
if !res.Eq(&ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ func (ms MatSize) String() string {
|
||||
}
|
||||
|
||||
type Mat interface {
|
||||
At(row, col int) float32
|
||||
Get(row, col int) float32
|
||||
Set(row, col int, val float32)
|
||||
Size() MatSize
|
||||
}
|
||||
|
||||
28
gglm/mat2.go
28
gglm/mat2.go
@ -11,7 +11,7 @@ type Mat2 struct {
|
||||
Data [4]float32
|
||||
}
|
||||
|
||||
func (m *Mat2) At(row, col int) float32 {
|
||||
func (m *Mat2) Get(row, col int) float32 {
|
||||
return m.Data[row*2+col]
|
||||
}
|
||||
|
||||
@ -29,23 +29,25 @@ func (m *Mat2) String() string {
|
||||
}
|
||||
|
||||
//Add m += m2
|
||||
func (m *Mat2) Add(m2 *Mat2) {
|
||||
func (m *Mat2) Add(m2 *Mat2) *Mat2 {
|
||||
m.Data[0] += m2.Data[0]
|
||||
m.Data[1] += m2.Data[1]
|
||||
m.Data[2] += m2.Data[2]
|
||||
m.Data[3] += m2.Data[3]
|
||||
return m
|
||||
}
|
||||
|
||||
//Add m -= m2
|
||||
func (m *Mat2) Sub(m2 *Mat2) {
|
||||
func (m *Mat2) Sub(m2 *Mat2) *Mat2 {
|
||||
m.Data[0] -= m2.Data[0]
|
||||
m.Data[1] -= m2.Data[1]
|
||||
m.Data[2] -= m2.Data[2]
|
||||
m.Data[3] -= m2.Data[3]
|
||||
return m
|
||||
}
|
||||
|
||||
//Mul m *= m2
|
||||
func (m *Mat2) Mul(m2 *Mat2) {
|
||||
func (m *Mat2) Mul(m2 *Mat2) *Mat2 {
|
||||
m.Data = [4]float32{
|
||||
m.Data[0]*m2.Data[0] + m.Data[1]*m2.Data[2],
|
||||
m.Data[0]*m2.Data[1] + m.Data[1]*m2.Data[3],
|
||||
@ -53,14 +55,20 @@ func (m *Mat2) Mul(m2 *Mat2) {
|
||||
m.Data[2]*m2.Data[0] + m.Data[3]*m2.Data[2],
|
||||
m.Data[2]*m2.Data[1] + m.Data[3]*m2.Data[3],
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
//Scale m *= x (element wise multiplication)
|
||||
func (m *Mat2) Scale(x float32) {
|
||||
func (m *Mat2) Scale(x float32) *Mat2 {
|
||||
m.Data[0] *= x
|
||||
m.Data[1] *= x
|
||||
m.Data[2] *= x
|
||||
m.Data[3] *= x
|
||||
return m
|
||||
}
|
||||
|
||||
func (v *Mat2) Clone() *Mat2 {
|
||||
return &Mat2{Data: v.Data}
|
||||
}
|
||||
|
||||
func (m *Mat2) Eq(m2 *Mat2) bool {
|
||||
@ -104,6 +112,16 @@ func MulMat2(m1, m2 *Mat2) *Mat2 {
|
||||
}
|
||||
}
|
||||
|
||||
//MulMat2Vec2 v2 = m1 * v1
|
||||
func MulMat2Vec2(m1 *Mat2, v1 *Vec2) *Vec2 {
|
||||
return &Vec2{
|
||||
Data: [2]float32{
|
||||
m1.Data[0]*v1.Data[0] + m1.Data[1]*v1.Data[1],
|
||||
m1.Data[2]*v1.Data[0] + m1.Data[3]*v1.Data[1],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//NewMat2Id returns the 2x2 identity matrix
|
||||
func NewMat2Id() *Mat2 {
|
||||
return &Mat2{
|
||||
|
||||
148
gglm/mat2_test.go
Executable file
148
gglm/mat2_test.go
Executable file
@ -0,0 +1,148 @@
|
||||
package gglm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
func TestMat2GetSet(t *testing.T) {
|
||||
|
||||
m1 := gglm.Mat2{}
|
||||
|
||||
m1.Set(0, 1, -10)
|
||||
m1.Set(1, 0, 55)
|
||||
|
||||
if m1.Get(0, 1) != -10 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(0, 1), -10)
|
||||
}
|
||||
|
||||
if m1.Get(1, 0) != 55 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(1, 0), 55)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMat2Id(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
1, 0,
|
||||
0, 1,
|
||||
}}
|
||||
|
||||
m1 := gglm.NewMat2Id()
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubMat2(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
-4, -4,
|
||||
-4, -4,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
1, 2,
|
||||
3, 4,
|
||||
}}
|
||||
m2 := &gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
5, 6,
|
||||
7, 8,
|
||||
}}
|
||||
|
||||
result := gglm.SubMat2(m1, m2)
|
||||
m1.Sub(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddMat2(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
6, 8,
|
||||
10, 12,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
1, 2,
|
||||
3, 4,
|
||||
}}
|
||||
m2 := &gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
5, 6,
|
||||
7, 8,
|
||||
}}
|
||||
|
||||
result := gglm.AddMat2(m1, m2)
|
||||
m1.Add(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulMat2(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
19, 22,
|
||||
43, 50,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
1, 2,
|
||||
3, 4,
|
||||
}}
|
||||
m2 := &gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
5, 6,
|
||||
7, 8,
|
||||
}}
|
||||
|
||||
result := gglm.MulMat2(m1, m2)
|
||||
m1.Mul(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulMat2Vec2(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Vec2{Data: [2]float32{5, 11}}
|
||||
|
||||
m := &gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
1, 2,
|
||||
3, 4,
|
||||
}}
|
||||
v := &gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
|
||||
result := gglm.MulMat2Vec2(m, v)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
29
gglm/mat3.go
29
gglm/mat3.go
@ -11,7 +11,7 @@ type Mat3 struct {
|
||||
Data [9]float32
|
||||
}
|
||||
|
||||
func (m *Mat3) At(row, col int) float32 {
|
||||
func (m *Mat3) Get(row, col int) float32 {
|
||||
return m.Data[row*3+col]
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ func (m *Mat3) String() string {
|
||||
}
|
||||
|
||||
//Add m += m2
|
||||
func (m *Mat3) Add(m2 *Mat3) {
|
||||
func (m *Mat3) Add(m2 *Mat3) *Mat3 {
|
||||
|
||||
m.Data[0] += m2.Data[0]
|
||||
m.Data[1] += m2.Data[1]
|
||||
@ -45,10 +45,11 @@ func (m *Mat3) Add(m2 *Mat3) {
|
||||
m.Data[6] += m2.Data[6]
|
||||
m.Data[7] += m2.Data[7]
|
||||
m.Data[8] += m2.Data[8]
|
||||
return m
|
||||
}
|
||||
|
||||
//Add m -= m2
|
||||
func (m *Mat3) Sub(m2 *Mat3) {
|
||||
func (m *Mat3) Sub(m2 *Mat3) *Mat3 {
|
||||
|
||||
m.Data[0] -= m2.Data[0]
|
||||
m.Data[1] -= m2.Data[1]
|
||||
@ -61,10 +62,11 @@ func (m *Mat3) Sub(m2 *Mat3) {
|
||||
m.Data[6] -= m2.Data[6]
|
||||
m.Data[7] -= m2.Data[7]
|
||||
m.Data[8] -= m2.Data[8]
|
||||
return m
|
||||
}
|
||||
|
||||
//Mul m *= m2
|
||||
func (m *Mat3) Mul(m2 *Mat3) {
|
||||
func (m *Mat3) Mul(m2 *Mat3) *Mat3 {
|
||||
|
||||
//Indices:
|
||||
// 0, 1, 2,
|
||||
@ -84,10 +86,11 @@ func (m *Mat3) Mul(m2 *Mat3) {
|
||||
m.Data[6]*m2.Data[1] + m.Data[7]*m2.Data[4] + m.Data[8]*m2.Data[7],
|
||||
m.Data[6]*m2.Data[2] + m.Data[7]*m2.Data[5] + m.Data[8]*m2.Data[8],
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
//Scale m *= x (element wise multiplication)
|
||||
func (m *Mat3) Scale(x float32) {
|
||||
func (m *Mat3) Scale(x float32) *Mat3 {
|
||||
|
||||
m.Data[0] *= x
|
||||
m.Data[1] *= x
|
||||
@ -100,6 +103,11 @@ func (m *Mat3) Scale(x float32) {
|
||||
m.Data[6] *= x
|
||||
m.Data[7] *= x
|
||||
m.Data[8] *= x
|
||||
return m
|
||||
}
|
||||
|
||||
func (v *Mat3) Clone() *Mat3 {
|
||||
return &Mat3{Data: v.Data}
|
||||
}
|
||||
|
||||
func (m *Mat3) Eq(m2 *Mat3) bool {
|
||||
@ -163,6 +171,17 @@ func MulMat3(m1, m2 *Mat3) *Mat3 {
|
||||
}
|
||||
}
|
||||
|
||||
//MulMat3Vec3 v2 = m1 * v1
|
||||
func MulMat3Vec3(m1 *Mat3, v1 *Vec3) *Vec3 {
|
||||
return &Vec3{
|
||||
Data: [3]float32{
|
||||
m1.Data[0]*v1.Data[0] + m1.Data[1]*v1.Data[1] + m1.Data[2]*v1.Data[2],
|
||||
m1.Data[3]*v1.Data[0] + m1.Data[4]*v1.Data[1] + m1.Data[5]*v1.Data[2],
|
||||
m1.Data[6]*v1.Data[0] + m1.Data[7]*v1.Data[1] + m1.Data[8]*v1.Data[2],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//NewMat3Id returns the 3x3 identity matrix
|
||||
func NewMat3Id() *Mat3 {
|
||||
return &Mat3{
|
||||
|
||||
163
gglm/mat3_test.go
Executable file
163
gglm/mat3_test.go
Executable file
@ -0,0 +1,163 @@
|
||||
package gglm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
func TestMat3GetSet(t *testing.T) {
|
||||
|
||||
m1 := gglm.Mat3{}
|
||||
|
||||
m1.Set(0, 1, -10)
|
||||
m1.Set(1, 0, 55)
|
||||
m1.Set(2, 2, 99)
|
||||
|
||||
if m1.Get(0, 1) != -10 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(0, 1), -10)
|
||||
}
|
||||
|
||||
if m1.Get(1, 0) != 55 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(1, 0), 55)
|
||||
}
|
||||
|
||||
if m1.Get(2, 2) != 99 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(2, 2), 99)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMat3Id(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
}}
|
||||
|
||||
m1 := gglm.NewMat3Id()
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubMat3(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
-9, -9, -9,
|
||||
-9, -9, -9,
|
||||
-9, -9, -9,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
}}
|
||||
m2 := &gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
10, 11, 12,
|
||||
13, 14, 15,
|
||||
16, 17, 18,
|
||||
}}
|
||||
|
||||
result := gglm.SubMat3(m1, m2)
|
||||
m1.Sub(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddMat3(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
11, 13, 15,
|
||||
17, 19, 21,
|
||||
23, 25, 27,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
}}
|
||||
m2 := &gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
10, 11, 12,
|
||||
13, 14, 15,
|
||||
16, 17, 18,
|
||||
}}
|
||||
|
||||
result := gglm.AddMat3(m1, m2)
|
||||
m1.Add(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulMat3(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
84, 90, 96,
|
||||
201, 216, 231,
|
||||
318, 342, 366,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
}}
|
||||
m2 := &gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
10, 11, 12,
|
||||
13, 14, 15,
|
||||
16, 17, 18,
|
||||
}}
|
||||
|
||||
result := gglm.MulMat3(m1, m2)
|
||||
m1.Mul(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulMat3Vec3(t *testing.T) {
|
||||
|
||||
m := &gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
}}
|
||||
v := &gglm.Vec3{Data: [3]float32{1, 2, 3}}
|
||||
|
||||
result := gglm.MulMat3Vec3(m, v)
|
||||
correctAns := gglm.Vec3{Data: [3]float32{14, 32, 50}}
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
32
gglm/mat4.go
32
gglm/mat4.go
@ -11,7 +11,7 @@ type Mat4 struct {
|
||||
Data [16]float32
|
||||
}
|
||||
|
||||
func (m *Mat4) At(row, col int) float32 {
|
||||
func (m *Mat4) Get(row, col int) float32 {
|
||||
return m.Data[row*4+col]
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ func (m *Mat4) String() string {
|
||||
}
|
||||
|
||||
//Add m += m2
|
||||
func (m *Mat4) Add(m2 *Mat4) {
|
||||
func (m *Mat4) Add(m2 *Mat4) *Mat4 {
|
||||
|
||||
m.Data[0] += m2.Data[0]
|
||||
m.Data[1] += m2.Data[1]
|
||||
@ -54,10 +54,12 @@ func (m *Mat4) Add(m2 *Mat4) {
|
||||
m.Data[13] += m2.Data[13]
|
||||
m.Data[14] += m2.Data[14]
|
||||
m.Data[15] += m2.Data[15]
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
//Add m -= m2
|
||||
func (m *Mat4) Sub(m2 *Mat4) {
|
||||
func (m *Mat4) Sub(m2 *Mat4) *Mat4 {
|
||||
|
||||
m.Data[0] -= m2.Data[0]
|
||||
m.Data[1] -= m2.Data[1]
|
||||
@ -78,10 +80,11 @@ func (m *Mat4) Sub(m2 *Mat4) {
|
||||
m.Data[13] -= m2.Data[13]
|
||||
m.Data[14] -= m2.Data[14]
|
||||
m.Data[15] -= m2.Data[15]
|
||||
return m
|
||||
}
|
||||
|
||||
//Mul m *= m2
|
||||
func (m *Mat4) Mul(m2 *Mat4) {
|
||||
func (m *Mat4) Mul(m2 *Mat4) *Mat4 {
|
||||
|
||||
//Indices:
|
||||
// 00, 01, 02, 03,
|
||||
@ -117,10 +120,12 @@ func (m *Mat4) Mul(m2 *Mat4) {
|
||||
m.Data[12]*m2.Data[2] + m.Data[13]*m2.Data[6] + m.Data[14]*m2.Data[10] + m.Data[15]*m2.Data[14],
|
||||
m.Data[12]*m2.Data[3] + m.Data[13]*m2.Data[7] + m.Data[14]*m2.Data[11] + m.Data[15]*m2.Data[15],
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
//Scale m *= x (element wise multiplication)
|
||||
func (m *Mat4) Scale(x float32) {
|
||||
func (m *Mat4) Scale(x float32) *Mat4 {
|
||||
|
||||
m.Data[0] *= x
|
||||
m.Data[1] *= x
|
||||
@ -141,6 +146,11 @@ func (m *Mat4) Scale(x float32) {
|
||||
m.Data[13] *= x
|
||||
m.Data[14] *= x
|
||||
m.Data[15] *= x
|
||||
return m
|
||||
}
|
||||
|
||||
func (v *Mat4) Clone() *Mat4 {
|
||||
return &Mat4{Data: v.Data}
|
||||
}
|
||||
|
||||
func (m *Mat4) Eq(m2 *Mat4) bool {
|
||||
@ -234,6 +244,18 @@ func MulMat4(m1, m2 *Mat4) *Mat4 {
|
||||
}
|
||||
}
|
||||
|
||||
//MulMat4Vec4 v2 = m1 * v1
|
||||
func MulMat4Vec4(m1 *Mat4, v1 *Vec4) *Vec4 {
|
||||
return &Vec4{
|
||||
Data: [4]float32{
|
||||
m1.Data[0]*v1.Data[0] + m1.Data[1]*v1.Data[1] + m1.Data[2]*v1.Data[2] + m1.Data[3]*v1.Data[3],
|
||||
m1.Data[4]*v1.Data[0] + m1.Data[5]*v1.Data[1] + m1.Data[6]*v1.Data[2] + m1.Data[7]*v1.Data[3],
|
||||
m1.Data[8]*v1.Data[0] + m1.Data[9]*v1.Data[1] + m1.Data[10]*v1.Data[2] + m1.Data[11]*v1.Data[3],
|
||||
m1.Data[12]*v1.Data[0] + m1.Data[13]*v1.Data[1] + m1.Data[14]*v1.Data[2] + m1.Data[15]*v1.Data[3],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//NewMat4Id returns the 4x4 identity matrix
|
||||
func NewMat4Id() *Mat4 {
|
||||
return &Mat4{
|
||||
|
||||
179
gglm/mat4_test.go
Executable file
179
gglm/mat4_test.go
Executable file
@ -0,0 +1,179 @@
|
||||
package gglm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
func TestMat4GetSet(t *testing.T) {
|
||||
|
||||
m1 := gglm.Mat4{}
|
||||
|
||||
m1.Set(0, 1, -10)
|
||||
m1.Set(1, 0, 55)
|
||||
m1.Set(2, 2, 99)
|
||||
m1.Set(3, 3, 513)
|
||||
|
||||
if m1.Get(0, 1) != -10 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(0, 1), -10)
|
||||
}
|
||||
|
||||
if m1.Get(1, 0) != 55 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(1, 0), 55)
|
||||
}
|
||||
|
||||
if m1.Get(2, 2) != 99 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(2, 2), 99)
|
||||
}
|
||||
|
||||
if m1.Get(3, 3) != 513 {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.Get(3, 3), 513)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMat4Id(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
}}
|
||||
|
||||
m1 := gglm.NewMat4Id()
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubMat4(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
-16, -16, -16, -16,
|
||||
-16, -16, -16, -16,
|
||||
-16, -16, -16, -16,
|
||||
-16, -16, -16, -16,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
}}
|
||||
m2 := &gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
17, 18, 19, 20,
|
||||
21, 22, 23, 24,
|
||||
25, 26, 27, 28,
|
||||
29, 30, 31, 32,
|
||||
}}
|
||||
|
||||
result := gglm.SubMat4(m1, m2)
|
||||
m1.Sub(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddMat4(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
18, 20, 22, 24,
|
||||
26, 28, 30, 32,
|
||||
34, 36, 38, 40,
|
||||
42, 44, 46, 48,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
}}
|
||||
m2 := &gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
17, 18, 19, 20,
|
||||
21, 22, 23, 24,
|
||||
25, 26, 27, 28,
|
||||
29, 30, 31, 32,
|
||||
}}
|
||||
|
||||
result := gglm.AddMat4(m1, m2)
|
||||
m1.Add(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulMat4(t *testing.T) {
|
||||
|
||||
correctAns := gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
250, 260, 270, 280,
|
||||
618, 644, 670, 696,
|
||||
986, 1028, 1070, 1112,
|
||||
1354, 1412, 1470, 1528,
|
||||
}}
|
||||
|
||||
m1 := &gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
}}
|
||||
m2 := &gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
17, 18, 19, 20,
|
||||
21, 22, 23, 24,
|
||||
25, 26, 27, 28,
|
||||
29, 30, 31, 32,
|
||||
}}
|
||||
|
||||
result := gglm.MulMat4(m1, m2)
|
||||
m1.Mul(m2)
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
|
||||
if !m1.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", m1.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulMat4Vec4(t *testing.T) {
|
||||
|
||||
m := &gglm.Mat4{
|
||||
Data: [16]float32{
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
}}
|
||||
v := &gglm.Vec4{Data: [4]float32{1, 2, 3, 4}}
|
||||
|
||||
result := gglm.MulMat4Vec4(m, v)
|
||||
correctAns := gglm.Vec4{Data: [4]float32{30, 70, 110, 150}}
|
||||
|
||||
if !result.Eq(&correctAns) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
63
gglm/quat.go
Executable file
63
gglm/quat.go
Executable file
@ -0,0 +1,63 @@
|
||||
package gglm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var _ Swizzle4 = &Quat{}
|
||||
var _ fmt.Stringer = &Quat{}
|
||||
|
||||
type Quat struct {
|
||||
Vec4
|
||||
}
|
||||
|
||||
//Euler takes rotations in radians and produces a rotation that
|
||||
//rotates around the z-axis, y-axis and lastly x-axis.
|
||||
func NewQuatEuler(v *Vec3) *Quat {
|
||||
|
||||
//Some other common terminology: x=roll, y=pitch, z=yaw
|
||||
sinX, cosX := Sincos32(v.Data[0] * 0.5)
|
||||
sinY, cosY := Sincos32(v.Data[1] * 0.5)
|
||||
sinZ, cosZ := Sincos32(v.Data[2] * 0.5)
|
||||
|
||||
//This produces a z->y->x multiply order, but its written as XYZ.
|
||||
//This is due to XYZ meaning independent rotation matrices, so Z is applied
|
||||
//first, then Y matrix and lastly X.
|
||||
//See this for more info: https://github.com/godotengine/godot/issues/6816#issuecomment-254592170
|
||||
//
|
||||
//Note: On most conversion tools putting the multiply order (e.g. ZYX for us) is required.
|
||||
return &Quat{
|
||||
Vec4: Vec4{
|
||||
Data: [4]float32{
|
||||
sinX*cosY*cosZ - cosX*sinY*sinZ,
|
||||
cosX*sinY*cosZ + sinX*cosY*sinZ,
|
||||
cosX*cosY*sinZ - sinX*sinY*cosZ,
|
||||
cosX*cosY*cosZ + sinX*sinY*sinZ,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//AngleAxis rotates rotRad radians around the *normalized* vector rotAxisNorm
|
||||
func NewQuatAngleAxis(rotRad float32, rotAxisNorm *Vec3) *Quat {
|
||||
|
||||
s, c := Sincos32(rotRad * 0.5)
|
||||
return &Quat{
|
||||
Vec4: Vec4{
|
||||
Data: [4]float32{
|
||||
rotAxisNorm.Data[0] * s,
|
||||
rotAxisNorm.Data[1] * s,
|
||||
rotAxisNorm.Data[2] * s,
|
||||
c,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewQuatId() *Quat {
|
||||
return &Quat{
|
||||
Vec4: Vec4{
|
||||
Data: [4]float32{0, 0, 0, 1},
|
||||
},
|
||||
}
|
||||
}
|
||||
29
gglm/scalar.go
Executable file
29
gglm/scalar.go
Executable file
@ -0,0 +1,29 @@
|
||||
package gglm
|
||||
|
||||
import "math"
|
||||
|
||||
//F32Epsilon = 0.0000005
|
||||
const F32Epsilon float32 = 1e-6
|
||||
|
||||
//EqF32 true if abs(f1-f2) <= F32Epsilon
|
||||
func EqF32(f1, f2 float32) bool {
|
||||
return math.Abs(float64(f1-f2)) <= float64(F32Epsilon)
|
||||
}
|
||||
|
||||
//EqF32Epsilon true if abs(f1-f2) <= eps
|
||||
func EqF32Epsilon(f1, f2, eps float32) bool {
|
||||
return math.Abs(float64(f1-f2)) <= float64(eps)
|
||||
}
|
||||
|
||||
func Sin32(x float32) float32 {
|
||||
return float32(math.Sin(float64(x)))
|
||||
}
|
||||
|
||||
func Cos32(x float32) float32 {
|
||||
return float32(math.Cos(float64(x)))
|
||||
}
|
||||
|
||||
func Sincos32(x float32) (sinx, cosx float32) {
|
||||
a, b := math.Sincos(float64(x))
|
||||
return float32(a), float32(b)
|
||||
}
|
||||
@ -3,22 +3,34 @@ package gglm
|
||||
type Swizzle1 interface {
|
||||
X() float32
|
||||
R() float32
|
||||
|
||||
SetX(float32)
|
||||
SetR(float32)
|
||||
}
|
||||
|
||||
type Swizzle2 interface {
|
||||
Swizzle1
|
||||
Y() float32
|
||||
G() float32
|
||||
|
||||
SetY(float32)
|
||||
SetG(float32)
|
||||
}
|
||||
|
||||
type Swizzle3 interface {
|
||||
Swizzle2
|
||||
Z() float32
|
||||
B() float32
|
||||
|
||||
SetZ(float32)
|
||||
SetB(float32)
|
||||
}
|
||||
|
||||
type Swizzle4 interface {
|
||||
Swizzle3
|
||||
W() float32
|
||||
A() float32
|
||||
|
||||
SetW(float32)
|
||||
SetA(float32)
|
||||
}
|
||||
|
||||
99
gglm/transform.go
Executable file
99
gglm/transform.go
Executable file
@ -0,0 +1,99 @@
|
||||
package gglm
|
||||
|
||||
import "fmt"
|
||||
|
||||
var _ Mat = &TrMat{}
|
||||
var _ fmt.Stringer = &TrMat{}
|
||||
|
||||
//TrMat represents a transformation matrix
|
||||
type TrMat struct {
|
||||
Mat4
|
||||
}
|
||||
|
||||
//Translate adds the vector to the translation components of the transformation matrix
|
||||
func (t *TrMat) Translate(v *Vec3) {
|
||||
t.Data[3] += v.Data[0]
|
||||
t.Data[7] += v.Data[1]
|
||||
t.Data[11] += v.Data[2]
|
||||
}
|
||||
|
||||
//Scale multiplies the vector by the scale components of the transformation matrix
|
||||
func (t *TrMat) Scale(v *Vec3) {
|
||||
t.Data[0] *= v.Data[0]
|
||||
t.Data[5] *= v.Data[1]
|
||||
t.Data[10] *= v.Data[2]
|
||||
}
|
||||
|
||||
func (t *TrMat) Mul(m *TrMat) *TrMat {
|
||||
t.Mat4.Mul(&m.Mat4)
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TrMat) Clone() *TrMat {
|
||||
return &TrMat{
|
||||
Mat4: *t.Mat4.Clone(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewTranslationMat(v *Vec3) *TrMat {
|
||||
return &TrMat{
|
||||
Mat4: Mat4{
|
||||
Data: [16]float32{
|
||||
1, 0, 0, v.Data[0],
|
||||
0, 1, 0, v.Data[1],
|
||||
0, 0, 1, v.Data[2],
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewScaleMat(v *Vec3) *TrMat {
|
||||
return &TrMat{
|
||||
Mat4: Mat4{
|
||||
Data: [16]float32{
|
||||
v.Data[0], 0, 0, 0,
|
||||
0, v.Data[1], 0, 0,
|
||||
0, 0, v.Data[2], 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewRotMat(q *Quat) *TrMat {
|
||||
|
||||
//Based on: https://www.weizmann.ac.il/sci-tea/benari/sites/sci-tea.benari/files/uploads/softwareAndLearningMaterials/quaternion-tutorial-2-0-1.pdf
|
||||
//Note: in the reference p0,p1,p2,p3 == w,x,y,z
|
||||
|
||||
xx := q.Data[0] * q.Data[0]
|
||||
yy := q.Data[1] * q.Data[1]
|
||||
zz := q.Data[2] * q.Data[2]
|
||||
ww := q.Data[3] * q.Data[3]
|
||||
|
||||
xy := q.Data[0] * q.Data[1]
|
||||
xz := q.Data[0] * q.Data[2]
|
||||
xw := q.Data[0] * q.Data[3]
|
||||
|
||||
yz := q.Data[1] * q.Data[2]
|
||||
yw := q.Data[1] * q.Data[3]
|
||||
|
||||
zw := q.Data[2] * q.Data[3]
|
||||
|
||||
return &TrMat{
|
||||
Mat4: Mat4{
|
||||
Data: [16]float32{
|
||||
2*(ww+xx) - 1, 2 * (xy - zw), 2 * (yw + xz), 0,
|
||||
2 * (zw + xy), 2*(ww+yy) - 1, 2 * (yz - xw), 0,
|
||||
2 * (xz - yw), 2 * (xw + yz), 2*(ww+zz) - 1, 0,
|
||||
0, 0, 0, 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewTransformMatId() *TrMat {
|
||||
return &TrMat{
|
||||
Mat4: *NewMat4Id(),
|
||||
}
|
||||
}
|
||||
49
gglm/vec2.go
49
gglm/vec2.go
@ -30,26 +30,45 @@ func (v *Vec2) G() float32 {
|
||||
return v.Data[1]
|
||||
}
|
||||
|
||||
func (v *Vec2) SetX(f float32) {
|
||||
v.Data[0] = f
|
||||
}
|
||||
|
||||
func (v *Vec2) SetR(f float32) {
|
||||
v.Data[0] = f
|
||||
}
|
||||
|
||||
func (v *Vec2) SetY(f float32) {
|
||||
v.Data[1] = f
|
||||
}
|
||||
|
||||
func (v *Vec2) SetG(f float32) {
|
||||
v.Data[1] = f
|
||||
}
|
||||
|
||||
func (v *Vec2) String() string {
|
||||
return fmt.Sprintf("(%f, %f)", v.X(), v.Y())
|
||||
}
|
||||
|
||||
//Scale v *= x (element wise multiplication)
|
||||
func (v *Vec2) Scale(x float32) {
|
||||
func (v *Vec2) Scale(x float32) *Vec2 {
|
||||
v.Data[0] *= x
|
||||
v.Data[1] *= x
|
||||
return v
|
||||
}
|
||||
|
||||
//Add v += v2
|
||||
func (v *Vec2) Add(v2 *Vec2) {
|
||||
func (v *Vec2) Add(v2 *Vec2) *Vec2 {
|
||||
v.Data[0] += v2.X()
|
||||
v.Data[1] += v2.Y()
|
||||
return v
|
||||
}
|
||||
|
||||
//SubVec2 v -= v2
|
||||
func (v *Vec2) Sub(v2 *Vec2) {
|
||||
func (v *Vec2) Sub(v2 *Vec2) *Vec2 {
|
||||
v.Data[0] -= v2.X()
|
||||
v.Data[1] -= v2.Y()
|
||||
return v
|
||||
}
|
||||
|
||||
//Mag returns the magnitude of the vector
|
||||
@ -66,6 +85,21 @@ func (v *Vec2) Eq(v2 *Vec2) bool {
|
||||
return v.Data == v2.Data
|
||||
}
|
||||
|
||||
func (v *Vec2) Set(x, y float32) {
|
||||
v.Data[0] = x
|
||||
v.Data[1] = y
|
||||
}
|
||||
|
||||
func (v *Vec2) Normalize() {
|
||||
mag := v.Mag()
|
||||
v.Data[0] /= mag
|
||||
v.Data[1] /= mag
|
||||
}
|
||||
|
||||
func (v *Vec2) Clone() *Vec2 {
|
||||
return &Vec2{Data: v.Data}
|
||||
}
|
||||
|
||||
//AddVec2 v3 = v1 + v2
|
||||
func AddVec2(v1, v2 *Vec2) *Vec2 {
|
||||
return &Vec2{
|
||||
@ -85,3 +119,12 @@ func SubVec2(v1, v2 *Vec2) *Vec2 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewVec2(x, y float32) *Vec2 {
|
||||
return &Vec2{
|
||||
[2]float32{
|
||||
x,
|
||||
y,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
74
gglm/vec3.go
74
gglm/vec3.go
@ -36,29 +36,56 @@ func (v *Vec3) B() float32 {
|
||||
return v.Data[2]
|
||||
}
|
||||
|
||||
func (v *Vec3) SetX(f float32) {
|
||||
v.Data[0] = f
|
||||
}
|
||||
|
||||
func (v *Vec3) SetR(f float32) {
|
||||
v.Data[0] = f
|
||||
}
|
||||
|
||||
func (v *Vec3) SetY(f float32) {
|
||||
v.Data[1] = f
|
||||
}
|
||||
|
||||
func (v *Vec3) SetG(f float32) {
|
||||
v.Data[1] = f
|
||||
}
|
||||
|
||||
func (v *Vec3) SetZ(f float32) {
|
||||
v.Data[2] = f
|
||||
}
|
||||
|
||||
func (v *Vec3) SetB(f float32) {
|
||||
v.Data[2] = f
|
||||
}
|
||||
|
||||
func (v *Vec3) String() string {
|
||||
return fmt.Sprintf("(%f, %f, %f)", v.X(), v.Y(), v.Z())
|
||||
}
|
||||
|
||||
//Scale v *= x (element wise multiplication)
|
||||
func (v *Vec3) Scale(x float32) {
|
||||
func (v *Vec3) Scale(x float32) *Vec3 {
|
||||
v.Data[0] *= x
|
||||
v.Data[1] *= x
|
||||
v.Data[2] *= x
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *Vec3) Add(v2 *Vec3) {
|
||||
func (v *Vec3) Add(v2 *Vec3) *Vec3 {
|
||||
|
||||
v.Data[0] += v2.X()
|
||||
v.Data[1] += v2.Y()
|
||||
v.Data[2] += v2.Z()
|
||||
return v
|
||||
}
|
||||
|
||||
//SubVec3 v -= v2
|
||||
func (v *Vec3) Sub(v2 *Vec3) {
|
||||
func (v *Vec3) Sub(v2 *Vec3) *Vec3 {
|
||||
v.Data[0] -= v2.X()
|
||||
v.Data[1] -= v2.Y()
|
||||
v.Data[2] -= v2.Z()
|
||||
return v
|
||||
}
|
||||
|
||||
//Mag returns the magnitude of the vector
|
||||
@ -75,6 +102,37 @@ func (v *Vec3) Eq(v2 *Vec3) bool {
|
||||
return v.Data == v2.Data
|
||||
}
|
||||
|
||||
func (v *Vec3) Set(x, y, z float32) {
|
||||
v.Data[0] = x
|
||||
v.Data[1] = y
|
||||
v.Data[2] = z
|
||||
}
|
||||
|
||||
//Normalize normalizes this vector and returns it (doesn't copy)
|
||||
func (v *Vec3) Normalize() *Vec3 {
|
||||
mag := float32(math.Sqrt(float64(v.X()*v.X() + v.Y()*v.Y() + v.Z()*v.Z())))
|
||||
v.Data[0] /= mag
|
||||
v.Data[1] /= mag
|
||||
v.Data[2] /= mag
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *Vec3) Clone() *Vec3 {
|
||||
return &Vec3{Data: v.Data}
|
||||
}
|
||||
|
||||
//AsRad returns a new vector with all values converted to Radians (i.e. multiplied by gglm.Deg2Rad)
|
||||
func (v *Vec3) AsRad() *Vec3 {
|
||||
return &Vec3{
|
||||
Data: [3]float32{
|
||||
v.Data[0] * Deg2Rad,
|
||||
v.Data[1] * Deg2Rad,
|
||||
v.Data[2] * Deg2Rad,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//AddVec3 v3 = v1 + v2
|
||||
func AddVec3(v1, v2 *Vec3) *Vec3 {
|
||||
return &Vec3{
|
||||
@ -96,3 +154,13 @@ func SubVec3(v1, v2 *Vec3) *Vec3 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewVec3(x, y, z float32) *Vec3 {
|
||||
return &Vec3{
|
||||
[3]float32{
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
72
gglm/vec4.go
72
gglm/vec4.go
@ -44,32 +44,66 @@ func (v *Vec4) A() float32 {
|
||||
return v.Data[3]
|
||||
}
|
||||
|
||||
func (v *Vec4) SetX(f float32) {
|
||||
v.Data[0] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) SetR(f float32) {
|
||||
v.Data[0] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) SetY(f float32) {
|
||||
v.Data[1] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) SetG(f float32) {
|
||||
v.Data[1] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) SetZ(f float32) {
|
||||
v.Data[2] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) SetB(f float32) {
|
||||
v.Data[2] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) SetW(f float32) {
|
||||
v.Data[3] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) SetA(f float32) {
|
||||
v.Data[3] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) String() string {
|
||||
return fmt.Sprintf("(%f, %f, %f, %f)", v.X(), v.Y(), v.Z(), v.W())
|
||||
}
|
||||
|
||||
//Scale v *= x (element wise multiplication)
|
||||
func (v *Vec4) Scale(x float32) {
|
||||
func (v *Vec4) Scale(x float32) *Vec4 {
|
||||
v.Data[0] *= x
|
||||
v.Data[1] *= x
|
||||
v.Data[2] *= x
|
||||
v.Data[3] *= x
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *Vec4) Add(v2 *Vec4) {
|
||||
|
||||
func (v *Vec4) Add(v2 *Vec4) *Vec4 {
|
||||
v.Data[0] += v2.X()
|
||||
v.Data[1] += v2.Y()
|
||||
v.Data[2] += v2.Z()
|
||||
v.Data[3] += v2.W()
|
||||
return v
|
||||
}
|
||||
|
||||
//SubVec4 v -= v2
|
||||
func (v *Vec4) Sub(v2 *Vec4) {
|
||||
func (v *Vec4) Sub(v2 *Vec4) *Vec4 {
|
||||
v.Data[0] -= v2.X()
|
||||
v.Data[1] -= v2.Y()
|
||||
v.Data[2] -= v2.Z()
|
||||
v.Data[3] -= v2.W()
|
||||
return v
|
||||
}
|
||||
|
||||
//Mag returns the magnitude of the vector
|
||||
@ -86,6 +120,25 @@ func (v *Vec4) Eq(v2 *Vec4) bool {
|
||||
return v.Data == v2.Data
|
||||
}
|
||||
|
||||
func (v *Vec4) Set(x, y, z, w float32) {
|
||||
v.Data[0] = x
|
||||
v.Data[1] = y
|
||||
v.Data[2] = z
|
||||
v.Data[3] = w
|
||||
}
|
||||
|
||||
func (v *Vec4) Normalize() {
|
||||
mag := float32(math.Sqrt(float64(v.Data[0]*v.Data[0] + v.Data[1]*v.Data[1] + v.Data[2]*v.Data[2] + v.Data[3]*v.Data[3])))
|
||||
v.Data[0] /= mag
|
||||
v.Data[1] /= mag
|
||||
v.Data[2] /= mag
|
||||
v.Data[3] /= mag
|
||||
}
|
||||
|
||||
func (v *Vec4) Clone() *Vec4 {
|
||||
return &Vec4{Data: v.Data}
|
||||
}
|
||||
|
||||
//AddVec4 v3 = v1 + v2
|
||||
func AddVec4(v1, v2 *Vec4) *Vec4 {
|
||||
return &Vec4{
|
||||
@ -109,3 +162,14 @@ func SubVec4(v1, v2 *Vec4) *Vec4 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewVec4(x, y, z, w float32) *Vec4 {
|
||||
return &Vec4{
|
||||
[4]float32{
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
w,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
109
main.go
109
main.go
@ -50,4 +50,113 @@ func main() {
|
||||
println(m4.String())
|
||||
println(m6.String())
|
||||
println(m4.Eq(m6))
|
||||
|
||||
//Vec2
|
||||
v1 := &gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
v2 := &gglm.Vec2{Data: [2]float32{3, 4}}
|
||||
println(gglm.DistVec2(v1, v2))
|
||||
println(gglm.SqrDistVec2(v2, v1))
|
||||
println(v1.Eq(v2))
|
||||
v2.Set(1, 2)
|
||||
println(v1.Eq(v2))
|
||||
|
||||
println("V1: " + v1.String())
|
||||
v1.Normalize()
|
||||
println("V1 Normal: " + v1.String())
|
||||
|
||||
//Vec3
|
||||
v3 := &gglm.Vec3{Data: [3]float32{1, 2, 3}}
|
||||
v4 := &gglm.Vec3{Data: [3]float32{4, 5, 6}}
|
||||
println(gglm.DistVec3(v3, v4))
|
||||
println(gglm.SqrDistVec3(v4, v3))
|
||||
|
||||
println(v3.Eq(v4))
|
||||
v4.Set(1, 2, 3)
|
||||
println(v3.Eq(v4))
|
||||
|
||||
println(gglm.DotVec3(v3, v4))
|
||||
println(gglm.Cross(v3, v4).String())
|
||||
|
||||
println("V3: " + v3.String())
|
||||
v3.Normalize()
|
||||
println("V3 Normal: " + v3.String())
|
||||
|
||||
//Vec4
|
||||
v5 := &gglm.Vec4{Data: [4]float32{1, 2, 3, 4}}
|
||||
v6 := &gglm.Vec4{Data: [4]float32{5, 6, 7, 8}}
|
||||
println(gglm.DistVec4(v5, v6))
|
||||
println(gglm.SqrDistVec4(v5, v6))
|
||||
|
||||
println(v5.Eq(v6))
|
||||
v6.Set(1, 2, 3, 4)
|
||||
println(v5.Eq(v6))
|
||||
|
||||
println(gglm.DotVec4(v5, v6))
|
||||
|
||||
println("V6: " + v6.String())
|
||||
v6.Normalize()
|
||||
println("V6 Normal: " + v6.String())
|
||||
|
||||
//Mat2Vec2
|
||||
mat2A := gglm.Mat2{
|
||||
Data: [4]float32{
|
||||
1, 2,
|
||||
3, 4,
|
||||
},
|
||||
}
|
||||
|
||||
vec2A := gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
println(gglm.MulMat2Vec2(&mat2A, &vec2A).String())
|
||||
|
||||
//Mat3Vec3
|
||||
mat3A := gglm.Mat3{
|
||||
Data: [9]float32{
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9,
|
||||
},
|
||||
}
|
||||
|
||||
vec3A := gglm.Vec3{Data: [3]float32{1, 2, 3}}
|
||||
mm3v3 := gglm.MulMat3Vec3(&mat3A, &vec3A)
|
||||
println(mm3v3.String())
|
||||
|
||||
//ReflectVec2
|
||||
vec2B := &gglm.Vec2{Data: [2]float32{4, 5}}
|
||||
normA := &gglm.Vec2{Data: [2]float32{0, 1}}
|
||||
rVec2A := gglm.ReflectVec2(vec2B, normA)
|
||||
println(rVec2A.String())
|
||||
|
||||
//Quaternion
|
||||
vRot := &gglm.Vec3{Data: [3]float32{60, 30, 20}}
|
||||
q := gglm.NewQuatEuler(vRot.AsRad())
|
||||
println("\n" + vRot.AsRad().String())
|
||||
println(q.String(), "\n", q.Mag())
|
||||
|
||||
q = gglm.NewQuatAngleAxis(60*gglm.Deg2Rad, vRot.Normalize())
|
||||
println("\n" + vRot.Normalize().String())
|
||||
println(q.String())
|
||||
|
||||
//Transform
|
||||
translationMat := gglm.NewTranslationMat(&gglm.Vec3{Data: [3]float32{1, 2, 3}})
|
||||
rotMat := gglm.NewRotMat(gglm.NewQuatEuler(gglm.NewVec3(60, 30, 20).AsRad()))
|
||||
scaleMat := gglm.NewScaleMat(gglm.NewVec3(1, 1, 1))
|
||||
|
||||
modelMat := gglm.NewTransformMatId()
|
||||
modelMat.Mul(translationMat.Mul(rotMat.Mul(scaleMat)))
|
||||
|
||||
println("\n\n\n", modelMat.String())
|
||||
|
||||
//Clone Vec2
|
||||
v2Orig := gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
v2Clone := v2Orig.Clone()
|
||||
v2Clone.SetX(99)
|
||||
println("\n\n", v2Orig.String(), "; ", v2Clone.String())
|
||||
|
||||
//Clone TrMat
|
||||
trMatOrig := gglm.NewTranslationMat(gglm.NewVec3(1, 2, 3))
|
||||
trMatClone := trMatOrig.Clone()
|
||||
trMatClone.Scale(gglm.NewVec3(2, 2, 2))
|
||||
trMatClone.Translate(gglm.NewVec3(9, 0, 0))
|
||||
println("\n\n", trMatOrig.String(), "; ", trMatClone.String())
|
||||
}
|
||||
|
||||
17
main_test.go
17
main_test.go
@ -7,9 +7,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
dotVec2Result float32 = 0
|
||||
dotVec3Result float32 = 0
|
||||
crossResult *gglm.Vec3
|
||||
dotVec2Result float32
|
||||
dotVec3Result float32
|
||||
crossResult *gglm.Vec3
|
||||
mulMat4Vec4Res *gglm.Vec4
|
||||
)
|
||||
|
||||
func BenchmarkDotVec2(b *testing.B) {
|
||||
@ -71,3 +72,13 @@ func BenchmarkMulMat4(b *testing.B) {
|
||||
m1.Mul(m2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat4Vec4(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat4Id()
|
||||
v1 := gglm.Vec4{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
mulMat4Vec4Res = gglm.MulMat4Vec4(m1, &v1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user