Documentation ¶
Index ¶
- type MatStack
- type NoInverseError
- type TransformStack
- func (ms *TransformStack) Copy() *TransformStack
- func (ms *TransformStack) Len() int
- func (ms *TransformStack) Peek() mgl32.Mat4
- func (ms *TransformStack) Pop() (mgl32.Mat4, error)
- func (ms *TransformStack) Push(m mgl32.Mat4)
- func (ms *TransformStack) Reseed(n int, change mgl32.Mat4) error
- func (ms *TransformStack) Unwind(n int) error
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type MatStack ¶
A MatStack is an OpenGL-style matrix stack, usually used for things like scenegraphs. This allows you to easily maintain matrix state per call level.
func NewMatStack ¶
func NewMatStack() *MatStack
func (*MatStack) LoadIdent ¶
func (ms *MatStack) LoadIdent()
LoadIdent is a shortcut for Load(mgl.Ident4())
func (*MatStack) Pop ¶
Pop removes the first element of the matrix from the stack, if there is only one element left there is an error.
type NoInverseError ¶
A NoInverseError is returned on rebase when an inverse cannot be found along the chain, due to a transformation projecting the matrix into a singularity. The values include the matrix no inverse can be found for, and the location of that matrix.
func (NoInverseError) Error ¶
func (nie NoInverseError) Error() string
type TransformStack ¶
TransformStack is a linear fully-persistent data structure of matrix multiplications Each push to a TransformStack multiplies the current top of the stack with thew new matrix and appends it to the top. Each pop undoes the previous multiplication.
This allows arbitrary unwinding of transformations, at the cost of a lot of memory. A notable feature is the reseed and rebase, which allow invertible transformations to be rewritten as if a different transform had been made in the middle.
func NewTransformStack ¶
func NewTransformStack() *TransformStack
NewTransformStack returns a matrix stack where the top element is the identity.
func Rebase ¶
func Rebase(ms *TransformStack, from int, m *TransformStack) (*TransformStack, error)
Rebase replays the current matrix stack as if the transformation that occurred at index "from" in ms had instead started at the top of m.
This returns a brand new stack containing all of m followed by all transformations at from and after on ms as if they has been done on m instead.
Example ¶
parent1 := NewTransformStack() scale := mgl32.Scale3D(2, 2, 2) rot := mgl32.HomogRotate3DY(mgl32.DegToRad(90)) trans := mgl32.Translate3D(5, 5, 5) parent1.Push(trans) parent1.Push(rot) parent1.Push(scale) parent2 := parent1.Copy() trans2 := mgl32.Translate3D(1, 1, 1) rot2 := mgl32.HomogRotate3DX(mgl32.DegToRad(45)) parent1.Push(trans2) parent1.Push(rot2) // Replay the pushes the changes from parent1 after the copy onto parent2, as if // they had been done on parent2 instead parent2, err := Rebase(parent1, 4, parent2) if err != nil { panic(err) } // Now parent2 and parent 1 should be the same! fmt.Println(parent2.Peek().ApproxEqualThreshold(parent1.Peek(), 1e-4))
Output: true
func (*TransformStack) Copy ¶
func (ms *TransformStack) Copy() *TransformStack
Copy will create a new "branch" of the current matrix stack, the copy will contain all elements of the current stack in a new stack. Changes to one will never affect the other.
func (*TransformStack) Len ¶
func (ms *TransformStack) Len() int
Len returns the size of the matrix stack. This value will never be less than 1.
func (*TransformStack) Peek ¶
func (ms *TransformStack) Peek() mgl32.Mat4
Peek returns the value of the current top element of the stack, without removing it.
func (*TransformStack) Pop ¶
func (ms *TransformStack) Pop() (mgl32.Mat4, error)
Pop the current matrix off the top of the stack and returns it. If the matrix stack only has one element left, this will return an error.
func (*TransformStack) Push ¶
func (ms *TransformStack) Push(m mgl32.Mat4)
Push multiplies the current top matrix by m, and pushes the result on the stack.
func (*TransformStack) Reseed ¶
func (ms *TransformStack) Reseed(n int, change mgl32.Mat4) error
Reseed is tricky. It attempts to seed an arbitrary point in the matrix and replay all transformations as if that point in the push had been the argument "change" instead of the original value. The matrix stack does NOT keep track of arguments so this is done via consecutive inverses. If the inverse of element i can be found, we can calculate the transformation that was given at point i+1. This transformation can then be multiplied by the NEW matrix at point i to complete the "what if". If no such inverse can be found at any given point along the rebase, it will be aborted, and the original stack will NOT be visibly affected. The error returned will be of type NoInverseError.
If n is out of bounds (n <= 0 || n >= len(*ms)), a generic error from the errors package will be returned.
If you have the old transformations retained, it is recommended that you use Unwind followed by Push(change) and then further calling Push for each transformation. Rebase is imprecise by nature, and sometimes impossible. It's also expensive due to the inverse calculation at each point.
Example ¶
stack := NewTransformStack() scale := mgl32.Scale3D(2, 2, 2) rot := mgl32.HomogRotate3DY(mgl32.DegToRad(90)) trans := mgl32.Translate3D(4, 5, 6) stack.Push(trans) stack.Push(rot) stack.Push(scale) fmt.Println("Initial state:\n", stack.Peek()) trans2 := mgl32.Translate3D(1, 2, 3) err := stack.Reseed(1, trans2) if err == nil { panic("Rebase failed") } fmt.Println("After rebase:\n", stack.Peek()) fmt.Println("Should be:\n", trans2.Mul4(rot).Mul4(scale))
Output:
func (*TransformStack) Unwind ¶
func (ms *TransformStack) Unwind(n int) error
Unwind cuts down the matrix as if Pop had been called n times. If n would bring the matrix down below 1 element, this does nothing and returns an error.