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