diff --git a/gglm/geometric.go b/gglm/geometric.go index 35f586e..d91d065 100755 --- a/gglm/geometric.go +++ b/gglm/geometric.go @@ -14,6 +14,10 @@ func DotVec4(v1, v2 *Vec4) float32 { return v1.X()*v2.X() + v1.Y()*v2.Y() + v1.Z()*v2.Z() + v1.W()*v2.W() } +func DotQuat(q1, q2 *Quat) float32 { + return q1.X()*q2.X() + q1.Y()*q2.Y() + q1.Z()*q2.Z() + q1.W()*q2.W() +} + func Cross(v1, v2 *Vec3) *Vec3 { return &Vec3{ Data: [3]float32{ @@ -106,3 +110,8 @@ func ReflectVec3(v, n *Vec3) *Vec3 { }, } } + +//AngleQuat returns the angle between the two quaternions in radians +func AngleQuat(q1, q2 *Quat) float32 { + return Acos32(DotQuat(q1, q2)) +} diff --git a/gglm/quat.go b/gglm/quat.go index 3ce4ea3..f1c1b30 100755 --- a/gglm/quat.go +++ b/gglm/quat.go @@ -11,6 +11,11 @@ type Quat struct { Vec4 } +//Eq checks for exact equality +func (q *Quat) Eq(q2 *Quat) bool { + return q.Data == q2.Data +} + //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 { diff --git a/gglm/quat_test.go b/gglm/quat_test.go new file mode 100755 index 0000000..a08ee51 --- /dev/null +++ b/gglm/quat_test.go @@ -0,0 +1,27 @@ +package gglm_test + +import ( + "testing" + + "github.com/bloeys/gglm/gglm" +) + +func TestNewQuatEuler(t *testing.T) { + + q := gglm.NewQuatEuler(gglm.NewVec3(180, 180, 180).AsRad()) + ans := &gglm.Quat{Vec4: *gglm.NewVec4(0, 0, 0, 1)} + + 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) { + + q := gglm.NewQuatAngleAxis(180*gglm.Deg2Rad, gglm.NewVec3(0, 1, 0)) + ans := &gglm.Quat{Vec4: *gglm.NewVec4(0, 1, 0, 0)} + + 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()) + } +} diff --git a/gglm/scalar.go b/gglm/scalar.go index 0a7bb25..4fb79ec 100755 --- a/gglm/scalar.go +++ b/gglm/scalar.go @@ -19,10 +19,18 @@ func Sin32(x float32) float32 { return float32(math.Sin(float64(x))) } +func Asin32(x float32) float32 { + return float32(math.Asin(float64(x))) +} + func Cos32(x float32) float32 { return float32(math.Cos(float64(x))) } +func Acos32(x float32) float32 { + return float32(math.Acos(float64(x))) +} + func Sincos32(x float32) (sinx, cosx float32) { a, b := math.Sincos(float64(x)) return float32(a), float32(b) diff --git a/gglm/transform.go b/gglm/transform.go index e776295..2045340 100755 --- a/gglm/transform.go +++ b/gglm/transform.go @@ -29,6 +29,10 @@ func (t *TrMat) Mul(m *TrMat) *TrMat { return t } +func (t *TrMat) Eq(m *TrMat) bool { + return t.Data == m.Data +} + func (t *TrMat) Clone() *TrMat { return &TrMat{ Mat4: *t.Mat4.Clone(), @@ -92,7 +96,7 @@ func NewRotMat(q *Quat) *TrMat { } } -func NewTransformMatId() *TrMat { +func NewTrMatId() *TrMat { return &TrMat{ Mat4: *NewMat4Id(), } diff --git a/gglm/transform_test.go b/gglm/transform_test.go new file mode 100755 index 0000000..2d5f6ed --- /dev/null +++ b/gglm/transform_test.go @@ -0,0 +1,83 @@ +package gglm_test + +import ( + "testing" + + "github.com/bloeys/gglm/gglm" +) + +func TestNewTrMatId(t *testing.T) { + + m := gglm.NewTrMatId() + ans := &gglm.TrMat{ + Mat4: gglm.Mat4{ + Data: [16]float32{ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }, + }, + } + + if !m.Eq(ans) { + t.Errorf("Got: %v; Expected: %v", m.String(), ans.String()) + } +} + +func TestNewTranslationMat(t *testing.T) { + + m := gglm.NewTranslationMat(gglm.NewVec3(1, 2, 3)) + ans := &gglm.TrMat{ + Mat4: gglm.Mat4{ + Data: [16]float32{ + 1, 0, 0, 1, + 0, 1, 0, 2, + 0, 0, 1, 3, + 0, 0, 0, 1, + }, + }, + } + + if !m.Eq(ans) { + t.Errorf("Got: %v; Expected: %v", m.String(), ans.String()) + } +} + +func TestNewScaleMat(t *testing.T) { + + m := gglm.NewScaleMat(gglm.NewVec3(1, 2, 3)) + ans := &gglm.TrMat{ + Mat4: gglm.Mat4{ + Data: [16]float32{ + 1, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 3, 0, + 0, 0, 0, 1, + }, + }, + } + + if !m.Eq(ans) { + t.Errorf("Got: %v; Expected: %v", m.String(), ans.String()) + } +} + +func TestNewRotMat(t *testing.T) { + + m := gglm.NewRotMat(gglm.NewQuatId()) + ans := &gglm.TrMat{ + Mat4: gglm.Mat4{ + Data: [16]float32{ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }, + }, + } + + if !m.Eq(ans) { + t.Errorf("Got: %v; Expected: %v", m.String(), ans.String()) + } +} diff --git a/main.go b/main.go index 2fb7471..dadeae7 100755 --- a/main.go +++ b/main.go @@ -142,7 +142,7 @@ func main() { rotMat := gglm.NewRotMat(gglm.NewQuatEuler(gglm.NewVec3(60, 30, 20).AsRad())) scaleMat := gglm.NewScaleMat(gglm.NewVec3(1, 1, 1)) - modelMat := gglm.NewTransformMatId() + modelMat := gglm.NewTrMatId() modelMat.Mul(translationMat.Mul(rotMat.Mul(scaleMat))) println("\n\n\n", modelMat.String()) @@ -159,4 +159,9 @@ func main() { trMatClone.Scale(gglm.NewVec3(2, 2, 2)) trMatClone.Translate(gglm.NewVec3(9, 0, 0)) println("\n\n", trMatOrig.String(), "; ", trMatClone.String()) + + //Quat geo + q1 := gglm.NewQuatEuler(gglm.NewVec3(180, 0, 0).AsRad()) + q2 := gglm.NewQuatEuler(gglm.NewVec3(0, 180, 0).AsRad()) + println(gglm.AngleQuat(q1, q2) * gglm.Rad2Deg) }