5 Commits

Author SHA1 Message Date
051f91288d remove comment 2022-07-02 20:59:59 +04:00
d0ac00b388 Set swizzles and tests 2022-05-23 22:26:52 +04:00
971afed401 Reorder interface 2022-05-23 22:12:29 +04:00
547d3ad234 Inlining checks+update readme 2022-05-22 20:24:07 +04:00
e45e4d3304 Add NewQuatEulerXYZ+better comments 2022-05-22 20:14:01 +04:00
9 changed files with 245 additions and 27 deletions

View File

@ -22,7 +22,6 @@ gglm currently has the following:
## Usage
```go
import "github.com/bloeys/gglm/gglm"
@ -43,10 +42,15 @@ func main() {
println(v1.Eq(v2))
v2.Set(1, 2)
println(v1.Eq(v2))
//This performs: v1 += v2
//v1 is returned from the function, so we can chain calls that operate on v1
newX := v1.Add(v2).X()
println("newX:", newX)
}
```
## 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.

View File

@ -16,7 +16,7 @@ func (q *Quat) Eq(q2 *Quat) bool {
return q.Data == q2.Data
}
//Angle returns the angle represented by this quaternion
//Angle returns the angle represented by this quaternion in radians
func (q *Quat) Angle() float32 {
if Abs32(q.Data[3]) > CosHalf {
@ -74,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)

View File

@ -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) {

View File

@ -2,56 +2,64 @@ package gglm
type Swizzle1 interface {
X() float32
R() float32
SetX(float32)
SetR(float32)
AddX(float32)
R() float32
SetR(float32)
AddR(float32)
}
type Swizzle2 interface {
Swizzle1
Y() float32
G() float32
SetY(float32)
SetG(float32)
AddY(float32)
SetXY(float32, float32)
AddXY(float32, float32)
G() float32
SetG(float32)
AddG(float32)
AddXY(float32, float32)
SetRG(float32, float32)
AddRG(float32, float32)
}
type Swizzle3 interface {
Swizzle2
Z() float32
B() float32
SetZ(float32)
SetB(float32)
AddZ(float32)
SetXYZ(float32, float32, float32)
AddXYZ(float32, float32, float32)
B() float32
SetB(float32)
AddB(float32)
AddXYZ(float32, float32, float32)
SetRGB(float32, float32, float32)
AddRGB(float32, float32, float32)
}
type Swizzle4 interface {
Swizzle3
W() float32
A() float32
SetW(float32)
SetA(float32)
AddW(float32)
SetXYZW(float32, float32, float32, float32)
AddXYZW(float32, float32, float32, float32)
A() float32
SetA(float32)
AddA(float32)
AddXYZW(float32, float32, float32, float32)
SetRGBA(float32, float32, float32, float32)
AddRGBA(float32, float32, float32, float32)
}

View File

@ -62,11 +62,21 @@ func (v *Vec2) AddG(g float32) {
v.Data[1] += g
}
func (v *Vec2) SetXY(x, y float32) {
v.Data[0] = x
v.Data[1] = y
}
func (v *Vec2) AddXY(x, y float32) {
v.Data[0] += x
v.Data[1] += y
}
func (v *Vec2) SetRG(r, g float32) {
v.Data[0] = r
v.Data[1] = g
}
func (v *Vec2) AddRG(r, g float32) {
v.Data[0] += r
v.Data[1] += g

View File

@ -84,22 +84,44 @@ func (v *Vec3) AddB(b float32) {
v.Data[2] += b
}
func (v *Vec3) SetXY(x, y float32) {
v.Data[0] = x
v.Data[1] = y
}
func (v *Vec3) AddXY(x, y float32) {
v.Data[0] += x
v.Data[1] += y
}
func (v *Vec3) SetRG(r, g float32) {
v.Data[0] = r
v.Data[1] = g
}
func (v *Vec3) AddRG(r, g float32) {
v.Data[0] += r
v.Data[1] += g
}
func (v *Vec3) SetXYZ(x, y, z float32) {
v.Data[0] = x
v.Data[1] = y
v.Data[2] = z
}
func (v *Vec3) AddXYZ(x, y, z float32) {
v.Data[0] += x
v.Data[1] += y
v.Data[2] += z
}
func (v *Vec3) SetRGB(r, g, b float32) {
v.Data[0] = r
v.Data[1] = g
v.Data[2] = b
}
func (v *Vec3) AddRGB(r, g, b float32) {
v.Data[0] += r
v.Data[1] += g

View File

@ -108,28 +108,57 @@ func (v *Vec4) AddA(a float32) {
v.Data[3] += a
}
func (v *Vec4) SetXY(x, y float32) {
v.Data[0] = x
v.Data[1] = y
}
func (v *Vec4) AddXY(x, y float32) {
v.Data[0] += x
v.Data[1] += y
}
func (v *Vec4) SetRG(r, g float32) {
v.Data[0] = r
v.Data[1] = g
}
func (v *Vec4) AddRG(r, g float32) {
v.Data[0] += r
v.Data[1] += g
}
func (v *Vec4) SetXYZ(x, y, z float32) {
v.Data[0] = x
v.Data[1] = y
v.Data[2] = z
}
func (v *Vec4) AddXYZ(x, y, z float32) {
v.Data[0] += x
v.Data[1] += y
v.Data[2] += z
}
func (v *Vec4) SetRGB(r, g, b float32) {
v.Data[0] = r
v.Data[1] = g
v.Data[2] = b
}
func (v *Vec4) AddRGB(r, g, b float32) {
v.Data[0] += r
v.Data[1] += g
v.Data[2] += b
}
func (v *Vec4) SetXYZW(x, y, z, w float32) {
v.Data[0] = x
v.Data[1] = y
v.Data[2] = z
v.Data[3] = w
}
func (v *Vec4) AddXYZW(x, y, z, w float32) {
v.Data[0] += x
v.Data[1] += y
@ -137,6 +166,13 @@ func (v *Vec4) AddXYZW(x, y, z, w float32) {
v.Data[3] += w
}
func (v *Vec4) SetRGBA(r, g, b, a float32) {
v.Data[0] = r
v.Data[1] = g
v.Data[2] = b
v.Data[3] = a
}
func (v *Vec4) AddRGBA(r, g, b, a float32) {
v.Data[0] += r
v.Data[1] += g

View File

@ -102,26 +102,42 @@ func TestVecSwizzleGet(t *testing.T) {
func TestVecSwizzleSet(t *testing.T) {
//Vec2
v2 := gglm.NewVec2(0, 0)
v2 := gglm.NewVec2(1, 1)
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())
}
v2 = gglm.NewVec2(1, 1)
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())
}
v2 = gglm.NewVec2(1, 1)
ans2 = gglm.NewVec2(1, 2)
v2.SetXY(1, 2)
if !v2.Eq(ans2) {
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
}
v2 = gglm.NewVec2(1, 1)
ans2 = gglm.NewVec2(11, 22)
v2.SetRG(11, 22)
if !v2.Eq(ans2) {
t.Errorf("Got: %v; Expected: %v", v2.String(), ans2.String())
}
//Vec3
v3 := gglm.NewVec3(0, 0, 0)
v3 := gglm.NewVec3(1, 1, 1)
ans3 := gglm.NewVec3(1, 2, 3)
v3.SetX(1)
@ -132,6 +148,7 @@ func TestVecSwizzleSet(t *testing.T) {
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
}
v3 = gglm.NewVec3(1, 1, 1)
ans3 = gglm.NewVec3(11, 22, 33)
v3.SetR(11)
@ -142,8 +159,40 @@ func TestVecSwizzleSet(t *testing.T) {
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
}
v3 = gglm.NewVec3(1, 1, 1)
ans3 = gglm.NewVec3(1, 2, 1)
v3.SetXY(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(1, 2, 1)
v3.SetRG(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(1, 2, 3)
v3.SetXYZ(1, 2, 3)
if !v3.Eq(ans3) {
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
}
v3 = gglm.NewVec3(1, 1, 1)
ans3 = gglm.NewVec3(1, 2, 3)
v3.SetRGB(1, 2, 3)
if !v3.Eq(ans3) {
t.Errorf("Got: %v; Expected: %v", v3.String(), ans3.String())
}
//Vec4
v4 := gglm.NewVec4(0, 0, 0, 0)
v4 := gglm.NewVec4(1, 1, 1, 1)
ans4 := gglm.NewVec4(1, 2, 3, 4)
v4.SetX(1)
@ -155,6 +204,7 @@ func TestVecSwizzleSet(t *testing.T) {
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
}
v4 = gglm.NewVec4(1, 1, 1, 1)
ans4 = gglm.NewVec4(11, 22, 33, 44)
v4.SetR(11)
@ -165,6 +215,54 @@ func TestVecSwizzleSet(t *testing.T) {
if !v4.Eq(ans4) {
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
}
v4 = gglm.NewVec4(1, 1, 1, 1)
ans4 = gglm.NewVec4(1, 2, 1, 1)
v4.SetXY(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(1, 2, 1, 1)
v4.SetRG(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(1, 2, 3, 1)
v4.SetXYZ(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(1, 2, 3, 1)
v4.SetRGB(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(1, 2, 3, 4)
v4.SetXYZW(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)
ans4 = gglm.NewVec4(1, 2, 3, 4)
v4.SetRGBA(1, 2, 3, 4)
if !v4.Eq(ans4) {
t.Errorf("Got: %v; Expected: %v", v4.String(), ans4.String())
}
}
func TestVecSwizzleAdd(t *testing.T) {

View File

@ -64,6 +64,9 @@ func main() {
v2.Set(1, 2)
println(v1.Eq(v2))
v1.AddXY(v2.X(), v2.Y())
println(v1.String())
println("V1: " + v1.String())
v1.Normalize()
println("V1 Normal: " + v1.String())
@ -97,6 +100,10 @@ func main() {
println(gglm.DotVec4(v5, v6))
v5.Add(v6)
v5.AddXYZW(v6.X(), v6.Y(), v6.Z(), v6.W())
println(v6.String())
println("V6: " + v6.String())
v6.Normalize()
println("V6 Normal: " + v6.String())