func (q *Quat) Dot(q2 *Quat) Real {
	return q[0]*q2[0] + q[1]*q2[1] + q[2]*q2[2] + q[3]*q2[3]
}
Dot calculates the dot product between two quaternions, equivalent to if this was a Vector4
package math
import "math"
func QuatFromAxis(angle, x, y, z Real) Quat {
	s := RealSin(angle / 2.0)
	c := RealCos(angle / 2.0)
	result := Quat{c, x * s, y * s, z * s}
	result.Normalize()
	return result
}
func (q *Quat) AddScaledVector(v *Vector3, scale Real) {
	var temp Quat
	temp[0] = 0.0
	temp[1] = v[0] * scale
	temp[2] = v[1] * scale
	temp[3] = v[2] * scale
	temp.Mul(q)
	q[0] += temp[0] * 0.5
	q[1] += temp[1] * 0.5
	q[2] += temp[2] * 0.5
	q[3] += temp[3] * 0.5
}
func (q *Quat) SetIdentity() {
	q[0], q[1], q[2], q[3] = 1.0, 0.0, 0.0, 0.0
}
func (q *Quat) Len() Real {
	return RealSqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3])
}
func (q *Quat) Mul(q2 *Quat) {
	var w, x, y, z Real
	w = q[0]*q2[0] - q[1]*q2[1] - q[2]*q2[2] - q[3]*q2[3]
	x = q[0]*q2[1] + q[1]*q2[0] + q[2]*q2[3] - q[3]*q2[2]
	y = q[0]*q2[2] + q[2]*q2[0] + q[3]*q2[1] - q[1]*q2[3]
	z = q[0]*q2[3] + q[3]*q2[0] + q[1]*q2[2] - q[2]*q2[1]
	q[0], q[1], q[2], q[3] = w, x, y, z
}
func (q *Quat) Rotate(v *Vector3) Vector3 {
	qvec := Vector3{q[1], q[2], q[3]}
	cross := qvec.Cross(v)
	result := *v
	qvec.MulWith(2.0)
	c2 := qvec.Cross(&cross)
	result.Add(&c2)
	cross.MulWith(2.0 * q[0])
	result.Add(&cross)
	return result
}
func (q *Quat) Conjugated() Quat {
	return Quat{q[0], -q[1], -q[2], -q[3]}
}
func (q *Quat) Normalize() {
	length := q.Len()
	if RealEqual(1.0, length) {
		return
	}
	if length == 0.0 {
		q.SetIdentity()
		return
	}
	if length == InfPos {
		length = MaxValue
	}
	invLength := 1.0 / length
	q[0] *= invLength
	q[1] *= invLength
	q[2] *= invLength
	q[3] *= invLength
}
func (q *Quat) LookAt(eye, center, up *Vector3) {
	direction := center
	direction.Sub(eye)
	direction.Normalize()
	rotDir := QuatBetweenVectors(&Vector3{0, 0, -1}, direction)
	upCur := rotDir.Rotate(&Vector3{0, 1, 0})
	rotTarget := QuatBetweenVectors(&upCur, up)
	rotTarget.Mul(&rotDir)  
	rotTarget.Inverse()     
	q[0] = rotTarget[0]
	q[1] = rotTarget[1]
	q[2] = rotTarget[2]
	q[3] = rotTarget[3]
}
func QuatBetweenVectors(s, d *Vector3) Quat {
	start := *s
	dest := *d
	start.Normalize()
	dest.Normalize()
	cosTheta := start.Dot(&dest)
	if cosTheta < -1.0+Epsilon {
		posX := Vector3{1.0, 0.0, 0.0}
		axis := posX.Cross(&start)
		if axis.Dot(&axis) < Epsilon {
			posY := Vector3{0.0, 1.0, 0.0}
			axis = posY.Cross(&start)
		}
		axis.Normalize()
		return QuatFromAxis(math.Pi, axis[0], axis[1], axis[2])
	}
	axis := start.Cross(&dest)
	ang := RealSqrt((1.0 + cosTheta) * 2.0)
	axis.MulWith(1.0 / ang)
	return Quat{
		ang * 0.5,
		axis[0], axis[1], axis[2],
	}
}
func (q *Quat) Inverse() {
	c := q.Conjugated()
	c.Scale(1.0 / q.Dot(q))
	q[0] = c[0]
	q[1] = c[1]
	q[2] = c[2]
	q[3] = c[3]
}
func (q *Quat) Scale(c Real) {
	q[0] *= c
	q[1] *= c
	q[2] *= c
	q[3] *= c
}