1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_TransformNode.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 25178 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/gfx/gfx_TransformNode.h>
19 #include <nw/gfx/gfx_ISceneVisitor.h>
20 
21 #include <nw/ut/ut_ResUtil.h>
22 #include <nw/ut/ut_ResDictionary.h>
23 
24 namespace nw
25 {
26 namespace gfx
27 {
28 
29 NW_UT_RUNTIME_TYPEINFO_DEFINITION(TransformNode, SceneNode);
30 
31 //----------------------------------------
TransformNode(os::IAllocator * allocator,ResTransformNode resObj,const TransformNode::Description & description)32 TransformNode::TransformNode(
33     os::IAllocator* allocator,
34     ResTransformNode resObj,
35     const TransformNode::Description& description)
36 : SceneNode(allocator, resObj, description),
37     m_InverseWorldMatrix(math::MTX34::Identity()),
38     m_IsInverseWorldMatrixValid(false),
39     m_PostCalculateWorldMatrixSignal(NULL),
40     m_IsBranchWorldMatrixCalculationEnabled(true),
41     m_Description(description)
42 {
43     if (resObj.IsValid())
44     {
45         this->m_Transform.SetTransform(resObj.GetTransform());
46         this->m_WorldMatrix = resObj.GetWorldMatrix();
47     }
48     else
49     {
50         math::MTX34Identity(&this->m_WorldMatrix);
51     }
52 }
53 
54 //----------------------------------------
55 TransformNode*
Create(os::IAllocator * allocator)56 TransformNode::DynamicBuilder::Create(
57     os::IAllocator* allocator
58 )
59 {
60     NW_NULL_ASSERT(allocator);
61 
62     void* memory = allocator->Alloc(sizeof(TransformNode));
63     NW_NULL_ASSERT(memory);
64 
65     TransformNode* node = new(memory) TransformNode(
66         allocator,
67         ResTransformNode(),
68         m_Description);
69 
70     Result result = node->Initialize(allocator);
71 
72     NW_ASSERT(result.IsSuccess());
73 
74     return node;
75 }
76 
77 //----------------------------------------
78 TransformNode*
Create(SceneNode * parent,ResSceneObject resource,const TransformNode::Description & description,os::IAllocator * allocator)79 TransformNode::Create(
80     SceneNode* parent,
81     ResSceneObject resource,
82     const TransformNode::Description& description,
83     os::IAllocator* allocator
84 )
85 {
86     NW_NULL_ASSERT(allocator);
87 
88     ResTransformNode resNode = ResStaticCast<ResTransformNode>(resource);
89 
90     void* memory = allocator->Alloc(sizeof(TransformNode));
91     NW_NULL_ASSERT(memory);
92 
93     TransformNode* node = new(memory) TransformNode(
94         allocator,
95         resNode,
96         description);
97 
98     Result result = node->Initialize(allocator);
99 
100     NW_ASSERT(result.IsSuccess());
101 
102     if (parent)
103     {
104         bool isAttached = parent->AttachChild(node);
105         NW_ASSERT(isAttached);
106     }
107     return node;
108 }
109 
110 
111 //----------------------------------------
112 Result
CreateCallbacks(os::IAllocator * allocator)113 TransformNode::CreateCallbacks(os::IAllocator* allocator)
114 {
115     Result result = INITIALIZE_RESULT_OK;
116 
117     if (m_Description.isFixedSizeMemory)
118     {
119         if (m_Description.maxCallbacks == 0)
120         {
121             m_PostCalculateWorldMatrixSignal =
122                 CalculateMatrixSignal::CreateInvalidateSignal(allocator);
123         }
124         else
125         {
126             m_PostCalculateWorldMatrixSignal =
127                 CalculateMatrixSignal::CreateFixedSizedSignal(m_Description.maxCallbacks, allocator);
128         }
129     }
130     else
131     {
132         m_PostCalculateWorldMatrixSignal =
133             CalculateMatrixSignal::CreateVariableSizeSignal(allocator);
134     }
135 
136     // 動的配列のメモリ確保に失敗した場合
137     if (m_PostCalculateWorldMatrixSignal == NULL)
138     {
139         result |= Result::MASK_FAIL_BIT;
140     }
141 
142     return result;
143 }
144 
145 //----------------------------------------
146 void
Accept(ISceneVisitor * visitor)147 TransformNode::Accept(
148     ISceneVisitor* visitor
149 )
150 {
151     visitor->VisitTransformNode(this);
152     AcceptChildren(visitor);
153 }
154 
155 //----------------------------------------
156 const math::MTX34&
InverseWorldMatrix() const157 TransformNode::InverseWorldMatrix() const
158 {
159     if (!m_IsInverseWorldMatrixValid)
160     {
161         NW_FAILSAFE_IF(math::MTX34Inverse(&m_InverseWorldMatrix, m_WorldMatrix) == 0)
162         {
163             m_InverseWorldMatrix = math::MTX34::Identity();
164         }
165 
166         m_IsInverseWorldMatrixValid = true;
167     }
168 
169     return m_InverseWorldMatrix;
170 }
171 
172 //----------------------------------------
173 void
InvalidateInverseWorldMatrix()174 TransformNode::InvalidateInverseWorldMatrix()
175 {
176     m_IsInverseWorldMatrixValid = false;
177 }
178 
179 //----------------------------------------
180 void
UpdateTransform(WorldMatrixUpdater * worldMatrixUpdater,SceneContext * sceneContext)181 TransformNode::UpdateTransform(
182     WorldMatrixUpdater* worldMatrixUpdater,
183     SceneContext* sceneContext)
184 {
185     // CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED を 0 にしたときでもコールバックは呼ばれます。
186     if (this->Transform().IsEnabledFlags(CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED))
187     {
188         // Transform に設定された Dirty フラグを参照して計算をスキップする
189         if (this->IsEnabledResults(SceneNode::FLAG_IS_DIRTY))
190         {
191             const CalculatedTransform* parentWorldTransform;
192             const CalculatedTransform* parentLocalTransform;
193 
194             if (this->GetParent() == NULL)
195             {
196                 parentWorldTransform = &CalculatedTransform::Identity();
197                 parentLocalTransform = &CalculatedTransform::Identity();
198             }
199             else
200             {
201                 parentWorldTransform = &this->GetParent()->TrackbackWorldTransform();
202                 parentLocalTransform = &this->GetParent()->TrackbackLocalTransform();
203             }
204 
205             worldMatrixUpdater->UpdateBasic(
206                 &this->WorldMatrix(),
207                 &this->WorldTransform(),
208                 this->Transform(),
209                 *parentWorldTransform,
210                 *parentLocalTransform);
211 
212             this->InvalidateInverseWorldMatrix();
213         }
214     }
215     else
216     {
217         // FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED は計算済みとして扱うので
218         // 継承用の Dirty フラグを 0 にしておく。
219         this->DisableTraversalResults(SceneNode::FLAG_IS_DIRTY);
220     }
221 
222     this->UpdateDirection();
223 
224     // Dirty フラグを 0 にする。
225     this->Transform().DisableFlags(CalculatedTransform::FLAG_IS_DIRTY);
226 
227     this->PostCalculateWorldMatrixSignal()(this, sceneContext);
228 }
229 
230 
231 //----------------------------------------
232 Result
Initialize(os::IAllocator * allocator)233 TransformNode::Initialize(os::IAllocator* allocator)
234 {
235     Result result = INITIALIZE_RESULT_OK;
236 
237     result |= SceneNode::Initialize(allocator);
238     NW_ENSURE_AND_RETURN(result);
239 
240     result |= CreateCallbacks(allocator);
241     NW_ENSURE_AND_RETURN(result);
242 
243     return result;
244 }
245 
246 } // namespace gfx
247 } // namespace nw
248