matstack

package
v0.0.0-...-f2cde84 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2023 License: BSD-3-Clause Imports: 3 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type MatStack

type MatStack []mgl32.Mat4

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) LeftMul

func (ms *MatStack) LeftMul(m mgl32.Mat4)

LeftMul multiplies the current top of the matrix by the argument.

func (*MatStack) Load

func (ms *MatStack) Load(m mgl32.Mat4)

Load rewrites the top element of the stack with m

func (*MatStack) LoadIdent

func (ms *MatStack) LoadIdent()

LoadIdent is a shortcut for Load(mgl.Ident4())

func (*MatStack) Peek

func (ms *MatStack) Peek() mgl32.Mat4

Peek returns the top element.

func (*MatStack) Pop

func (ms *MatStack) Pop() error

Pop removes the first element of the matrix from the stack, if there is only one element left there is an error.

func (*MatStack) Push

func (ms *MatStack) Push()

Push copies the top element and pushes it on the stack.

func (*MatStack) RightMul

func (ms *MatStack) RightMul(m mgl32.Mat4)

RightMul multiplies the current top of the matrix by the argument.

type NoInverseError

type NoInverseError struct {
	Mat mgl32.Mat4
	Loc int
}

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

type TransformStack []mgl32.Mat4

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL