/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "core/item.h" #include "geometry/bounding_box.h" #include "log/log.h" using namespace GS; using namespace GS::Core; //------------------------------------------------------------------------------ Matrix4 Item::GetMatrixNoPivot() { Matrix4 p = GetPivot(); SetPivot(Matrix4::IdentityMatrix()); Matrix4 m = GetMatrix(); SetPivot(p); return m; } void Item::ComputeLocalMatrix() { if (!item_flags.IsSet(ItemFlagLocalMatrixDirty)) return; if (!item_flags.IsSet(ItemFlagHasTarget) && item_flags.IsSet(ItemFlagRotationMatrixDirty)) { rotation_matrix = Matrix3::FromEuler(rotation.x, rotation.y, rotation.z, rorder); item_flags.Remove(ItemFlagRotationMatrixDirty); } local_matrix = ( Matrix4::TranslationMatrix(position) * Matrix4::FromMatrix3(rotation_matrix) * Matrix4::ScaleMatrix(scale) ) * pivot_matrix; item_flags.Remove(ItemFlagLocalMatrixDirty); } void Item::ComputeMatrix() { bool update_local = item_flags.IsSet(ItemFlagLocalMatrixDirty), update_world = item_flags.IsSet(ItemFlagWorldMatrixDirty); if (update_local) ComputeLocalMatrix(); if (!parent) { if (update_world) matrix = local_matrix; } else if (update_world) { matrix = parent->GetMatrix() * local_matrix; if (item_flags.IsSet(ItemFlagInheritPositionOnly)) { Matrix4 m(Matrix4::FromMatrix3(rotation_matrix)); m.SetRow(3, matrix.GetRow(3)); matrix = m; } } /// Handle item target and scale. if (update_local || update_world) if (item_flags.IsSet(ItemFlagHasTarget)) { matrix.Decompose(NULL, NULL, &rotation_matrix); Matrix3 tgtm = Matrix3::FromOrthonormalBasis(target - matrix.GetRow(3)); matrix = matrix * Matrix4::FromMatrix3(rotation_matrix.Transposed() * tgtm); rotation_matrix = tgtm; } item_flags.Remove(ItemFlagWorldMatrixDirty); } void Item::ComputeInverseMatrix() { if (item_flags.IsSet(ItemFlagInverseWorldMatrixDirty)) { imatrix = GetMatrix().InversedFast(); item_flags.Remove(ItemFlagInverseWorldMatrixDirty); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void Item::MarkWorldTransformationDirty() { item_flags.Set(ItemFlagWorldMatrixDirty | ItemFlagInverseWorldMatrixDirty); ListForeachPtr(Item *, i, children) i->MarkWorldTransformationDirty(); } void Item::MarkTransformationDirty(bool child_only) { if (!child_only) item_flags.Set(ItemFlagLocalMatrixDirty | ItemFlagWorldMatrixDirty | ItemFlagInverseWorldMatrixDirty); ListForeachPtr(Item *, i, children) i->MarkWorldTransformationDirty(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void Item::SetPosition(const Vector4 &p) { position = p; MarkTransformationDirty(); } const Vector4 &Item::GetPosition() const { return position; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void Item::SetRotation(const Vector4 &r) { rotation = r; item_flags.Set(ItemFlagRotationMatrixDirty); MarkTransformationDirty(); } void Item::SetRotation(const Quaternion &q) { rotation_matrix = q.AsMatrix3(); item_flags.Remove(ItemFlagRotationMatrixDirty); rotation = rotation_matrix.AsEuler(GetRotationOrder()); MarkTransformationDirty(); } void Item::SetRotation(const Matrix3 &m) { rotation_matrix = m; item_flags.Remove(ItemFlagRotationMatrixDirty); rotation = rotation_matrix.AsEuler(GetRotationOrder()); MarkTransformationDirty(); } const Vector4 &Item::GetRotation() const { return rotation; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void Item::SetScale(const Vector4 &s) { scale = s; MarkTransformationDirty(); } const Vector4 &Item::GetScale() const { return scale; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void Item::SetPivot(const Matrix4 &m) { pivot_matrix = m; MarkTransformationDirty(); } const Matrix4 &Item::GetPivot() const { return pivot_matrix; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ const Matrix4 &Item::GetPreviousMatrix() const { return prv_matrix; } void Item::SetPreviousMatrix(const Matrix4 &mtx) { prv_matrix = mtx; } const Matrix4 &Item::GetLocalMatrix() { ComputeMatrix(); return local_matrix; } const Matrix4 &Item::GetMatrix() { ComputeMatrix(); return matrix; } const Matrix4 &Item::GetInverseMatrix() { ComputeInverseMatrix(); return imatrix; } const Matrix3 &Item::GetRotationMatrix() { ComputeMatrix(); return rotation_matrix; } //------------------------------------------------------------------------------ //------------------------------------------------------------------- void Item::OffsetWorldPosition(const Vector4 &offset) //------------------------------------------------------------------- { if (parent) position += (matrix.GetRow(3) + offset) * parent->imatrix - matrix.GetRow(3) * parent->imatrix; else position += offset; MarkTransformationDirty(); } //------------------------------------------------ bool Item::IsLinkedTo(Item *item) //------------------------------------------------ { for (Item *c = this; c; ) { if (c == item) return true; c = c->GetParent(); } return false; } //------------------------------------------------------------------ void Item::ComputeLocalMinMax(MinMax &minmax) const //------------------------------------------------------------------ { Vector4 w_position = matrix.GetRow(3); minmax.Set(w_position, w_position); } //------------------------------------------------------------------------------------------------ void Item::SnapshotTransformation(const Matrix4 &m, bool local, bool only_matrix) //------------------------------------------------------------------------------------------------ { local_matrix = (parent && !local) ? parent->GetInverseMatrix() * m : m; item_flags.Remove(ItemFlagLocalMatrixDirty); if (!only_matrix) { // Remove pivot before extracting transformation components. (local_matrix * pivot_matrix.InversedFast()).Decompose(&position, &scale, &rotation_matrix); rotation = rotation_matrix.AsEuler(rorder); item_flags.Remove(ItemFlagRotationMatrixDirty); } MarkWorldTransformationDirty(); } //-------------------------------------------- void Item::SetParent(Item *p) //-------------------------------------------- { if (p == this) __ERRRAW__(__LOG_E__ << "Cannot parent item to itself.\n") // Already linked. if (p && p->children.Find(this)) // FIXME why not if (parent == i)??? return; // Catch and correct deadlock. for (Item *c = p; c; c = c->GetParent()) if (c->GetParent() && (c->GetParent() == this)) { c->SetParent(GetParent()); // Extract 'this' from the parent chain. __LOG_W__ << "Deadlock detected, link chain has been corrected.\n"; break; } // Remove from current parent children list. if (parent) parent->children.Remove(this); // Set parent. parent = p; // Insert as a new parent child. if (parent) parent->children.Add(this); MarkTransformationDirty(); } //---------------------------------------------------- void Item::SetTarget(const Vector4 *p) //---------------------------------------------------- { if (p) { item_flags.Set(ItemFlagHasTarget); target = *p; } else item_flags.Remove(ItemFlagHasTarget); MarkTransformationDirty(); } //----------------------------------------------------- void Item::SetMatrix(const Matrix4 &m) //----------------------------------------------------- { SnapshotTransformation(m, false); matrix = m; imatrix = m.InversedFast(); item_flags.Remove(ItemFlagWorldMatrixDirty | ItemFlagInverseWorldMatrixDirty); MarkTransformationDirty(true); } //-------------------------------------------------------------- void Item::SetRotationOrder(Math::rOrder order) //-------------------------------------------------------------- { rorder = order; MarkTransformationDirty(); } //------------------------------------------------------------------------------ Item::Item() : position(0, 0, 0), rotation(0, 0, 0), scale(1, 1, 1) { local_matrix = Matrix4::IdentityMatrix(); prv_matrix = Matrix4::IdentityMatrix(); matrix = Matrix4::IdentityMatrix(); imatrix = Matrix4::IdentityMatrix(); pivot_matrix = Matrix4::IdentityMatrix(); parent = NULL; rorder = Math::rOrder_Default; scale.Set(1,1,1,1); mitem = NULL; target.Set(0, 0, 1); opacity = 1; MarkTransformationDirty(); item_flags.Set(ItemFlagRotationMatrixDirty); } Item::~Item() { ListForeachPtr(Item *, child, children) child->SetParent(NULL); SetParent(NULL); } //------------------------------------------------------------------------------