gg/ox/transform.go

275 lines
5.2 KiB
Go
Raw Permalink Normal View History

2024-05-28 11:24:12 +03:00
package ox
2023-02-17 12:47:17 +03:00
2024-05-28 11:24:12 +03:00
import "surdeus.su/core/gg/mx"
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
2024-05-28 11:24:12 +03:00
// features: positioning, rotating and scaling
// in more high level and more "GAME ENGINE" style.
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-05-28 11:24:12 +03:00
position, scale mx.Vector
2023-12-23 00:09:07 +03:00
// The object rotation in radians.
2024-05-28 11:24:12 +03:00
rotation mx.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-05-28 11:24:12 +03:00
around mx.Vector
2024-01-18 06:06:27 +03:00
// 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
2024-05-28 11:24:12 +03:00
matrix, parentMatrice, parentInverted mx.Matrice
2023-02-17 12:47:17 +03:00
}
2023-12-24 15:05:34 +03:00
// Returns the default Transform structure.
2024-06-02 22:27:11 +03:00
func T() *Transform {
ret := &Transform{
2023-12-24 15:05:34 +03:00
// Rotate around
2024-05-28 11:24:12 +03:00
scale: mx.V2(1),
2023-12-24 15:05:34 +03:00
// Rotate around the center.
2024-05-28 11:24:12 +03:00
around: mx.V2(.5),
2023-05-22 23:51:14 +03:00
}
2024-06-01 22:01:17 +03:00
ret.dirty = true
2024-06-02 22:27:11 +03:00
ret.parentDirty = true
2023-02-17 12:47:17 +03:00
return ret
}
2024-05-28 11:24:12 +03:00
// Returns whether it needs to be recalculated
// or not.
func (t *Transform) IsDirty() bool {
2024-06-01 16:07:28 +03:00
return t.dirty || t.parentDirty
2024-05-28 11:24:12 +03:00
}
// For implementing the Transformer on embedding.
func (t *Transform) GetTransform() *Transform {
return t
}
2024-01-18 06:06:27 +03:00
// Set the absolute object position.
2024-06-01 22:01:17 +03:00
func (t *Transform) SetPosition(position mx.Vector) *Transform {
2024-01-18 06:06:27 +03:00
t.dirty = true
t.parentDirty = true
if t.parent == nil {
t.position = position
2024-06-01 22:01:17 +03:00
return t
2024-01-18 06:06:27 +03:00
}
2024-05-28 11:24:12 +03:00
_, mi := t.parent.GetMatriceForParenting()
2024-01-18 06:06:27 +03:00
t.position = position.Apply(mi)
2024-06-01 22:01:17 +03:00
return t
2024-01-18 06:06:27 +03:00
}
// Set the absolute object rotation.
2024-06-01 22:01:17 +03:00
func (t *Transform) SetRotation(rotation mx.Float) *Transform {
2024-01-18 06:06:27 +03:00
t.dirty = true
t.parentDirty = true
if t.parent == nil {
t.rotation = rotation
2024-06-01 22:01:17 +03:00
return t
}
2024-05-28 11:24:12 +03:00
t.rotation -= t.parent.GetRotation()
2024-06-01 22:01:17 +03:00
return t
2024-01-18 06:06:27 +03:00
}
// Set the absolute object scale.
2024-06-01 22:01:17 +03:00
func (t *Transform) SetScale(scale mx.Vector) *Transform {
2024-01-18 06:06:27 +03:00
t.dirty = true
t.parentDirty = true
2024-01-18 06:06:27 +03:00
t.scale = scale
2024-06-01 22:01:17 +03:00
return t
2024-01-18 06:06:27 +03:00
}
2024-06-01 22:01:17 +03:00
func (t *Transform) AddScale(add mx.Vector) *Transform {
t.dirty = true
//t.parentDirty = true
2024-05-28 11:24:12 +03:00
t.scale = t.scale.Add(add)
2024-06-01 22:01:17 +03:00
return t
}
2024-06-01 22:01:17 +03:00
func (t *Transform) Scale(mul mx.Vector) *Transform {
t.dirty = true
t.scale = t.scale.Mul(mul)
return t
}
func (t *Transform) SetAround(around mx.Vector) *Transform {
2024-01-18 06:06:27 +03:00
t.dirty = true
t.around = around
2024-06-01 22:01:17 +03:00
return t
}
// 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-05-28 11:24:12 +03:00
ret.position = t.GetPosition()
ret.rotation = t.GetRotation()
ret.scale = t.GetScale()
ret.around = t.GetAround()
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.
2024-05-28 11:24:12 +03:00
func (t *Transform) GetPosition() mx.Vector {
2024-01-18 06:06:27 +03:00
if t.parent == nil {
return t.position
}
2024-05-28 11:24:12 +03:00
pm, _ := t.parent.GetMatriceForParenting()
2024-01-18 06:06:27 +03:00
return t.position.Apply(pm)
}
2024-05-28 11:24:12 +03:00
// Move by the specified delta.
func (t *Transform) Move(v mx.Vector) {
t.SetPosition(t.GetPosition().Add(v))
2024-01-18 06:06:27 +03:00
}
// Get the absolute object scale.
2024-05-28 11:24:12 +03:00
func (t *Transform) GetScale() mx.Vector {
2024-01-18 06:06:27 +03:00
return t.scale
}
2024-01-18 06:06:27 +03:00
// Get the absolute object rotation.
2024-05-28 11:24:12 +03:00
func (t *Transform) GetRotation() mx.Float {
2024-01-18 06:06:27 +03:00
if t.parent == nil {
return t.rotation
}
2024-05-28 11:24:12 +03:00
return t.rotation + t.parent.GetRotation()
2024-01-18 06:06:27 +03:00
}
2024-06-01 22:01:17 +03:00
func (t *Transform) Rotate(rot mx.Float) *Transform {
t.dirty = true
t.parentDirty = true
2024-05-28 11:24:12 +03:00
t.rotation += rot
2024-06-01 22:01:17 +03:00
return t
}
2024-05-28 11:24:12 +03:00
func (t *Transform) GetAround() mx.Vector {
2024-01-18 06:06:27 +03:00
return t.around
}
2024-01-18 06:06:27 +03:00
// Returns true if the object is connected
// to some parent.
2024-05-28 11:24:12 +03:00
func (t *Transform) IsConnected() 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.
2024-06-01 22:01:17 +03:00
func (t *Transform) Connect(parent Transformer) *Transform {
if parent == nil {
2024-06-01 22:01:17 +03:00
return t
}
if t.parent != nil {
t.Disconnect()
}
2024-05-28 11:24:12 +03:00
position := t.GetPosition()
rotation := t.GetRotation()
2024-01-18 06:06:27 +03:00
t.parent = parent.GetTransform()
t.SetPosition(position)
t.SetRotation(rotation)
2024-06-01 22:01:17 +03:00
return t
}
2024-01-18 06:06:27 +03:00
// Disconnect from the parent.
2024-06-01 22:01:17 +03:00
func (t *Transform) Disconnect() *Transform {
2024-01-18 06:06:27 +03:00
if t.parent == nil {
2024-06-01 22:01:17 +03:00
return t
}
*t = t.Abs()
2024-06-01 22:01:17 +03:00
return t
}
2024-06-01 22:01:17 +03:00
// Return the matrix and the inverted
// one for parenting children.
2024-05-28 11:24:12 +03:00
func (t *Transform) GetMatriceForParenting(
) (mx.Matrice, mx.Matrice) {
var m, mi mx.Matrice
2024-01-18 06:06:27 +03:00
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)
2024-05-28 11:24:12 +03:00
t.parentMatrice = m
2024-01-18 06:06:27 +03:00
mi = m
2024-01-18 06:06:27 +03:00
mi.Invert()
t.parentInverted = mi
t.parentDirty = false
} else {
2024-05-28 11:24:12 +03:00
m = t.parentMatrice
2024-01-18 06:06:27 +03:00
mi = t.parentInverted
}
2024-01-18 06:06:27 +03:00
if t.parent != nil {
2024-05-28 11:24:12 +03:00
pm, pmi := t.parent.GetMatriceForParenting()
2024-01-18 06:06:27 +03:00
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-05-28 11:24:12 +03:00
func (t *Transform) GetMatrice() mx.Matrice {
var m, pm mx.Matrice
2024-01-18 06:06:27 +03:00
// 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 {
2024-05-28 11:24:12 +03:00
pm, _ = t.parent.GetMatriceForParenting()
2024-01-18 06:06:27 +03:00
m.Concat(pm)
}
2024-01-18 06:06:27 +03:00
return m
2023-02-17 23:51:40 +03:00
}