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
|
|
|
|
2023-12-26 23:31:04 +03:00
|
|
|
type Transformer interface {
|
2024-01-18 06:06:27 +03:00
|
|
|
GetTransform() *Transform
|
2023-12-26 23:31:04 +03:00
|
|
|
}
|
|
|
|
|
2023-06-03 10:39:15 +03:00
|
|
|
// 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
|
|
|
|
2023-12-26 23:31:04 +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
|
2023-12-28 02:31:43 +03:00
|
|
|
}
|
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
|
2024-01-21 16:34:23 +03:00
|
|
|
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 {
|
2024-01-21 13:35:40 +03:00
|
|
|
t.dirty = true
|
2024-01-21 16:34:23 +03:00
|
|
|
//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-01-21 13:35:40 +03:00
|
|
|
}
|
|
|
|
|
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
|
2023-12-26 23:31:04 +03:00
|
|
|
}
|
|
|
|
|
2023-12-27 01:35:50 +03:00
|
|
|
// 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
|
2023-12-28 02:31:43 +03:00
|
|
|
}
|
|
|
|
|
2024-01-21 16:34:23 +03:00
|
|
|
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()
|
2024-01-21 16:34:23 +03:00
|
|
|
ret.dirty = true
|
|
|
|
ret.parentDirty = true
|
2023-12-28 02:31:43 +03:00
|
|
|
|
2023-12-27 01:35:50 +03:00
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2024-01-18 06:06:27 +03:00
|
|
|
func (t *Transform) Rel() Transform {
|
|
|
|
ret := *t
|
|
|
|
ret.parent = nil
|
|
|
|
return ret
|
2023-12-26 23:31:04 +03:00
|
|
|
}
|
|
|
|
|
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
|
2023-12-28 02:31:43 +03:00
|
|
|
}
|
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)
|
2023-12-27 01:35:50 +03:00
|
|
|
}
|
|
|
|
|
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
|
2023-12-27 01:35:50 +03:00
|
|
|
}
|
|
|
|
|
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
|
2023-12-28 02:31:43 +03:00
|
|
|
}
|
2024-05-28 11:24:12 +03:00
|
|
|
return t.rotation + t.parent.GetRotation()
|
2024-01-18 06:06:27 +03:00
|
|
|
}
|
2024-01-21 13:35:40 +03:00
|
|
|
|
2024-06-01 22:01:17 +03:00
|
|
|
func (t *Transform) Rotate(rot mx.Float) *Transform {
|
2024-01-21 13:35:40 +03:00
|
|
|
t.dirty = true
|
2024-01-21 17:00:50 +03:00
|
|
|
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-01-21 13:35:40 +03:00
|
|
|
}
|
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
|
2023-12-28 02:31:43 +03:00
|
|
|
}
|
|
|
|
|
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
|
2023-12-27 01:35:50 +03:00
|
|
|
}
|
|
|
|
|
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 {
|
2024-01-21 16:34:23 +03:00
|
|
|
if parent == nil {
|
2024-06-01 22:01:17 +03:00
|
|
|
return t
|
2024-01-21 16:34:23 +03:00
|
|
|
}
|
|
|
|
if t.parent != nil {
|
|
|
|
t.Disconnect()
|
|
|
|
}
|
|
|
|
|
2024-05-28 11:24:12 +03:00
|
|
|
position := t.GetPosition()
|
|
|
|
rotation := t.GetRotation()
|
2024-01-21 16:34:23 +03:00
|
|
|
|
2024-01-18 06:06:27 +03:00
|
|
|
t.parent = parent.GetTransform()
|
2024-01-21 16:34:23 +03:00
|
|
|
t.SetPosition(position)
|
|
|
|
t.SetRotation(rotation)
|
2024-06-01 22:01:17 +03:00
|
|
|
|
|
|
|
return t
|
2023-12-26 23:31:04 +03:00
|
|
|
}
|
|
|
|
|
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
|
2023-12-27 01:35:50 +03:00
|
|
|
}
|
|
|
|
*t = t.Abs()
|
2024-06-01 22:01:17 +03:00
|
|
|
|
|
|
|
return t
|
2023-12-28 02:31:43 +03:00
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
|
2024-01-21 16:34:23 +03:00
|
|
|
//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
|
|
|
|
2024-01-21 16:34:23 +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
|
2023-12-28 02:31:43 +03:00
|
|
|
}
|
|
|
|
|
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)
|
2024-01-21 17:00:50 +03:00
|
|
|
pmi.Concat(mi)
|
|
|
|
mi = pmi
|
2024-01-18 06:06:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return m, mi
|
2023-12-27 01:35:50 +03:00
|
|
|
}
|
|
|
|
|
2023-02-17 23:51:40 +03:00
|
|
|
// Returns the GeoM with corresponding
|
2023-05-30 22:35:49 +03:00
|
|
|
// 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)
|
|
|
|
}
|
2023-12-26 23:31:04 +03:00
|
|
|
|
2024-01-18 06:06:27 +03:00
|
|
|
return m
|
2023-02-17 23:51:40 +03:00
|
|
|
}
|
|
|
|
|