1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_TransformNode.h
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: 30175 $
14 *---------------------------------------------------------------------------*/
15
16 #ifndef NW_GFX_TRANSFORMNODE_H_
17 #define NW_GFX_TRANSFORMNODE_H_
18
19 #include <nw/gfx/gfx_SceneNode.h>
20
21 #include <nw/gfx/gfx_CalculatedTransform.h>
22
23 namespace nw
24 {
25 namespace gfx
26 {
27
28 //---------------------------------------------------------------------------
29 //! @brief 変換情報を持つシーンノードを表すクラスです。
30 //---------------------------------------------------------------------------
31 class TransformNode : public SceneNode
32 {
33 private:
34 NW_DISALLOW_COPY_AND_ASSIGN(TransformNode);
35
36 public:
37 NW_UT_RUNTIME_TYPEINFO;
38
39 //! @brief マトリクス計算時に呼ばれるコールバック用シグナルの定義です。
40 //!
41 //! @sa PostCalculateWorldMatrixSignal
42 typedef ut::Signal2<void, TransformNode*, SceneContext*> CalculateMatrixSignal;
43
44 //! @brief マトリクス計算時に呼ばれるコールバック用スロットの定義です。
45 typedef CalculateMatrixSignal::SlotType CalculateMatrixSlot;
46
47 //! @brief 設定内容です。
48 struct Description : public SceneNode::Description
49 {
50 //! @brief コンストラクタです。
DescriptionDescription51 Description(){}
52 };
53
54 //----------------------------------------
55 //! @name 作成/破棄
56 //@{
57
58 //! @brief トランスフォームノードを動的に構築するためのクラスです。
59 //!
60 //! IsFixedSizeMemory の初期値は true です。false に変更すると、各種最大数の設定は無視されます。
61 class DynamicBuilder
62 {
63 public:
64 //! @brief コンストラクタです。
DynamicBuilder()65 DynamicBuilder() {}
66 //! @brief デストラクタです。
~DynamicBuilder()67 ~DynamicBuilder() {}
68
69 //! @brief 生成時以外にもメモリを確保するかどうかのフラグを設定します。
70 //!
71 //! true を指定すると、生成時のみ固定サイズのメモリ確保を行います。
72 //!
73 //! false を指定すると、生成時以外にも必要に応じて動的にメモリ確保が行われます。
IsFixedSizeMemory(bool isFixedSizeMemory)74 DynamicBuilder& IsFixedSizeMemory(bool isFixedSizeMemory)
75 {
76 m_Description.isFixedSizeMemory = isFixedSizeMemory;
77 return *this;
78 }
79
80 //! @brief 子の最大数を設定します。
MaxChildren(int maxChildren)81 DynamicBuilder& MaxChildren(int maxChildren)
82 {
83 m_Description.maxChildren = maxChildren;
84 return *this;
85 }
86
87 //! @brief 管理できるコールバックの最大数を設定します。
MaxCallbacks(int maxCallbacks)88 DynamicBuilder& MaxCallbacks(int maxCallbacks)
89 {
90 m_Description.maxCallbacks = maxCallbacks;
91 return *this;
92 }
93
94 //! @brief トランスフォームノードを生成します。
95 //!
96 //! @param[in] allocator アロケータです。
97 //!
98 //! @return 生成したトランスフォームノードを返します。
99 //!
100 TransformNode* Create(os::IAllocator* allocator);
101
102 //! @brief 生成時に必要なメモリサイズを取得します。
103 //!
104 //! メモリサイズは Builder の設定によって変化します。
105 //! すべての設定が終わった後にこの関数を呼び出してください。
106 //!
107 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
108 size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
109 {
110 os::MemorySizeCalculator size(alignment);
111
112 size += sizeof(TransformNode);
113 GetMemorySizeForInitialize(&size, ResTransformNode(), m_Description);
114
115 return size.GetSizeWithPadding(alignment);
116 }
117
118 private:
119 TransformNode::Description m_Description;
120 };
121
122 //! @brief リソースからトランスフォームノードを生成します。
123 //!
124 //! @param[in] parent 親のノードです。
125 //! @param[in] resource リソースです。
126 //! @param[in] description 設定内容です。
127 //! @param[in] allocator アロケータです。
128 //!
129 //! @return 生成されたトランスフォームノードです。
130 //!
131 static TransformNode* Create(
132 SceneNode* parent,
133 ResSceneObject resource,
134 const TransformNode::Description& description,
135 os::IAllocator* allocator);
136
137 //! @brief 生成時に必要なメモリサイズを取得します。
138 //!
139 //! @param[in] resTransformNode リソースです。
140 //! @param[in] description 設定内容です。
141 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
142 static size_t GetMemorySize(
143 ResTransformNode resTransformNode,
144 Description description,
145 size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
146 {
147 os::MemorySizeCalculator size(alignment);
148
149 GetMemorySizeInternal(&size, resTransformNode, description);
150
151 return size.GetSizeWithPadding(alignment);
152 }
153
154 //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResTransformNode resTransformNode,Description description)155 static void GetMemorySizeInternal(
156 os::MemorySizeCalculator* pSize,
157 ResTransformNode resTransformNode,
158 Description description)
159 {
160 os::MemorySizeCalculator& size = *pSize;
161
162 size += sizeof(TransformNode);
163 GetMemorySizeForInitialize(pSize, resTransformNode, description);
164 }
165
166 //@}
167
168 //----------------------------------------
169 //! @name リソース
170 //@{
171
172 //! @brief トランスフォームノードのリソースを取得します。
GetResTransformNode()173 ResTransformNode GetResTransformNode()
174 {
175 return ResStaticCast<ResTransformNode>( this->GetResSceneObject() );
176 }
177
178 //! @brief トランスフォームノードのリソースを取得します。
GetResTransformNode()179 const ResTransformNode GetResTransformNode() const
180 {
181 return ResStaticCast<ResTransformNode>( this->GetResSceneObject() );
182 }
183
184 //@}
185
186 //----------------------------------------
187 //! @name トランスフォーム
188 //@{
189
190 //! @brief 変換情報を取得します。
Transform()191 CalculatedTransform& Transform() { return m_Transform; }
192
193 //! @brief 変換情報を取得します。
Transform()194 const CalculatedTransform& Transform() const { return m_Transform; }
195
196 //! @brief ワールドマトリクスを取得します。
WorldMatrix()197 math::MTX34& WorldMatrix() { return m_WorldMatrix; }
198
199 //! @brief ワールドマトリクスを取得します。
WorldMatrix()200 const math::MTX34& WorldMatrix() const { return m_WorldMatrix; }
201
202 //! @brief WorldMatrix 計算後の詳細な変換情報を取得します。
203 //!
WorldTransform()204 CalculatedTransform& WorldTransform() { return m_CalculatedTransform; }
205
206 //! @brief WorldMatrix 計算後の詳細な変換情報を取得します。
207 //! TransformMatrix にはこのノードの Rotate と Translate に親ノードまでの Scale が掛かっています。
208 //! Scale は親ノードまでの累積のスケールとなります。
WorldTransform()209 const CalculatedTransform& WorldTransform() const { return m_CalculatedTransform; }
210
211 //! @brief ワールド行列の逆行列を取得します。2回目以降は、キャッシュを利用します。
212 const math::MTX34& InverseWorldMatrix() const;
213
214 //! @brief ワールド行列の逆行列のキャッシュを無効化します。(ワールド行列を更新する際に呼び出します。)
215 void InvalidateInverseWorldMatrix();
216
217 //! @brief 方向情報を更新します。
UpdateDirection()218 virtual void UpdateDirection() {}
219
220 //! @brief 変換情報に関する更新を行います。
221 //!
222 //! @param[in] worldMatrixUpdater ワールドマトリクス更新クラスです。
223 //! @param[in] sceneContext シーンコンテキストです。
224 //!
225 virtual void UpdateTransform(
226 WorldMatrixUpdater* worldMatrixUpdater,
227 SceneContext* sceneContext);
228
229 //! @brief リソースの持つトランスフォーム情報を基準にトランスフォームを設定します。
230 //!
231 //! リソースの持つトランスフォーム情報を表す変換行列に、引数で与えられた変換行列を乗じ、
232 //! その結果をノードに設定します。
233 //! transformMatrix はスケール成分を含むことができません。
234 //!
235 //! この関数は実行毎にリソースのトランスフォーム情報から行列を生成するので
236 //! パフォーマンスに注意してください。
237 //!
238 //! @param[in] transformMatrix 合成する変換行列です。
239 //! @param[in] scale スケールです。
240 void SetResourceBasedTransform(
241 const math::MTX34& transformMatrix,
242 const math::VEC3& scale = math::VEC3(1.0f, 1.0f, 1.0f)
243 )
244 {
245 math::Transform3& resTransform = GetResTransformNode().GetTransform();
246
247 math::MTX34 resultMatrix;
248 nw::math::MTX34RotXYZRad(&resultMatrix,
249 resTransform.rotate.x,
250 resTransform.rotate.y,
251 resTransform.rotate.z);
252 resultMatrix.f._03 = resTransform.translate.x;
253 resultMatrix.f._13 = resTransform.translate.y;
254 resultMatrix.f._23 = resTransform.translate.z;
255
256 math::MTX34Mult(&resultMatrix, &transformMatrix, &resultMatrix);
257
258 math::VEC3 resultScale;
259 math::VEC3Mult(&resultScale, &scale, &resTransform.scale);
260
261 m_Transform.SetTransformMatrix(resultMatrix);
262 m_Transform.SetScale(resultScale);
263 m_Transform.UpdateFlagsStrictly();
264 }
265
266 //! @brief リソースの持つトランスフォーム情報を基準にトランスフォームを設定します。
267 //!
268 //! リソースの持つトランスフォーム情報を表す変換行列に、引数で与えられた変換行列を乗じ、
269 //! その結果をノードに設定します。
270 //!
271 //! SetResourceBasedTransform() と異なり、行列にスケールを含むことができますが、
272 //! 内部でスケールの分離処理を行なうのでパフォーマンスに注意してください。
273 //!
274 //! @param[in] transformMatrix 合成する変換行列です。
SetResourceScaledTransform(const math::MTX34 & transformMatrix)275 void SetResourceScaledTransform(const math::MTX34& transformMatrix)
276 {
277 math::VEC3 scale;
278 math::MTX34 matrix;
279 nw::math::MTX34DecomposeToColumnScale(&scale, &transformMatrix);
280
281 NW_ASSERT(scale.x > 0 && scale.y > 0 && scale.z > 0);
282
283 matrix.f._00 = transformMatrix.f._00 / scale.x;
284 matrix.f._10 = transformMatrix.f._10 / scale.x;
285 matrix.f._20 = transformMatrix.f._20 / scale.x;
286 matrix.f._01 = transformMatrix.f._01 / scale.y;
287 matrix.f._11 = transformMatrix.f._11 / scale.y;
288 matrix.f._21 = transformMatrix.f._21 / scale.y;
289 matrix.f._02 = transformMatrix.f._02 / scale.z;
290 matrix.f._12 = transformMatrix.f._12 / scale.z;
291 matrix.f._22 = transformMatrix.f._22 / scale.z;
292 matrix.f._03 = transformMatrix.f._03;
293 matrix.f._13 = transformMatrix.f._13;
294 matrix.f._23 = transformMatrix.f._23;
295
296 SetResourceBasedTransform(matrix, scale);
297 }
298
299 //@}
300
301 //----------------------------------------
302 //! @name シーンツリー
303 //@{
304
305 //! @brief ビジターを受け付けます。
306 //!
307 //! @param[in] visitor ビジターです。
308 //!
309 virtual void Accept(ISceneVisitor* visitor);
310
311 //! @brief 親ノードをたどりワールドマトリクスを取得します。
TrackbackWorldMatrix()312 virtual const math::MTX34& TrackbackWorldMatrix() const
313 {
314 return this->WorldMatrix();
315 }
316
317 //! @brief 親ノードをたどりワールドトランスフォームを取得します。
TrackbackWorldTransform()318 virtual const CalculatedTransform& TrackbackWorldTransform() const
319 {
320 return this->WorldTransform();
321 }
322
323 //! @brief 親ノードをたどりローカルトランスフォームを取得します。
TrackbackLocalTransform()324 virtual const CalculatedTransform& TrackbackLocalTransform() const
325 {
326 return this->Transform();
327 }
328
329 //! @brief 親ノードから変換情報を継承します。
330 NW_INLINE virtual void InheritTraversalResults();
331
332 //@}
333
334 //----------------------------------------
335 //! @name コールバック
336 //@{
337
338 //! @brief ワールドマトリクス計算後のシグナルを取得します。
339 //!
340 //! @sa CalculateMatrixSignal
PostCalculateWorldMatrixSignal()341 CalculateMatrixSignal& PostCalculateWorldMatrixSignal()
342 {
343 return *m_PostCalculateWorldMatrixSignal;
344 }
345
346 //! @brief ワールドマトリクス計算後のシグナルを取得します。
347 //!
348 //! @sa CalculateMatrixSignal
PostCalculateWorldMatrixSignal()349 const CalculateMatrixSignal& PostCalculateWorldMatrixSignal() const
350 {
351 return *m_PostCalculateWorldMatrixSignal;
352 }
353
354 //@}
355
356 protected:
357 //----------------------------------------
358 //! @name コンストラクタ/デストラクタ
359 //@{
360
361 //! @brief コンストラクタです。
362 TransformNode(
363 os::IAllocator* allocator,
364 ResTransformNode resObj,
365 const TransformNode::Description& description);
366
367 //! @brief デストラクタです。
~TransformNode()368 virtual ~TransformNode()
369 {
370 SafeDestroy(m_PostCalculateWorldMatrixSignal);
371 }
372
373 virtual Result Initialize(os::IAllocator* allocator);
374
375 //@}
376
377 //! @brief 親ノードの変換情報を継承した方向を計算します。
CalcInheritingDiretion(math::VEC3 & inheritingDirection,const math::VEC3 & direction)378 void CalcInheritingDiretion(
379 math::VEC3& inheritingDirection,
380 const math::VEC3 &direction) const
381 {
382 if (this->GetParent() == NULL)
383 {
384 inheritingDirection = direction;
385 }
386 else
387 {
388 const math::MTX34& parentWorldMatrix = this->TrackbackWorldMatrix();
389 inheritingDirection.x =
390 parentWorldMatrix.f._00 * direction.x +
391 parentWorldMatrix.f._01 * direction.y +
392 parentWorldMatrix.f._02 * direction.z;
393
394 inheritingDirection.y =
395 parentWorldMatrix.f._10 * direction.x +
396 parentWorldMatrix.f._11 * direction.y +
397 parentWorldMatrix.f._12 * direction.z;
398
399 inheritingDirection.z =
400 parentWorldMatrix.f._20 * direction.x +
401 parentWorldMatrix.f._21 * direction.y +
402 parentWorldMatrix.f._22 * direction.z;
403 }
404 }
405
406
407 //! @brief Initialize() の実行に必要なメモリサイズを取得します。
408 //!
409 //! @details :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,ResTransformNode resTransformNode,Description description)410 static void GetMemorySizeForInitialize(
411 os::MemorySizeCalculator* pSize,
412 ResTransformNode resTransformNode,
413 Description description)
414 {
415 NW_ASSERT(description.isFixedSizeMemory);
416
417 SceneNode::GetMemorySizeForInitialize(pSize, resTransformNode, description);
418
419 // TransformNode::CreateCallbacks
420 if (description.maxCallbacks == 0)
421 {
422 CalculateMatrixSignal::GetMemorySizeForInvalidateSignalInternal(pSize);
423 }
424 else
425 {
426 CalculateMatrixSignal::GetMemorySizeForFixedSizedSignalInternal(pSize, description.maxCallbacks);
427 }
428 }
429
430 private:
431 //! @brief コールバック関数を生成します。
432 Result CreateCallbacks(os::IAllocator* allocator);
433
434 CalculatedTransform m_Transform;
435 math::MTX34 m_WorldMatrix;
436 CalculatedTransform m_CalculatedTransform;
437
438 mutable math::MTX34 m_InverseWorldMatrix;
439 mutable bool m_IsInverseWorldMatrixValid;
440
441 CalculateMatrixSignal* m_PostCalculateWorldMatrixSignal;
442 bool m_IsBranchWorldMatrixCalculationEnabled;
443 Description m_Description;
444 };
445
446 //----------------------------------------
447 NW_INLINE void
InheritTraversalResults()448 TransformNode::InheritTraversalResults()
449 {
450 SceneNode::InheritTraversalResults();
451
452 SceneNode* parent = this->GetParent();
453 bit32 results = this->GetTraversalResults();
454
455 if (this->Transform().IsEnabledFlags(CalculatedTransform::FLAG_IS_DIRTY))
456 {
457 results = ut::EnableFlag(results, SceneNode::FLAG_IS_DIRTY);
458 }
459 else if (parent== NULL)
460 {
461 results = ut::DisableFlag(results, SceneNode::FLAG_IS_DIRTY);
462 }
463 else if (parent->IsEnabledResults(SceneNode::FLAG_IS_DIRTY))
464 {
465 results = ut::EnableFlag(results, SceneNode::FLAG_IS_DIRTY);
466 }
467 else
468 {
469 results = ut::DisableFlag(results, SceneNode::FLAG_IS_DIRTY);
470 }
471
472 this->SetTraversalResults(results);
473 }
474
475 } // namespace gfx
476 } // namespace nw
477
478 #endif // NW_GFX_TRANSFORMNODE_H_
479