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