mirror of
https://github.com/bloeys/gglm.git
synced 2025-12-29 13:38:20 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e45e4d3304 | |||
| f3db256007 | |||
| d7f5cbb136 | |||
| 2648dc910c | |||
| 386fa0b641 | |||
| 7d8dce922f | |||
| f4f06c54b3 | |||
| 80d1c12e2d | |||
| 8bb31393b4 | |||
| e4edb7dcec | |||
| d832e19dab | |||
| b39e8e0b80 | |||
| 585d17aa29 | |||
| d4c7755ca8 | |||
| 2071b351d5 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
.vscode
|
||||
*~
|
||||
48
README.md
48
README.md
@ -1,8 +1,52 @@
|
||||
# gglm
|
||||
|
||||
Fast Go OpenGL Mathematics library inspired by the c++ library [glm](https://github.com/g-truc/glm).
|
||||
Fast OpenGL/Graphics focused Mathematics library in Go inspired by the c++ library [glm](https://github.com/g-truc/glm).
|
||||
|
||||
gglm currently has the following:
|
||||
|
||||
- `Vec2`, `Vec3` and `Vec4` structs that implement vector (x,y,z,w) operations
|
||||
- `Mat2`, `Mat3`, `Mat4` structs that implement square matrix operations
|
||||
- `Quat` struct that implements quaternion operations
|
||||
- `TrMat` struct that implements 3D transformation matrix operations
|
||||
- Many useful geometric functions (e.g. dot product, cross product, vector reflection etc)
|
||||
- 32-bit scalar operations (e.g. sin32, cos32, equality using epsilon, sqrt32 etc)
|
||||
- Useful 32-bit constants (e.g. pi, Deg2Rad, Rad2Deg, float32 epsilon etc)
|
||||
- Simple 'siwzzle' interfaces that allow you to do things like `.X()` or `.R()` etc.
|
||||
- Very easy to use with graphics/native APIs as everything is implemented using arrays
|
||||
- `.String()` functions on all types for pretty pritning
|
||||
|
||||
## Installation
|
||||
|
||||
`go get github.com/bloeys/gglm`
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
|
||||
import "github.com/bloeys/gglm/gglm"
|
||||
|
||||
|
||||
func main() {
|
||||
|
||||
//LookAt
|
||||
camPos := gglm.NewVec3(0, 0, 3)
|
||||
worldUp := gglm.NewVec3(0, 1, 0)
|
||||
targetPos := gglm.NewVec3(0, 0, 0)
|
||||
viewMat := gglm.LookAt(camPos, targetPos, worldUp)
|
||||
println(viewMat.String())
|
||||
|
||||
//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))
|
||||
}
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
package gglm
|
||||
|
||||
const (
|
||||
Pi float32 = 3.14159265359
|
||||
Deg2Rad float32 = Pi / 180
|
||||
Rad2Deg float32 = 180 / Pi
|
||||
Pi float32 = 3.14159265359
|
||||
Deg2Rad float32 = Pi / 180
|
||||
Rad2Deg float32 = 180 / Pi
|
||||
F32Epsilon float32 = 1e-6
|
||||
|
||||
//CosHalf is Cos32(0.5)
|
||||
CosHalf float32 = 0.87758256189
|
||||
)
|
||||
|
||||
@ -6,6 +6,13 @@ import (
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
var (
|
||||
dotVec2Result, distVec2Result float32
|
||||
dotVec3Result, distVec3Result float32
|
||||
reflectVec2Result *gglm.Vec2
|
||||
crossResult, reflectVec3Result *gglm.Vec3
|
||||
)
|
||||
|
||||
func TestDotVec2(t *testing.T) {
|
||||
|
||||
v1 := gglm.Vec2{Data: [2]float32{1, 2}}
|
||||
@ -137,3 +144,73 @@ func TestReflectVec3(t *testing.T) {
|
||||
t.Errorf("Got: %v; Expected: %v", res, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDotVec2(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec2{}
|
||||
v2 := &gglm.Vec2{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
dotVec2Result = gglm.DotVec2(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDotVec3(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec3{}
|
||||
v2 := &gglm.Vec3{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
dotVec3Result = gglm.DotVec3(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCross(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec3{}
|
||||
v2 := &gglm.Vec3{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
crossResult = gglm.Cross(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDistVec2(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec2{}
|
||||
v2 := &gglm.Vec2{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
distVec2Result = gglm.DistVec2(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDistVec3(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec3{}
|
||||
v2 := &gglm.Vec3{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
distVec3Result = gglm.DistVec3(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReflectVec2(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec2{}
|
||||
v2 := &gglm.Vec2{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
reflectVec2Result = gglm.ReflectVec2(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReflectVec3(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec3{}
|
||||
v2 := &gglm.Vec3{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
reflectVec3Result = gglm.ReflectVec3(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,10 @@ func (m *Mat2) String() string {
|
||||
return fmt.Sprintf("\n| %+-9.3f %+-9.3f |\n| %+-9.3f %+-9.3f |\n", m.Data[0][0], m.Data[0][1], m.Data[1][0], m.Data[1][1])
|
||||
}
|
||||
|
||||
func (m *Mat2) Col(c int) *Vec2 {
|
||||
return &Vec2{Data: m.Data[c]}
|
||||
}
|
||||
|
||||
//Add m += m2
|
||||
func (m *Mat2) Add(m2 *Mat2) *Mat2 {
|
||||
m.Data[0][0] += m2.Data[0][0]
|
||||
|
||||
@ -146,3 +146,13 @@ func TestMulMat2Vec2(t *testing.T) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat2(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat2Id()
|
||||
m2 := gglm.NewMat2Id()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
m1.Mul(m2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,10 @@ func (m *Mat3) String() string {
|
||||
)
|
||||
}
|
||||
|
||||
func (m *Mat3) Col(c int) *Vec3 {
|
||||
return &Vec3{Data: m.Data[c]}
|
||||
}
|
||||
|
||||
//Add m += m2
|
||||
func (m *Mat3) Add(m2 *Mat3) *Mat3 {
|
||||
|
||||
|
||||
@ -161,3 +161,13 @@ func TestMulMat3Vec3(t *testing.T) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat3(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat3Id()
|
||||
m2 := gglm.NewMat3Id()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
m1.Mul(m2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,10 @@ func (m *Mat4) String() string {
|
||||
)
|
||||
}
|
||||
|
||||
func (m *Mat4) Col(c int) *Vec4 {
|
||||
return &Vec4{Data: m.Data[c]}
|
||||
}
|
||||
|
||||
//Add m += m2
|
||||
func (m *Mat4) Add(m2 *Mat4) *Mat4 {
|
||||
|
||||
|
||||
@ -6,6 +6,10 @@ import (
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
var (
|
||||
mulMat4Vec4Res *gglm.Vec4
|
||||
)
|
||||
|
||||
func TestMat4GetSet(t *testing.T) {
|
||||
|
||||
m1 := gglm.Mat4{}
|
||||
@ -177,3 +181,23 @@ func TestMulMat4Vec4(t *testing.T) {
|
||||
t.Errorf("Got: %v; Expected: %v", result.String(), correctAns.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat4(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat4Id()
|
||||
m2 := gglm.NewMat4Id()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
60
gglm/quat.go
60
gglm/quat.go
@ -16,6 +16,37 @@ func (q *Quat) Eq(q2 *Quat) bool {
|
||||
return q.Data == q2.Data
|
||||
}
|
||||
|
||||
//Angle returns the angle represented by this quaternion in radians
|
||||
func (q *Quat) Angle() float32 {
|
||||
|
||||
if Abs32(q.Data[3]) > CosHalf {
|
||||
|
||||
a := Asin32(Sqrt32(q.Data[0]*q.Data[0]+q.Data[1]*q.Data[1]+q.Data[2]*q.Data[2])) * 2
|
||||
if q.Data[3] < 0 {
|
||||
return Pi*2 - a
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
return Acos32(q.Data[3]) * 2
|
||||
}
|
||||
|
||||
//Axis returns the rotation axis represented by this quaternion
|
||||
func (q *Quat) Axis() *Vec3 {
|
||||
|
||||
var t float32 = 1 - q.Data[3]*q.Data[3]
|
||||
if t <= 0 {
|
||||
return &Vec3{Data: [3]float32{0, 0, 1}}
|
||||
}
|
||||
|
||||
t = 1 / Sqrt32(t)
|
||||
return &Vec3{Data: [3]float32{
|
||||
q.Data[0] * t,
|
||||
q.Data[1] * t,
|
||||
q.Data[2] * t,
|
||||
}}
|
||||
}
|
||||
|
||||
//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 {
|
||||
@ -43,7 +74,34 @@ func NewQuatEuler(v *Vec3) *Quat {
|
||||
}
|
||||
}
|
||||
|
||||
//AngleAxis rotates rotRad radians around the *normalized* vector rotAxisNorm
|
||||
//Euler takes rotations in radians and produces a rotation that
|
||||
//rotates around the z-axis, y-axis and lastly x-axis.
|
||||
func NewQuatEulerXYZ(x, y, z float32) *Quat {
|
||||
|
||||
//Some other common terminology: x=roll, y=pitch, z=yaw
|
||||
sinX, cosX := Sincos32(x * 0.5)
|
||||
sinY, cosY := Sincos32(y * 0.5)
|
||||
sinZ, cosZ := Sincos32(z * 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//NewQuatAngleAxis produces a quaternion thats rotates rotRad radians around the *normalized* vector rotAxisNorm
|
||||
func NewQuatAngleAxis(rotRad float32, rotAxisNorm *Vec3) *Quat {
|
||||
|
||||
s, c := Sincos32(rotRad * 0.5)
|
||||
|
||||
@ -14,6 +14,12 @@ func TestNewQuatEuler(t *testing.T) {
|
||||
if !gglm.EqF32(q.X(), ans.X()) || !gglm.EqF32(q.Y(), ans.Y()) || !gglm.EqF32(q.Z(), ans.Z()) || !gglm.EqF32(q.W(), ans.W()) {
|
||||
t.Errorf("Got: %v; Expected: %v", q.String(), ans.String())
|
||||
}
|
||||
|
||||
q = gglm.NewQuatEulerXYZ(180*gglm.Deg2Rad, 180*gglm.Deg2Rad, 180*gglm.Deg2Rad)
|
||||
|
||||
if !gglm.EqF32(q.X(), ans.X()) || !gglm.EqF32(q.Y(), ans.Y()) || !gglm.EqF32(q.Z(), ans.Z()) || !gglm.EqF32(q.W(), ans.W()) {
|
||||
t.Errorf("Got: %v; Expected: %v", q.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewQuatAngleAxis(t *testing.T) {
|
||||
@ -25,3 +31,51 @@ func TestNewQuatAngleAxis(t *testing.T) {
|
||||
t.Errorf("Got: %v; Expected: %v", q.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuatAngle(t *testing.T) {
|
||||
|
||||
a := gglm.NewQuatAngleAxis(180*gglm.Deg2Rad, gglm.NewVec3(0, 1, 0)).Angle()
|
||||
var ans float32 = 180.0 * gglm.Deg2Rad
|
||||
|
||||
if !gglm.EqF32(a, ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", a, ans)
|
||||
}
|
||||
|
||||
a = gglm.NewQuatAngleAxis(90*gglm.Deg2Rad, gglm.NewVec3(1, 1, 0).Normalize()).Angle()
|
||||
ans = 90 * gglm.Deg2Rad
|
||||
|
||||
if !gglm.EqF32(a, ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", a, ans)
|
||||
}
|
||||
|
||||
a = gglm.NewQuatAngleAxis(125*gglm.Deg2Rad, gglm.NewVec3(1, 1, 0).Normalize()).Angle()
|
||||
ans = 125 * gglm.Deg2Rad
|
||||
|
||||
if !gglm.EqF32(a, ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", a, ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuatAxis(t *testing.T) {
|
||||
|
||||
a := gglm.NewQuatAngleAxis(1, gglm.NewVec3(0, 1, 0)).Axis()
|
||||
ans := gglm.NewVec3(0, 1, 0)
|
||||
|
||||
if !gglm.EqF32(a.X(), ans.X()) || !gglm.EqF32(a.Y(), ans.Y()) || !gglm.EqF32(a.Z(), ans.Z()) {
|
||||
t.Errorf("Got: %v; Expected: %v", a.String(), ans.String())
|
||||
}
|
||||
|
||||
a = gglm.NewQuatAngleAxis(1, gglm.NewVec3(1, 1, 0).Normalize()).Axis()
|
||||
ans = gglm.NewVec3(1, 1, 0).Normalize()
|
||||
|
||||
if !gglm.EqF32(a.X(), ans.X()) || !gglm.EqF32(a.Y(), ans.Y()) || !gglm.EqF32(a.Z(), ans.Z()) {
|
||||
t.Errorf("Got: %v; Expected: %v", a.String(), ans.String())
|
||||
}
|
||||
|
||||
a = gglm.NewQuatAngleAxis(1, gglm.NewVec3(67, 46, 32).Normalize()).Axis()
|
||||
ans = gglm.NewVec3(67, 46, 32).Normalize()
|
||||
|
||||
if !gglm.EqF32(a.X(), ans.X()) || !gglm.EqF32(a.Y(), ans.Y()) || !gglm.EqF32(a.Z(), ans.Z()) {
|
||||
t.Errorf("Got: %v; Expected: %v", a.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,9 +2,6 @@ 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)
|
||||
@ -31,7 +28,27 @@ func Acos32(x float32) float32 {
|
||||
return float32(math.Acos(float64(x)))
|
||||
}
|
||||
|
||||
func Tan32(x float32) float32 {
|
||||
return float32(math.Tan(float64(x)))
|
||||
}
|
||||
|
||||
func Atan32(x float32) float32 {
|
||||
return float32(math.Atan(float64(x)))
|
||||
}
|
||||
|
||||
func Atan232(x, y float32) float32 {
|
||||
return float32(math.Atan2(float64(y), float64(x)))
|
||||
}
|
||||
|
||||
func Sincos32(x float32) (sinx, cosx float32) {
|
||||
a, b := math.Sincos(float64(x))
|
||||
return float32(a), float32(b)
|
||||
}
|
||||
|
||||
func Abs32(x float32) float32 {
|
||||
return float32(math.Abs(float64(x)))
|
||||
}
|
||||
|
||||
func Sqrt32(x float32) float32 {
|
||||
return float32(math.Sqrt(float64(x)))
|
||||
}
|
||||
|
||||
@ -6,6 +6,9 @@ type Swizzle1 interface {
|
||||
|
||||
SetX(float32)
|
||||
SetR(float32)
|
||||
|
||||
AddX(float32)
|
||||
AddR(float32)
|
||||
}
|
||||
|
||||
type Swizzle2 interface {
|
||||
@ -15,6 +18,12 @@ type Swizzle2 interface {
|
||||
|
||||
SetY(float32)
|
||||
SetG(float32)
|
||||
|
||||
AddY(float32)
|
||||
AddG(float32)
|
||||
|
||||
AddXY(float32, float32)
|
||||
AddRG(float32, float32)
|
||||
}
|
||||
|
||||
type Swizzle3 interface {
|
||||
@ -24,6 +33,12 @@ type Swizzle3 interface {
|
||||
|
||||
SetZ(float32)
|
||||
SetB(float32)
|
||||
|
||||
AddZ(float32)
|
||||
AddB(float32)
|
||||
|
||||
AddXYZ(float32, float32, float32)
|
||||
AddRGB(float32, float32, float32)
|
||||
}
|
||||
|
||||
type Swizzle4 interface {
|
||||
@ -33,4 +48,10 @@ type Swizzle4 interface {
|
||||
|
||||
SetW(float32)
|
||||
SetA(float32)
|
||||
|
||||
AddW(float32)
|
||||
AddA(float32)
|
||||
|
||||
AddXYZW(float32, float32, float32, float32)
|
||||
AddRGBA(float32, float32, float32, float32)
|
||||
}
|
||||
|
||||
@ -13,18 +13,64 @@ type TrMat struct {
|
||||
Mat4
|
||||
}
|
||||
|
||||
//Translate adds the vector to the translation components of the transformation matrix
|
||||
func (t *TrMat) Translate(v *Vec3) {
|
||||
//Translate adds v to the translation components of the transformation matrix
|
||||
func (t *TrMat) Translate(v *Vec3) *TrMat {
|
||||
t.Data[3][0] += v.Data[0]
|
||||
t.Data[3][1] += v.Data[1]
|
||||
t.Data[3][2] += v.Data[2]
|
||||
return t
|
||||
}
|
||||
|
||||
//Scale multiplies the vector by the scale components of the transformation matrix
|
||||
func (t *TrMat) Scale(v *Vec3) {
|
||||
//Scale multiplies the scale components of the transformation matrix by v
|
||||
func (t *TrMat) Scale(v *Vec3) *TrMat {
|
||||
t.Data[0][0] *= v.Data[0]
|
||||
t.Data[1][1] *= v.Data[1]
|
||||
t.Data[2][2] *= v.Data[2]
|
||||
return t
|
||||
}
|
||||
|
||||
//Rotate takes a *normalized* axis and angles in radians to rotate around the given axis
|
||||
func (t *TrMat) Rotate(rads float32, axis *Vec3) *TrMat {
|
||||
|
||||
s := Sin32(rads)
|
||||
c := Cos32(rads)
|
||||
|
||||
axis = axis.Normalize()
|
||||
temp := axis.Clone().Scale(1 - c)
|
||||
|
||||
rotate := TrMat{}
|
||||
rotate.Data[0][0] = c + temp.Data[0]*axis.Data[0]
|
||||
rotate.Data[0][1] = temp.Data[0]*axis.Data[1] + s*axis.Data[2]
|
||||
rotate.Data[0][2] = temp.Data[0]*axis.Data[2] - s*axis.Data[1]
|
||||
|
||||
rotate.Data[1][0] = temp.Data[1]*axis.Data[0] - s*axis.Data[2]
|
||||
rotate.Data[1][1] = c + temp.Data[1]*axis.Data[1]
|
||||
rotate.Data[1][2] = temp.Data[1]*axis.Data[2] + s*axis.Data[0]
|
||||
|
||||
rotate.Data[2][0] = temp.Data[2]*axis.Data[0] + s*axis.Data[1]
|
||||
rotate.Data[2][1] = temp.Data[2]*axis.Data[1] - s*axis.Data[0]
|
||||
rotate.Data[2][2] = c + temp.Data[2]*axis.Data[2]
|
||||
|
||||
result := &Mat4{}
|
||||
result.Data[0] = t.Col(0).Scale(rotate.Data[0][0]).
|
||||
Add(t.Col(1).Scale(rotate.Data[0][1])).
|
||||
Add(t.Col(2).Scale(rotate.Data[0][2])).
|
||||
Data
|
||||
|
||||
result.Data[1] = t.Col(0).Scale(rotate.Data[1][0]).
|
||||
Add(t.Col(1).Scale(rotate.Data[1][1])).
|
||||
Add(t.Col(2).Scale(rotate.Data[1][2])).
|
||||
Data
|
||||
|
||||
result.Data[2] = t.Col(0).Scale(rotate.Data[2][0]).
|
||||
Add(t.Col(1).Scale(rotate.Data[2][1])).
|
||||
Add(t.Col(2).Scale(rotate.Data[2][2])).
|
||||
Data
|
||||
|
||||
t.Data[0] = result.Data[0]
|
||||
t.Data[1] = result.Data[1]
|
||||
t.Data[2] = result.Data[2]
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TrMat) Mul(m *TrMat) *TrMat {
|
||||
|
||||
42
gglm/vec2.go
42
gglm/vec2.go
@ -30,20 +30,46 @@ func (v *Vec2) G() float32 {
|
||||
return v.Data[1]
|
||||
}
|
||||
|
||||
func (v *Vec2) SetX(f float32) {
|
||||
v.Data[0] = f
|
||||
func (v *Vec2) SetX(x float32) {
|
||||
v.Data[0] = x
|
||||
}
|
||||
|
||||
func (v *Vec2) SetR(f float32) {
|
||||
v.Data[0] = f
|
||||
func (v *Vec2) SetR(r float32) {
|
||||
v.Data[0] = r
|
||||
}
|
||||
|
||||
func (v *Vec2) SetY(f float32) {
|
||||
v.Data[1] = f
|
||||
func (v *Vec2) SetY(y float32) {
|
||||
v.Data[1] = y
|
||||
}
|
||||
|
||||
func (v *Vec2) SetG(f float32) {
|
||||
v.Data[1] = f
|
||||
func (v *Vec2) SetG(g float32) {
|
||||
v.Data[1] = g
|
||||
}
|
||||
|
||||
func (v *Vec2) AddX(x float32) {
|
||||
v.Data[0] += x
|
||||
}
|
||||
|
||||
func (v *Vec2) AddY(y float32) {
|
||||
v.Data[1] += y
|
||||
}
|
||||
|
||||
func (v *Vec2) AddR(r float32) {
|
||||
v.Data[0] += r
|
||||
}
|
||||
|
||||
func (v *Vec2) AddG(g float32) {
|
||||
v.Data[1] += g
|
||||
}
|
||||
|
||||
func (v *Vec2) AddXY(x, y float32) {
|
||||
v.Data[0] += x
|
||||
v.Data[1] += y
|
||||
}
|
||||
|
||||
func (v *Vec2) AddRG(r, g float32) {
|
||||
v.Data[0] += r
|
||||
v.Data[1] += g
|
||||
}
|
||||
|
||||
func (v *Vec2) String() string {
|
||||
|
||||
46
gglm/vec3.go
46
gglm/vec3.go
@ -60,6 +60,52 @@ func (v *Vec3) SetB(f float32) {
|
||||
v.Data[2] = f
|
||||
}
|
||||
|
||||
func (v *Vec3) AddX(x float32) {
|
||||
v.Data[0] += x
|
||||
}
|
||||
|
||||
func (v *Vec3) AddY(y float32) {
|
||||
v.Data[1] += y
|
||||
}
|
||||
|
||||
func (v *Vec3) AddZ(z float32) {
|
||||
v.Data[2] += z
|
||||
}
|
||||
|
||||
func (v *Vec3) AddR(r float32) {
|
||||
v.Data[0] += r
|
||||
}
|
||||
|
||||
func (v *Vec3) AddG(g float32) {
|
||||
v.Data[1] += g
|
||||
}
|
||||
|
||||
func (v *Vec3) AddB(b float32) {
|
||||
v.Data[2] += b
|
||||
}
|
||||
|
||||
func (v *Vec3) AddXY(x, y float32) {
|
||||
v.Data[0] += x
|
||||
v.Data[1] += y
|
||||
}
|
||||
|
||||
func (v *Vec3) AddRG(r, g float32) {
|
||||
v.Data[0] += r
|
||||
v.Data[1] += g
|
||||
}
|
||||
|
||||
func (v *Vec3) AddXYZ(x, y, z float32) {
|
||||
v.Data[0] += x
|
||||
v.Data[1] += y
|
||||
v.Data[2] += z
|
||||
}
|
||||
|
||||
func (v *Vec3) AddRGB(r, g, b float32) {
|
||||
v.Data[0] += r
|
||||
v.Data[1] += g
|
||||
v.Data[2] += b
|
||||
}
|
||||
|
||||
func (v *Vec3) String() string {
|
||||
return fmt.Sprintf("(%f, %f, %f)", v.X(), v.Y(), v.Z())
|
||||
}
|
||||
|
||||
68
gglm/vec4.go
68
gglm/vec4.go
@ -76,6 +76,74 @@ func (v *Vec4) SetA(f float32) {
|
||||
v.Data[3] = f
|
||||
}
|
||||
|
||||
func (v *Vec4) AddX(x float32) {
|
||||
v.Data[0] += x
|
||||
}
|
||||
|
||||
func (v *Vec4) AddY(y float32) {
|
||||
v.Data[1] += y
|
||||
}
|
||||
|
||||
func (v *Vec4) AddZ(z float32) {
|
||||
v.Data[2] += z
|
||||
}
|
||||
|
||||
func (v *Vec4) AddW(w float32) {
|
||||
v.Data[3] += w
|
||||
}
|
||||
|
||||
func (v *Vec4) AddR(r float32) {
|
||||
v.Data[0] += r
|
||||
}
|
||||
|
||||
func (v *Vec4) AddG(g float32) {
|
||||
v.Data[1] += g
|
||||
}
|
||||
|
||||
func (v *Vec4) AddB(b float32) {
|
||||
v.Data[2] += b
|
||||
}
|
||||
|
||||
func (v *Vec4) AddA(a float32) {
|
||||
v.Data[3] += a
|
||||
}
|
||||
|
||||
func (v *Vec4) AddXY(x, y float32) {
|
||||
v.Data[0] += x
|
||||
v.Data[1] += y
|
||||
}
|
||||
|
||||
func (v *Vec4) AddRG(r, g float32) {
|
||||
v.Data[0] += r
|
||||
v.Data[1] += g
|
||||
}
|
||||
|
||||
func (v *Vec4) AddXYZ(x, y, z float32) {
|
||||
v.Data[0] += x
|
||||
v.Data[1] += y
|
||||
v.Data[2] += z
|
||||
}
|
||||
|
||||
func (v *Vec4) AddRGB(r, g, b float32) {
|
||||
v.Data[0] += r
|
||||
v.Data[1] += g
|
||||
v.Data[2] += b
|
||||
}
|
||||
|
||||
func (v *Vec4) AddXYZW(x, y, z, w float32) {
|
||||
v.Data[0] += x
|
||||
v.Data[1] += y
|
||||
v.Data[2] += z
|
||||
v.Data[3] += w
|
||||
}
|
||||
|
||||
func (v *Vec4) AddRGBA(r, g, b, a float32) {
|
||||
v.Data[0] += r
|
||||
v.Data[1] += g
|
||||
v.Data[2] += b
|
||||
v.Data[3] += a
|
||||
}
|
||||
|
||||
func (v *Vec4) String() string {
|
||||
return fmt.Sprintf("(%f, %f, %f, %f)", v.X(), v.Y(), v.Z(), v.W())
|
||||
}
|
||||
|
||||
302
gglm/vec_test.go
Executable file
302
gglm/vec_test.go
Executable file
@ -0,0 +1,302 @@
|
||||
package gglm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
func TestVecSwizzleGet(t *testing.T) {
|
||||
|
||||
//Vec2
|
||||
v2 := gglm.NewVec2(1, 2)
|
||||
var ans2X float32 = 1
|
||||
var ans2Y float32 = 2
|
||||
|
||||
if v2.X() != ans2X {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.X(), ans2X)
|
||||
}
|
||||
|
||||
if v2.Y() != ans2Y {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.Y(), ans2Y)
|
||||
}
|
||||
|
||||
if v2.R() != ans2X {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.R(), ans2X)
|
||||
}
|
||||
|
||||
if v2.G() != ans2Y {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.G(), ans2Y)
|
||||
}
|
||||
|
||||
//Vec3
|
||||
v3 := gglm.NewVec3(1, 2, 3)
|
||||
var ans3X float32 = 1
|
||||
var ans3Y float32 = 2
|
||||
var ans3Z float32 = 3
|
||||
|
||||
if v3.X() != ans3X {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.X(), ans3X)
|
||||
}
|
||||
|
||||
if v3.Y() != ans3Y {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.Y(), ans3Y)
|
||||
}
|
||||
|
||||
if v3.Z() != ans3Z {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.Z(), ans3Z)
|
||||
}
|
||||
|
||||
if v3.R() != ans3X {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.R(), ans3X)
|
||||
}
|
||||
|
||||
if v3.G() != ans3Y {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.G(), ans3Y)
|
||||
}
|
||||
|
||||
if v3.B() != ans3Z {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.B(), ans3Z)
|
||||
}
|
||||
|
||||
//Vec4
|
||||
v4 := gglm.NewVec4(1, 2, 3, 4)
|
||||
var ans4X float32 = 1
|
||||
var ans4Y float32 = 2
|
||||
var ans4Z float32 = 3
|
||||
var ans4W float32 = 4
|
||||
|
||||
if v4.X() != ans4X {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.X(), ans4X)
|
||||
}
|
||||
|
||||
if v4.Y() != ans4Y {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.Y(), ans4Y)
|
||||
}
|
||||
|
||||
if v4.Z() != ans4Z {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.Z(), ans4Z)
|
||||
}
|
||||
|
||||
if v4.W() != ans4W {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.W(), ans4W)
|
||||
}
|
||||
|
||||
if v4.R() != ans4X {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.R(), ans4X)
|
||||
}
|
||||
|
||||
if v4.G() != ans4Y {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.G(), ans4Y)
|
||||
}
|
||||
|
||||
if v4.B() != ans4Z {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.B(), ans4Z)
|
||||
}
|
||||
|
||||
if v4.A() != ans4W {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.A(), ans4W)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVecSwizzleSet(t *testing.T) {
|
||||
|
||||
//Vec2
|
||||
v2 := gglm.NewVec2(0, 0)
|
||||
ans2 := gglm.NewVec2(1, 2)
|
||||
|
||||
v2.SetX(1)
|
||||
v2.SetY(2)
|
||||
|
||||
if !v2.Eq(ans2) {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
|
||||
}
|
||||
|
||||
ans2 = gglm.NewVec2(11, 22)
|
||||
v2.SetR(11)
|
||||
v2.SetG(22)
|
||||
|
||||
if !v2.Eq(ans2) {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
|
||||
}
|
||||
|
||||
//Vec3
|
||||
v3 := gglm.NewVec3(0, 0, 0)
|
||||
ans3 := gglm.NewVec3(1, 2, 3)
|
||||
|
||||
v3.SetX(1)
|
||||
v3.SetY(2)
|
||||
v3.SetZ(3)
|
||||
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
ans3 = gglm.NewVec3(11, 22, 33)
|
||||
|
||||
v3.SetR(11)
|
||||
v3.SetG(22)
|
||||
v3.SetB(33)
|
||||
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
//Vec4
|
||||
v4 := gglm.NewVec4(0, 0, 0, 0)
|
||||
ans4 := gglm.NewVec4(1, 2, 3, 4)
|
||||
|
||||
v4.SetX(1)
|
||||
v4.SetY(2)
|
||||
v4.SetZ(3)
|
||||
v4.SetW(4)
|
||||
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
ans4 = gglm.NewVec4(11, 22, 33, 44)
|
||||
|
||||
v4.SetR(11)
|
||||
v4.SetG(22)
|
||||
v4.SetB(33)
|
||||
v4.SetA(44)
|
||||
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestVecSwizzleAdd(t *testing.T) {
|
||||
|
||||
//Vec2
|
||||
v2 := gglm.NewVec2(1, 1)
|
||||
ans2 := gglm.NewVec2(2, 3)
|
||||
v2.AddX(1)
|
||||
v2.AddY(2)
|
||||
if !v2.Eq(ans2) {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
|
||||
}
|
||||
|
||||
v2 = gglm.NewVec2(1, 1)
|
||||
v2.AddR(1)
|
||||
v2.AddG(2)
|
||||
if !v2.Eq(ans2) {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
|
||||
}
|
||||
|
||||
v2 = gglm.NewVec2(1, 1)
|
||||
v2.AddXY(1, 2)
|
||||
if !v2.Eq(ans2) {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
|
||||
}
|
||||
|
||||
v2 = gglm.NewVec2(1, 1)
|
||||
v2.AddRG(1, 2)
|
||||
if !v2.Eq(ans2) {
|
||||
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
|
||||
}
|
||||
|
||||
//Vec3
|
||||
v3 := gglm.NewVec3(1, 1, 1)
|
||||
ans3 := gglm.NewVec3(2, 3, 4)
|
||||
v3.AddX(1)
|
||||
v3.AddY(2)
|
||||
v3.AddZ(3)
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
v3 = gglm.NewVec3(1, 1, 1)
|
||||
v3.AddR(1)
|
||||
v3.AddG(2)
|
||||
v3.AddB(3)
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
v3 = gglm.NewVec3(1, 1, 1)
|
||||
ans3 = gglm.NewVec3(2, 3, 1)
|
||||
v3.AddXY(1, 2)
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
v3 = gglm.NewVec3(1, 1, 1)
|
||||
v3.AddRG(1, 2)
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
v3 = gglm.NewVec3(1, 1, 1)
|
||||
ans3 = gglm.NewVec3(2, 3, 4)
|
||||
v3.AddXYZ(1, 2, 3)
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
v3 = gglm.NewVec3(1, 1, 1)
|
||||
v3.AddRGB(1, 2, 3)
|
||||
if !v3.Eq(ans3) {
|
||||
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
|
||||
}
|
||||
|
||||
//Vec4
|
||||
v4 := gglm.NewVec4(1, 1, 1, 1)
|
||||
ans4 := gglm.NewVec4(2, 3, 4, 5)
|
||||
v4.AddX(1)
|
||||
v4.AddY(2)
|
||||
v4.AddZ(3)
|
||||
v4.AddW(4)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
v4 = gglm.NewVec4(1, 1, 1, 1)
|
||||
v4.AddR(1)
|
||||
v4.AddG(2)
|
||||
v4.AddB(3)
|
||||
v4.AddA(4)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
v4 = gglm.NewVec4(1, 1, 1, 1)
|
||||
ans4 = gglm.NewVec4(2, 3, 1, 1)
|
||||
v4.AddXY(1, 2)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
v4 = gglm.NewVec4(1, 1, 1, 1)
|
||||
v4.AddRG(1, 2)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
v4 = gglm.NewVec4(1, 1, 1, 1)
|
||||
ans4 = gglm.NewVec4(2, 3, 4, 1)
|
||||
v4.AddXYZ(1, 2, 3)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
v4 = gglm.NewVec4(1, 1, 1, 1)
|
||||
v4.AddRGB(1, 2, 3)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
v4 = gglm.NewVec4(1, 1, 1, 1)
|
||||
ans4 = gglm.NewVec4(2, 3, 4, 5)
|
||||
v4.AddXYZW(1, 2, 3, 4)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
|
||||
v4 = gglm.NewVec4(1, 1, 1, 1)
|
||||
v4.AddRGBA(1, 2, 3, 4)
|
||||
if !v4.Eq(ans4) {
|
||||
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
|
||||
}
|
||||
}
|
||||
84
main_test.go
84
main_test.go
@ -1,84 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
)
|
||||
|
||||
var (
|
||||
dotVec2Result float32
|
||||
dotVec3Result float32
|
||||
crossResult *gglm.Vec3
|
||||
mulMat4Vec4Res *gglm.Vec4
|
||||
)
|
||||
|
||||
func BenchmarkDotVec2(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec2{}
|
||||
v2 := &gglm.Vec2{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
dotVec2Result = gglm.DotVec2(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDotVec3(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec3{}
|
||||
v2 := &gglm.Vec3{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
dotVec3Result = gglm.DotVec3(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCross(b *testing.B) {
|
||||
|
||||
v1 := &gglm.Vec3{}
|
||||
v2 := &gglm.Vec3{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
crossResult = gglm.Cross(v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat2(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat2Id()
|
||||
m2 := gglm.NewMat2Id()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
m1.Mul(m2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat3(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat3Id()
|
||||
m2 := gglm.NewMat3Id()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
m1.Mul(m2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat4(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat4Id()
|
||||
m2 := gglm.NewMat4Id()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
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