gg/transform.go

247 lines
4.6 KiB
Go
Raw Normal View History

2023-10-23 15:45:18 +03:00
package gg
2023-02-17 12:47:17 +03:00
2023-02-17 23:51:40 +03:00
import (
//"github.com/hajimehoshi/ebiten/v2"
//"math"
2023-02-17 23:51:40 +03:00
)
type Transformer interface {
2024-01-18 06:06:27 +03:00
GetTransform() *Transform
}
// The structure represents basic transformation
// features: positioning, rotating and scaling.
2023-02-17 12:47:17 +03:00
type Transform struct {
2023-12-23 00:09:07 +03:00
// Absolute (if no parent) position and
// the scale.
2024-01-18 06:06:27 +03:00
position, scale Vector
2023-12-23 00:09:07 +03:00
// The object rotation in radians.
2024-01-18 06:06:27 +03:00
rotation Float
2023-12-23 00:09:07 +03:00
// The not scaled offset vector from upper left corner
// which the object should be rotated around.
2024-01-18 06:06:27 +03:00
around Vector
// If is not nil then the upper values will be relational to
// the parent ones.
2024-01-18 06:06:27 +03:00
parent *Transform
// Dirty is true if we anyhow changed matrix.
dirty, parentDirty bool
matrix, parentMatrix, parentInverted Matrix
}
2024-01-18 06:06:27 +03:00
// For implementing the Transformer on embedding.
func (t *Transform) GetTransform() *Transform {
return t
2023-02-17 12:47:17 +03:00
}
2023-12-24 15:05:34 +03:00
// Returns the default Transform structure.
2023-02-17 12:47:17 +03:00
func T() Transform {
2023-05-22 23:51:14 +03:00
ret := Transform{
2023-12-24 15:05:34 +03:00
// Rotate around
2024-01-18 06:06:27 +03:00
scale: Vector{1, 1},
2023-12-24 15:05:34 +03:00
// Rotate around the center.
2024-01-18 06:06:27 +03:00
around: V(.5, .5),
2023-05-22 23:51:14 +03:00
}
2023-02-17 12:47:17 +03:00
return ret
}
2024-01-18 06:06:27 +03:00
// 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
}
2024-01-18 06:06:27 +03:00
t.rotation -= t.parent.Rotation()
}
// Set the absolute object scale.
func (t *Transform) SetScale(scale Vector) {
t.dirty = true
t.parentDirty = true
2024-01-18 06:06:27 +03:00
t.scale = scale
}
func (t *Transform) AddScale(add ...Vector) {
t.dirty = true
//t.parentDirty = true
t.scale = t.scale.Add(add...)
}
2024-01-18 06:06:27 +03:00
func (t *Transform) SetAround(around Vector) {
t.dirty = true
t.around = around
}
// Get the absolute representation of the transform.
2024-01-18 06:06:27 +03:00
func (t *Transform) Abs() Transform {
if t.parent == nil {
return *t
}
ret := Transform{}
2024-01-18 06:06:27 +03:00
ret.position = t.Position()
ret.rotation = t.Rotation()
ret.scale = t.Scale()
ret.around = t.Around()
ret.dirty = true
ret.parentDirty = true
return ret
}
2024-01-18 06:06:27 +03:00
func (t *Transform) Rel() Transform {
ret := *t
ret.parent = nil
return ret
}
2024-01-18 06:06:27 +03:00
// Get the absolute object position.
func (t *Transform) Position() Vector {
if t.parent == nil {
return t.position
}
2024-01-18 06:06:27 +03:00
pm, _ := t.parent.MatrixForParenting()
return t.position.Apply(pm)
}
2024-01-18 06:06:27 +03:00
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
}
2024-01-18 06:06:27 +03:00
// Get the absolute object rotation.
func (t *Transform) Rotation() Float {
if t.parent == nil {
return t.rotation
}
2024-01-18 06:06:27 +03:00
return t.rotation + t.parent.Rotation()
}
func (t *Transform) Rotate(add Float) {
t.dirty = true
t.parentDirty = true
t.rotation += add
}
2024-01-18 06:06:27 +03:00
func (t *Transform) Around() Vector {
return t.around
}
2024-01-18 06:06:27 +03:00
// Returns true if the object is connected
// to some parent.
func (t *Transform) Connected() bool {
2024-01-18 06:06:27 +03:00
return t.parent != nil
}
2024-01-18 06:06:27 +03:00
// Connect the object to another one making
// it its parent.
func (t *Transform) Connect(parent Transformer) {
if parent == nil {
return
}
if t.parent != nil {
t.Disconnect()
}
position := t.Position()
rotation := t.Rotation()
2024-01-18 06:06:27 +03:00
t.parent = parent.GetTransform()
t.SetPosition(position)
t.SetRotation(rotation)
}
2024-01-18 06:06:27 +03:00
// Disconnect from the parent.
func (t *Transform) Disconnect() {
2024-01-18 06:06:27 +03:00
if t.parent == nil {
return
}
*t = t.Abs()
}
2024-01-18 06:06:27 +03:00
// 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)
2024-01-18 06:06:27 +03:00
m.Rotate(t.rotation)
m.Translate(t.position.X, t.position.Y)
t.parentMatrix = m
mi = m
2024-01-18 06:06:27 +03:00
mi.Invert()
t.parentInverted = mi
t.parentDirty = false
} else {
m = t.parentMatrix
mi = t.parentInverted
}
2024-01-18 06:06:27 +03:00
if t.parent != nil {
pm, pmi := t.parent.MatrixForParenting()
m.Concat(pm)
pmi.Concat(mi)
mi = pmi
2024-01-18 06:06:27 +03:00
}
return m, mi
}
2023-02-17 23:51:40 +03:00
// Returns the GeoM with corresponding
// to the transfrom transformation.
2024-01-18 06:06:27 +03:00
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
}
2023-02-17 23:51:40 +03:00
2024-01-18 06:06:27 +03:00
if t.parent != nil {
pm, _ = t.parent.MatrixForParenting()
m.Concat(pm)
}
2024-01-18 06:06:27 +03:00
return m
2023-02-17 23:51:40 +03:00
}