/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_TransformNode.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 25178 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include namespace nw { namespace gfx { NW_UT_RUNTIME_TYPEINFO_DEFINITION(TransformNode, SceneNode); //---------------------------------------- TransformNode::TransformNode( os::IAllocator* allocator, ResTransformNode resObj, const TransformNode::Description& description) : SceneNode(allocator, resObj, description), m_InverseWorldMatrix(math::MTX34::Identity()), m_IsInverseWorldMatrixValid(false), m_PostCalculateWorldMatrixSignal(NULL), m_IsBranchWorldMatrixCalculationEnabled(true), m_Description(description) { if (resObj.IsValid()) { this->m_Transform.SetTransform(resObj.GetTransform()); this->m_WorldMatrix = resObj.GetWorldMatrix(); } else { math::MTX34Identity(&this->m_WorldMatrix); } } //---------------------------------------- TransformNode* TransformNode::DynamicBuilder::Create( os::IAllocator* allocator ) { NW_NULL_ASSERT(allocator); void* memory = allocator->Alloc(sizeof(TransformNode)); NW_NULL_ASSERT(memory); TransformNode* node = new(memory) TransformNode( allocator, ResTransformNode(), m_Description); Result result = node->Initialize(allocator); NW_ASSERT(result.IsSuccess()); return node; } //---------------------------------------- TransformNode* TransformNode::Create( SceneNode* parent, ResSceneObject resource, const TransformNode::Description& description, os::IAllocator* allocator ) { NW_NULL_ASSERT(allocator); ResTransformNode resNode = ResStaticCast(resource); void* memory = allocator->Alloc(sizeof(TransformNode)); NW_NULL_ASSERT(memory); TransformNode* node = new(memory) TransformNode( allocator, resNode, description); Result result = node->Initialize(allocator); NW_ASSERT(result.IsSuccess()); if (parent) { bool isAttached = parent->AttachChild(node); NW_ASSERT(isAttached); } return node; } //---------------------------------------- Result TransformNode::CreateCallbacks(os::IAllocator* allocator) { Result result = INITIALIZE_RESULT_OK; if (m_Description.isFixedSizeMemory) { if (m_Description.maxCallbacks == 0) { m_PostCalculateWorldMatrixSignal = CalculateMatrixSignal::CreateInvalidateSignal(allocator); } else { m_PostCalculateWorldMatrixSignal = CalculateMatrixSignal::CreateFixedSizedSignal(m_Description.maxCallbacks, allocator); } } else { m_PostCalculateWorldMatrixSignal = CalculateMatrixSignal::CreateVariableSizeSignal(allocator); } // 動的配列のメモリ確保に失敗した場合 if (m_PostCalculateWorldMatrixSignal == NULL) { result |= Result::MASK_FAIL_BIT; } return result; } //---------------------------------------- void TransformNode::Accept( ISceneVisitor* visitor ) { visitor->VisitTransformNode(this); AcceptChildren(visitor); } //---------------------------------------- const math::MTX34& TransformNode::InverseWorldMatrix() const { if (!m_IsInverseWorldMatrixValid) { NW_FAILSAFE_IF(math::MTX34Inverse(&m_InverseWorldMatrix, m_WorldMatrix) == 0) { m_InverseWorldMatrix = math::MTX34::Identity(); } m_IsInverseWorldMatrixValid = true; } return m_InverseWorldMatrix; } //---------------------------------------- void TransformNode::InvalidateInverseWorldMatrix() { m_IsInverseWorldMatrixValid = false; } //---------------------------------------- void TransformNode::UpdateTransform( WorldMatrixUpdater* worldMatrixUpdater, SceneContext* sceneContext) { // CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED を 0 にしたときでもコールバックは呼ばれます。 if (this->Transform().IsEnabledFlags(CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED)) { // Transform に設定された Dirty フラグを参照して計算をスキップする if (this->IsEnabledResults(SceneNode::FLAG_IS_DIRTY)) { const CalculatedTransform* parentWorldTransform; const CalculatedTransform* parentLocalTransform; if (this->GetParent() == NULL) { parentWorldTransform = &CalculatedTransform::Identity(); parentLocalTransform = &CalculatedTransform::Identity(); } else { parentWorldTransform = &this->GetParent()->TrackbackWorldTransform(); parentLocalTransform = &this->GetParent()->TrackbackLocalTransform(); } worldMatrixUpdater->UpdateBasic( &this->WorldMatrix(), &this->WorldTransform(), this->Transform(), *parentWorldTransform, *parentLocalTransform); this->InvalidateInverseWorldMatrix(); } } else { // FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED は計算済みとして扱うので // 継承用の Dirty フラグを 0 にしておく。 this->DisableTraversalResults(SceneNode::FLAG_IS_DIRTY); } this->UpdateDirection(); // Dirty フラグを 0 にする。 this->Transform().DisableFlags(CalculatedTransform::FLAG_IS_DIRTY); this->PostCalculateWorldMatrixSignal()(this, sceneContext); } //---------------------------------------- Result TransformNode::Initialize(os::IAllocator* allocator) { Result result = INITIALIZE_RESULT_OK; result |= SceneNode::Initialize(allocator); NW_ENSURE_AND_RETURN(result); result |= CreateCallbacks(allocator); NW_ENSURE_AND_RETURN(result); return result; } } // namespace gfx } // namespace nw