239 lines
4.5 KiB
Go
239 lines
4.5 KiB
Go
package gg
|
|
|
|
import (
|
|
//"github.com/hajimehoshi/ebiten/v2"
|
|
//"math"
|
|
)
|
|
|
|
type Transformer interface {
|
|
GetTransform() *Transform
|
|
}
|
|
|
|
// The structure represents basic transformation
|
|
// features: positioning, rotating and scaling.
|
|
type Transform struct {
|
|
// Absolute (if no parent) position and
|
|
// the scale.
|
|
position, scale Vector
|
|
// The object rotation in radians.
|
|
rotation Float
|
|
// The not scaled offset vector from upper left corner
|
|
// which the object should be rotated around.
|
|
around Vector
|
|
|
|
// If is not nil then the upper values will be relational to
|
|
// the parent ones.
|
|
parent *Transform
|
|
|
|
// Dirty is true if we anyhow changed matrix.
|
|
dirty, parentDirty bool
|
|
|
|
matrix, parentMatrix, parentInverted Matrix
|
|
}
|
|
|
|
// For implementing the Transformer on embedding.
|
|
func (t *Transform) GetTransform() *Transform {
|
|
return t
|
|
}
|
|
|
|
// Returns the default Transform structure.
|
|
func T() Transform {
|
|
ret := Transform{
|
|
// Rotate around
|
|
scale: Vector{1, 1},
|
|
// Rotate around the center.
|
|
around: V(.5, .5),
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// Set the absolute object position.
|
|
func (t *Transform) SetPosition(position Vector) {
|
|
t.dirty = true
|
|
t.parentDirty = true
|
|
if t.parent == nil {
|
|
t.position = position
|
|
return
|
|
}
|
|
|
|
_, mi := t.parent.MatrixForParenting()
|
|
t.position = position.Apply(mi)
|
|
}
|
|
|
|
// Set the absolute object rotation.
|
|
func (t *Transform) SetRotation(rotation Float) {
|
|
t.dirty = true
|
|
t.parentDirty = true
|
|
if t.parent == nil {
|
|
t.rotation = rotation
|
|
return
|
|
}
|
|
t.rotation -= t.parent.Rotation()
|
|
}
|
|
|
|
// Set the absolute object scale.
|
|
func (t *Transform) SetScale(scale Vector) {
|
|
t.dirty = true
|
|
t.scale = scale
|
|
}
|
|
|
|
func (t *Transform) AddScale(add ...Vector) {
|
|
t.dirty = true
|
|
t.scale = t.scale.Add(add...)
|
|
}
|
|
|
|
func (t *Transform) SetAround(around Vector) {
|
|
t.dirty = true
|
|
t.around = around
|
|
}
|
|
|
|
// Get the absolute representation of the transform.
|
|
func (t *Transform) Abs() Transform {
|
|
if t.parent == nil {
|
|
return *t
|
|
}
|
|
|
|
ret := T()
|
|
ret.position = t.Position()
|
|
ret.rotation = t.Rotation()
|
|
|
|
// Do not need that
|
|
// cause parent does not affect
|
|
// scaling.
|
|
// (Should think if scaling from parent
|
|
// can be used anyhow)
|
|
|
|
//ret.scale = t.Scale()
|
|
|
|
return ret
|
|
}
|
|
|
|
func (t *Transform) Rel() Transform {
|
|
ret := *t
|
|
ret.parent = nil
|
|
return ret
|
|
}
|
|
|
|
// Get the absolute object position.
|
|
func (t *Transform) Position() Vector {
|
|
if t.parent == nil {
|
|
return t.position
|
|
}
|
|
pm, _ := t.parent.MatrixForParenting()
|
|
return t.position.Apply(pm)
|
|
}
|
|
|
|
func (t *Transform) Move(v ...Vector) {
|
|
t.SetPosition(t.Position().Add(v...))
|
|
}
|
|
|
|
// Get the absolute object scale.
|
|
func (t *Transform) Scale() Vector {
|
|
return t.scale
|
|
}
|
|
|
|
// Get the absolute object rotation.
|
|
func (t *Transform) Rotation() Float {
|
|
if t.parent == nil {
|
|
return t.rotation
|
|
}
|
|
return t.rotation + t.parent.Rotation()
|
|
}
|
|
|
|
func (t *Transform) Rotate(add Float) {
|
|
t.rotation += add
|
|
t.dirty = true
|
|
}
|
|
func (t *Transform) Around() Vector {
|
|
return t.around
|
|
}
|
|
|
|
// Returns true if the object is connected
|
|
// to some parent.
|
|
func (t *Transform) Connected() bool {
|
|
return t.parent != nil
|
|
}
|
|
|
|
// Connect the object to another one making
|
|
// it its parent.
|
|
func (t *Transform) Connect(parent Transformer) {
|
|
absPosition := t.Position()
|
|
absRotation := t.Rotation()
|
|
t.parent = parent.GetTransform()
|
|
t.SetPosition(absPosition)
|
|
t.SetRotation(absRotation)
|
|
}
|
|
|
|
// Disconnect from the parent.
|
|
func (t *Transform) Disconnect() {
|
|
if t.parent == nil {
|
|
return
|
|
}
|
|
*t = t.Abs()
|
|
}
|
|
|
|
// Return the matrix and the inverted one for parenting children.
|
|
func (t *Transform) MatrixForParenting() (Matrix, Matrix) {
|
|
var m, mi Matrix
|
|
|
|
if t.parentDirty {
|
|
|
|
m.Scale(t.scale.X, t.scale.Y)
|
|
m.Rotate(t.rotation)
|
|
m.Translate(t.position.X, t.position.Y)
|
|
t.parentMatrix = m
|
|
|
|
mi := m
|
|
mi.Invert()
|
|
t.parentInverted = mi
|
|
|
|
t.parentDirty = false
|
|
} else {
|
|
m = t.parentMatrix
|
|
mi = t.parentInverted
|
|
}
|
|
|
|
if t.parent != nil {
|
|
pm, pmi := t.parent.MatrixForParenting()
|
|
m.Concat(pm)
|
|
mi.Concat(pmi)
|
|
}
|
|
|
|
return m, mi
|
|
|
|
|
|
}
|
|
|
|
// Returns the GeoM with corresponding
|
|
// to the transfrom transformation.
|
|
func (t *Transform)Matrix() Matrix {
|
|
var m, pm Matrix
|
|
|
|
// Calculating only if we changed the structure anyhow.
|
|
if t.dirty {
|
|
// Scale first.
|
|
m.Scale(t.scale.X, t.scale.Y)
|
|
// Then move and rotate.
|
|
m.Translate(
|
|
-t.around.X * t.scale.X,
|
|
-t.around.Y * t.scale.Y,
|
|
)
|
|
m.Rotate(t.rotation)
|
|
// And finally move to the absolute position.
|
|
m.Translate(t.position.X, t.position.Y)
|
|
t.matrix = m
|
|
|
|
// Setting the flag so we d
|
|
t.dirty = false
|
|
} else {
|
|
m = t.matrix
|
|
}
|
|
|
|
if t.parent != nil {
|
|
pm, _ = t.parent.MatrixForParenting()
|
|
m.Concat(pm)
|
|
}
|
|
|
|
return m
|
|
}
|
|
|