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