package ox import "surdeus.su/core/gg/mx" type Transformer interface { GetTransform() *Transform } // The structure represents basic transformation // features: positioning, rotating and scaling // in more high level and more "GAME ENGINE" style. type Transform struct { // Absolute (if no parent) position and // the scale. position, scale mx.Vector // The object rotation in radians. rotation mx.Float // The not scaled offset vector from upper left corner // which the object should be rotated around. around mx.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, parentMatrice, parentInverted mx.Matrice } // Returns the default Transform structure. func T() *Transform { ret := &Transform{ // Rotate around scale: mx.V2(1), // Rotate around the center. around: mx.V2(.5), } ret.dirty = true ret.parentDirty = true return ret } // Returns whether it needs to be recalculated // or not. func (t *Transform) IsDirty() bool { return t.dirty || t.parentDirty } // For implementing the Transformer on embedding. func (t *Transform) GetTransform() *Transform { return t } // Set the absolute object position. func (t *Transform) SetPosition(position mx.Vector) *Transform { t.dirty = true t.parentDirty = true if t.parent == nil { t.position = position return t } _, mi := t.parent.GetMatriceForParenting() t.position = position.Apply(mi) return t } // Set the absolute object rotation. func (t *Transform) SetRotation(rotation mx.Float) *Transform { t.dirty = true t.parentDirty = true if t.parent == nil { t.rotation = rotation return t } t.rotation -= t.parent.GetRotation() return t } // Set the absolute object scale. func (t *Transform) SetScale(scale mx.Vector) *Transform { t.dirty = true t.parentDirty = true t.scale = scale return t } func (t *Transform) AddScale(add mx.Vector) *Transform { t.dirty = true //t.parentDirty = true t.scale = t.scale.Add(add) return t } 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 { t.dirty = true t.around = around return t } // Get the absolute representation of the transform. func (t *Transform) Abs() Transform { if t.parent == nil { return *t } ret := Transform{} ret.position = t.GetPosition() ret.rotation = t.GetRotation() ret.scale = t.GetScale() ret.around = t.GetAround() ret.dirty = true ret.parentDirty = true return ret } func (t *Transform) Rel() Transform { ret := *t ret.parent = nil return ret } // Get the absolute object position. func (t *Transform) GetPosition() mx.Vector { if t.parent == nil { return t.position } pm, _ := t.parent.GetMatriceForParenting() return t.position.Apply(pm) } // Move by the specified delta. func (t *Transform) Move(v mx.Vector) { t.SetPosition(t.GetPosition().Add(v)) } // Get the absolute object scale. func (t *Transform) GetScale() mx.Vector { return t.scale } // Get the absolute object rotation. func (t *Transform) GetRotation() mx.Float { if t.parent == nil { return t.rotation } return t.rotation + t.parent.GetRotation() } func (t *Transform) Rotate(rot mx.Float) *Transform { t.dirty = true t.parentDirty = true t.rotation += rot return t } func (t *Transform) GetAround() mx.Vector { return t.around } // Returns true if the object is connected // to some parent. func (t *Transform) IsConnected() bool { return t.parent != nil } // Connect the object to another one making // it its parent. func (t *Transform) Connect(parent Transformer) *Transform { if parent == nil { return t } if t.parent != nil { t.Disconnect() } position := t.GetPosition() rotation := t.GetRotation() t.parent = parent.GetTransform() t.SetPosition(position) t.SetRotation(rotation) return t } // Disconnect from the parent. func (t *Transform) Disconnect() *Transform { if t.parent == nil { return t } *t = t.Abs() return t } // Return the matrix and the inverted // one for parenting children. func (t *Transform) GetMatriceForParenting( ) (mx.Matrice, mx.Matrice) { var m, mi mx.Matrice if t.parentDirty { //m.Scale(t.scale.X, t.scale.Y) m.Rotate(t.rotation) m.Translate(t.position.X, t.position.Y) t.parentMatrice = m mi = m mi.Invert() t.parentInverted = mi t.parentDirty = false } else { m = t.parentMatrice mi = t.parentInverted } if t.parent != nil { pm, pmi := t.parent.GetMatriceForParenting() m.Concat(pm) pmi.Concat(mi) mi = pmi } return m, mi } // Returns the GeoM with corresponding // to the transfrom transformation. func (t *Transform) GetMatrice() mx.Matrice { var m, pm mx.Matrice // 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.GetMatriceForParenting() m.Concat(pm) } return m }