1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_CalculatedTransform.h
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 #ifndef NW_GFX_CALCULATED_TRANSFORM_H_
19 #define NW_GFX_CALCULATED_TRANSFORM_H_
20 
21 #include <nw/ut/ut_Flag.h>
22 #include <nw/gfx/gfx_Common.h>
23 #include <nw/types.h>
24 #include <nw/assert.h>
25 #include <nw/gfx/res/gfx_ResSkeleton.h>
26 
27 namespace nw {
28 namespace gfx {
29 #define NN_MATH_USE_ANONYMOUS_STRUCT
30 
31 //---------------------------------------------------------------------------
32 //! @brief        計算済みトランスフォームを表すクラスです。
33 //---------------------------------------------------------------------------
34 class CalculatedTransform
35 {
36 public:
37     //! ゼロベクトルを判定する境界値です。
38     //!
39     //! :private
40     static const f32 s_VecSquareLenTol;
41 
42     //----------------------------------------
43     //! @name 定数定義
44     //@{
45 
46     //! 変換情報についての付加情報ビットフラグの定義です。
47     enum Flag
48     {
49         // NOTE: CreativeStudio側の、Graphics.Scenes.CalculatedTransform.csで定義されているフラグは、
50         //       ここで定義されているものと一致していることが期待されます。
51         //       ビットシフトがずれたりした場合は、両方とも同じように変更してください。
52 
53         //! @details :private
54         FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED_SHIFT           = 0,
55         //! @details :private
56         FLAG_IS_VALID_SHIFT                                     = 1,
57         //! @details :private
58         FLAG_IS_IGNORE_TRANSLATE_SHIFT                          = 2,
59         //! @details :private
60         FLAG_IS_IGNORE_SCALE_SHIFT                              = 3,
61         //! @details :private
62         FLAG_IS_IGNORE_ROTATE_SHIFT                             = 4,
63         //! @details :private
64         FLAG_IS_IDENTITY_SHIFT                                  = 5,
65         //! @details :private
66         FLAG_IS_ROTATE_TRANSLATE_ZERO_SHIFT                     = 6,
67         //! @details :private
68         FLAG_IS_ROTATE_ZERO_SHIFT                               = 7,
69         //! @details :private
70         FLAG_IS_TRANSLATE_ZERO_SHIFT                            = 8,
71         //! @details :private
72         FLAG_IS_SCALE_ONE_SHIFT                                 = 9,
73         //! @details :private
74         FLAG_IS_UNIFORM_SCALE_SHIFT                             = 10,
75         //! @details :private
76         FLAG_IS_DIRTY_SHIFT                                     = 11,
77         //! @details :private
78         FLAG_FORCE_VIEW_CALCULATION_ENABLED_SHIFT               = 12,
79         //! @details :private
80         FLAG_CONVERTED_FOR_BLEND_SHIFT                          = 30,
81 
82         //! ワールドマトリクスの計算処理を行うのであれば、1になります。
83         FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED             = 0x1 << FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED_SHIFT,
84         //! 有効な変換情報であれば、1になります。
85         FLAG_IS_VALID                                       = 0x1 << FLAG_IS_VALID_SHIFT,
86         //! 平行移動計算を無視できるのであれば、1になります。
87         FLAG_IS_IGNORE_TRANSLATE                            = 0x1 << FLAG_IS_IGNORE_TRANSLATE_SHIFT,
88         //! スケール計算を無視できるのであれば、1になります。
89         FLAG_IS_IGNORE_SCALE                                = 0x1 << FLAG_IS_IGNORE_SCALE_SHIFT,
90         //! 回転計算を無視できるのであれば、1になります。
91         FLAG_IS_IGNORE_ROTATE                               = 0x1 << FLAG_IS_IGNORE_ROTATE_SHIFT,
92         //! 正規化されていれば、1となります。
93         FLAG_IS_IDENTITY                                    = 0x1 << FLAG_IS_IDENTITY_SHIFT,
94         //! 回転と平行移動が0であれば、1となります。
95         FLAG_IS_ROTATE_TRANSLATE_ZERO                       = 0x1 << FLAG_IS_ROTATE_TRANSLATE_ZERO_SHIFT,
96         //! 回転が0であれば、1となります。
97         FLAG_IS_ROTATE_ZERO                                 = 0x1 << FLAG_IS_ROTATE_ZERO_SHIFT,
98         //! 平行移動が0であれば、1となります。
99         FLAG_IS_TRANSLATE_ZERO                              = 0x1 << FLAG_IS_TRANSLATE_ZERO_SHIFT,
100         //! スケール値全てが1であれば、1となります。
101         FLAG_IS_SCALE_ONE                                   = 0x1 << FLAG_IS_SCALE_ONE_SHIFT,
102         //! スケール値全てが均一であれば、1となります。
103         FLAG_IS_UNIFORM_SCALE                               = 0x1 << FLAG_IS_UNIFORM_SCALE_SHIFT,
104         //! 値が変更されれば、1となります。
105         FLAG_IS_DIRTY                                       = 0x1 << FLAG_IS_DIRTY_SHIFT,
106         //! 必ず UpdateView を計算するのであれば、1となります。
107         FLAG_FORCE_VIEW_CALCULATION_ENABLED                 = 0x1 << FLAG_FORCE_VIEW_CALCULATION_ENABLED_SHIFT,
108         //! アニメーションブレンド用の空間に変換されていれば、1になります。
109         FLAG_CONVERTED_FOR_BLEND                            = 0x1 << FLAG_CONVERTED_FOR_BLEND_SHIFT,
110 
111         //! 計算の無視を制御するフラグ群です。
112         FLAG_IS_IGNORE_ALL = FLAG_IS_IGNORE_SCALE | FLAG_IS_IGNORE_ROTATE | FLAG_IS_IGNORE_TRANSLATE,
113 
114         //! ビットフラグの初期値です。
115         FLAG_DEFAULT = FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED | FLAG_IS_DIRTY
116     };
117 
118     //! @brief 単位行列を取得します。
Identity()119     static const CalculatedTransform& Identity()
120     {
121         static const CalculatedTransform identity(
122             FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED |
123             FLAG_IS_IDENTITY |
124             FLAG_IS_ROTATE_TRANSLATE_ZERO |
125             FLAG_IS_ROTATE_ZERO |
126             FLAG_IS_TRANSLATE_ZERO |
127             FLAG_IS_SCALE_ONE |
128             FLAG_IS_UNIFORM_SCALE);
129 
130         return identity;
131     }
132 
133     //@}
134 
135 public:
136     //----------------------------------------
137     //! @name 作成
138     //@{
139 
140     //! コンストラクタです。
CalculatedTransform(bit32 flags)141     CalculatedTransform(bit32 flags)
142     : m_TransformMatrix(math::MTX34::Identity()),
143       m_Scale(1.0f, 1.0f, 1.0f),
144       m_Flags(flags)
145     {
146     }
147 
148     //! コンストラクタです。
CalculatedTransform()149     CalculatedTransform()
150     : m_TransformMatrix(math::MTX34::Identity()),
151       m_Scale(1.0f, 1.0f, 1.0f),
152       m_Flags(FLAG_DEFAULT)
153     {
154     }
155 
156     //! @brief コンストラクタです。
157     //!        内部で Setup を呼び出します。
158     //!
159     //! @param[in] resBone 初期化に用いるボーンです。
160     //!
CalculatedTransform(const ResBone bone)161     CalculatedTransform(const ResBone bone)
162     : m_Flags(FLAG_DEFAULT)
163     {
164         // m_TransformMatrix と m_Scale は Setup で設定されます。
165         Setup(bone);
166     }
167 
168     //! コピーコンストラクタです。
CalculatedTransform(const CalculatedTransform & transform)169     CalculatedTransform(const CalculatedTransform& transform)
170     : m_TransformMatrix(transform.m_TransformMatrix),
171       m_Scale(transform.m_Scale),
172       m_Flags(transform.m_Flags)
173     {
174     }
175 
176 
177     //! @brief リソースボーンから計算済みトランスフォームをセットアップします。
178     //!
179     //! @param[in] bone リソースボーンです。
180     //!
181     void Setup(const ResBone bone);
182 
183     //@}
184 
185     //----------------------------------------
186     //! @name 取得/設定
187     //@{
188 
189     //! @brief 座標変換を表す行列を取得します。
190     //!        更新をした場合、必ず Dirty フラグを設定してください。
DirectTransformMatrix()191     math::MTX34& DirectTransformMatrix() { return this->m_TransformMatrix; }
192 
193     //! @brief 座標変換を表す行列を取得します。
194     //!        自分のスケールは掛かっておらず、親のスケールは掛かっています
195     //!
196     //! @return トランスフォームのマトリクスです。
TransformMatrix()197     const math::MTX34& TransformMatrix() const { return this->m_TransformMatrix; }
198 
199     //! @brief 座標変換を表す行列を設定します。
200     //!        Dirty フラグを設定します。
SetTransformMatrix(const math::MTX34 & transformMatrix)201     void SetTransformMatrix(const math::MTX34& transformMatrix)
202     {
203         math::MTX34Copy(&this->m_TransformMatrix, transformMatrix);
204 
205         this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
206     }
207 
208     //! @brief 座標変換を表す行列を設定します。
209     //!        Dirty フラグを設定します。
SetTransformMatrix(f32 x00,f32 x01,f32 x02,f32 x03,f32 x10,f32 x11,f32 x12,f32 x13,f32 x20,f32 x21,f32 x22,f32 x23)210     void SetTransformMatrix(
211         f32 x00, f32 x01, f32 x02, f32 x03,
212         f32 x10, f32 x11, f32 x12, f32 x13,
213         f32 x20, f32 x21, f32 x22, f32 x23)
214     {
215         this->m_TransformMatrix.f._00 = x00;
216         this->m_TransformMatrix.f._10 = x10;
217         this->m_TransformMatrix.f._20 = x20;
218         this->m_TransformMatrix.f._01 = x01;
219         this->m_TransformMatrix.f._11 = x11;
220         this->m_TransformMatrix.f._21 = x21;
221         this->m_TransformMatrix.f._02 = x02;
222         this->m_TransformMatrix.f._12 = x12;
223         this->m_TransformMatrix.f._22 = x22;
224         this->m_TransformMatrix.f._03 = x03;
225         this->m_TransformMatrix.f._13 = x13;
226         this->m_TransformMatrix.f._23 = x23;
227 
228         this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
229     }
230 
231     //! @brief 回転行列を設定します。
232     //!        Dirty フラグを設定します。
233     template<typename TMatrix>
SetRotateMatrix(const TMatrix & rotateMatrix)234     void SetRotateMatrix(const TMatrix& rotateMatrix)
235     {
236         this->m_TransformMatrix.f._00 = rotateMatrix.f._00;
237         this->m_TransformMatrix.f._10 = rotateMatrix.f._10;
238         this->m_TransformMatrix.f._20 = rotateMatrix.f._20;
239         this->m_TransformMatrix.f._01 = rotateMatrix.f._01;
240         this->m_TransformMatrix.f._11 = rotateMatrix.f._11;
241         this->m_TransformMatrix.f._21 = rotateMatrix.f._21;
242         this->m_TransformMatrix.f._02 = rotateMatrix.f._02;
243         this->m_TransformMatrix.f._12 = rotateMatrix.f._12;
244         this->m_TransformMatrix.f._22 = rotateMatrix.f._22;
245 
246         this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
247     }
248 
249     //! @brief 回転行列を設定します。
250     //!        Dirty フラグを設定します。
SetRotateMatrix(f32 x00,f32 x01,f32 x02,f32 x10,f32 x11,f32 x12,f32 x20,f32 x21,f32 x22)251     void SetRotateMatrix(
252         f32 x00, f32 x01, f32 x02,
253         f32 x10, f32 x11, f32 x12,
254         f32 x20, f32 x21, f32 x22)
255     {
256         this->m_TransformMatrix.f._00 = x00;
257         this->m_TransformMatrix.f._10 = x10;
258         this->m_TransformMatrix.f._20 = x20;
259         this->m_TransformMatrix.f._01 = x01;
260         this->m_TransformMatrix.f._11 = x11;
261         this->m_TransformMatrix.f._21 = x21;
262         this->m_TransformMatrix.f._02 = x02;
263         this->m_TransformMatrix.f._12 = x12;
264         this->m_TransformMatrix.f._22 = x22;
265 
266         this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
267     }
268 
269     //! @brief スケーリング変換ベクトルを取得します。
270     //!        更新をした場合、必ず Dirty フラグを設定してください。
DirectScale()271     math::VEC3& DirectScale() { return m_Scale; }
272 
273     //! スケーリング変換ベクトルを取得します。
Scale()274     const math::VEC3& Scale() const { return m_Scale; }
275 
276     //! @brief スケーリング変換ベクトルを設定します。
277     //!        Dirty フラグを設定します。
SetScale(const math::VEC3 & scale)278     void SetScale(const math::VEC3& scale)
279     {
280         m_Scale = scale;
281 
282         this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
283     }
284 
285     //! @brief スケーリング変換ベクトルを設定します。
286     //!        Dirty フラグを設定します。
SetScale(f32 fx,f32 fy,f32 fz)287     void SetScale(f32 fx, f32 fy, f32 fz)
288     {
289         m_Scale.Set(fx, fy, fz);
290 
291         this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
292     }
293 
294     //! @brief 平行移動を設定します。
295     //!        Dirty フラグを設定します。
SetTranslate(f32 x,f32 y,f32 z)296     void SetTranslate(f32 x, f32 y, f32 z)
297     {
298         this->m_TransformMatrix.f._03 = x;
299         this->m_TransformMatrix.f._13 = y;
300         this->m_TransformMatrix.f._23 = z;
301 
302         this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
303     }
304 
305     //! @brief 平行移動を設定します。
306     //!        Dirty フラグを設定します。
SetTranslate(const math::VEC3 & translate)307     void SetTranslate(const math::VEC3& translate)
308     {
309         SetTranslate(translate.x, translate.y, translate.z);
310 
311         // SetTranslate 内で呼び出しているので不要
312         //this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
313     }
314 
315     //! @brief 平行移動を取得します。
GetTranslate(math::VEC3 * translate)316     void GetTranslate(math::VEC3* translate) const
317     {
318         NW_NULL_ASSERT(translate);
319         translate->x = this->m_TransformMatrix.f._03;
320         translate->y = this->m_TransformMatrix.f._13;
321         translate->z = this->m_TransformMatrix.f._23;
322     }
323 
324     //! @brief 平行移動を取得します。
GetTranslate()325     math::VEC3 GetTranslate() const
326     {
327         return math::VEC3(
328             this->m_TransformMatrix.f._03,
329             this->m_TransformMatrix.f._13,
330             this->m_TransformMatrix.f._23);
331     }
332 
333     //! @brief 回転を設定します。
334     //!        Dirty フラグを設定します。
SetRotateXYZ(f32 x,f32 y,f32 z)335     void SetRotateXYZ(f32 x, f32 y, f32 z)
336     {
337         math::VEC3 translate;
338         this->GetTranslate(&translate);
339         nw::math::MTX34RotXYZRad(&this->m_TransformMatrix,
340                                  x,
341                                  y,
342                                  z);
343         this->SetTranslate(translate);
344 
345         // SetTranslate 内で呼び出しているので不要
346         //this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
347     }
348 
349     //! @brief 回転と平行移動を設定します。
350     //!        回転順は XYZ となります。
351     //!        Dirty フラグを設定します。
SetRotateAndTranslate(const math::VEC3 & rotate,const math::VEC3 & translate)352     void SetRotateAndTranslate(const math::VEC3& rotate, const math::VEC3& translate)
353     {
354         nw::math::MTX34RotXYZRad(&this->m_TransformMatrix,
355                                  rotate.x,
356                                  rotate.y,
357                                  rotate.z);
358 
359         this->SetTranslate(translate);
360 
361         // SetTranslate 内で呼び出しているので不要
362         //this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
363     }
364 
365     //! @brief トランスフォームを設定します。
366     //!        Dirty フラグを設定します。
SetTransform(const math::Transform3 & transform)367     void SetTransform(const math::Transform3& transform)
368     {
369         this->m_Scale = transform.scale;
370         SetRotateAndTranslate(transform.rotate, transform.translate);
371 
372         // SetRotateAndTranslate 内で呼び出しているので不要
373         //this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
374     }
375 
376     //@}
377 
378     //----------------------------------------
379     //! @name ユーティリティ関数
380     //@{
381 
382     //! @brief 行列の回転成分を正規直交化します。
383     //!        Dirty フラグを設定します。
384     //!
385     //! @return 正しく変換できれば true を返します。
386     //!
NormalizeRotateMatrix()387     bool NormalizeRotateMatrix()
388     {
389         if (!this->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
390         {
391             // 回転行列を正規直交化します。
392 
393             // 回転行列の 3 行目を外積で計算
394             math::VEC3* v0 = reinterpret_cast<math::VEC3*>(&this->m_TransformMatrix.m[0]);
395             math::VEC3* v1 = reinterpret_cast<math::VEC3*>(&this->m_TransformMatrix.m[1]);
396             math::VEC3* v2 = reinterpret_cast<math::VEC3*>(&this->m_TransformMatrix.m[2]);
397 
398             (void)math::VEC3Cross(v2, v0, v1);
399 
400             float lengthSquareV0 = v0->LengthSquare();
401             float lengthSquareV2 = v2->LengthSquare();
402 
403             if (lengthSquareV0 < s_VecSquareLenTol ||
404                 lengthSquareV2 < s_VecSquareLenTol)
405             {
406                 // 回転軸がゼロベクトル
407                 return false;
408             }
409             else
410             {
411                 *v0 *= 1.0f / nn::math::FSqrt(lengthSquareV0);
412                 *v2 *= 1.0f / nn::math::FSqrt(lengthSquareV2);
413 
414                 (void)math::VEC3Cross(v1, v2, v0);
415             }
416 
417             this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
418         }
419         return true;
420     }
421 
422     //! @brief 行列の回転成分をクォータニオンに変換します。
423     //!        行列の 00, 01, 02, 10 成分にクォータニオンの x, y, z, w が格納されます。
424     //!        Dirty フラグを設定します。
425     //!
426     //! @return 正しく変換できれば true を返します。
427     //!
RotateMatrixToQuaternion()428     bool RotateMatrixToQuaternion()
429     {
430         if (!this->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
431         {
432             // 行列の回転成分をクォータニオンに変換します。
433             math::QUAT q;
434             math::MTX34ToQUAT(&q, &this->m_TransformMatrix);
435             this->m_TransformMatrix.f._00 = q.x;
436             this->m_TransformMatrix.f._01 = q.y;
437             this->m_TransformMatrix.f._02 = q.z;
438             this->m_TransformMatrix.f._10 = q.w;
439 
440             this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
441         }
442         return true;
443     }
444 
445     //! @brief クォータニオンを行列の回転成分に変換します。
446     //!        行列の 00, 01, 02, 10 成分をクォータニオンの x, y, z, w とみなします。
447     //!        Dirty フラグを設定します。
448     //!
449     //! @return 正しく変換できれば true を返します。
450     //!
QuaternionToRotateMatrix()451     bool QuaternionToRotateMatrix()
452     {
453         if (!this->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
454         {
455             // クォータニオンを行列の回転成分に変換します。
456             math::VEC3 t = this->m_TransformMatrix.GetColumn(3);
457             math::QUAT q(this->m_TransformMatrix.f._00, this->m_TransformMatrix.f._01, this->m_TransformMatrix.f._02, this->m_TransformMatrix.f._10);
458             math::QUATToMTX34(&this->m_TransformMatrix, &q);
459             this->m_TransformMatrix.SetColumn(3, t); // 移動成分を復元
460 
461             math::VEC3* v0 = reinterpret_cast<math::VEC3*>(&this->m_TransformMatrix.m[0]);
462             math::VEC3* v1 = reinterpret_cast<math::VEC3*>(&this->m_TransformMatrix.m[1]);
463             math::VEC3* v2 = reinterpret_cast<math::VEC3*>(&this->m_TransformMatrix.m[2]);
464             if (math::VEC3SquareLen(v0) < s_VecSquareLenTol ||
465                 math::VEC3SquareLen(v1) < s_VecSquareLenTol ||
466                 math::VEC3SquareLen(v2) < s_VecSquareLenTol)
467             {
468                 // ブレンド結果の回転軸がゼロベクトル
469                 return false;
470             }
471 
472             this->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
473         }
474         return true;
475     }
476 
477     //! @brief 行列の回転成分にゼロベクトルがあれば補正します。
478     //!
479     //! @param[in] useDefaultMtx デフォルトの行列を使用するかどうかです。
480     //! false なら回転成分を単位行列にします。
481     //! @param[in] defaultMtx デフォルトの行列です。
482     //!
483     //! :private
AdjustZeroRotateMatrix(const bool useDefaultMtx,const math::MTX34 & defaultMtx)484     void AdjustZeroRotateMatrix(const bool useDefaultMtx, const math::MTX34& defaultMtx)
485     {
486         if (!this->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
487         {
488             const math::MTX34& m = this->TransformMatrix();
489             const math::VEC3* v0 = reinterpret_cast<const math::VEC3*>(&m.m[0]);
490             const math::VEC3* v1 = reinterpret_cast<const math::VEC3*>(&m.m[1]);
491             const math::VEC3* v2 = reinterpret_cast<const math::VEC3*>(&m.m[2]);
492 
493             if (math::VEC3SquareLen(v0) < s_VecSquareLenTol ||
494                 math::VEC3SquareLen(v1) < s_VecSquareLenTol ||
495                 math::VEC3SquareLen(v2) < s_VecSquareLenTol)
496             {
497                 if (useDefaultMtx)
498                 {
499                     this->SetRotateMatrix(defaultMtx);
500                 }
501                 else
502                 {
503                     this->SetRotateMatrix(
504                         1.0f, 0.0f, 0.0f,
505                         0.0f, 1.0f, 0.0f,
506                         0.0f, 0.0f, 1.0f);
507                 }
508             }
509         }
510     }
511 
512     //@}
513 
514     //----------------------------------------
515     //! @name フラグ取得/設定
516     //@{
517 
518     //! フラグの値を直接取得します。
GetFlags()519     bit32 GetFlags() const { return m_Flags; }
520 
521     //! フラグの値を直接設定します。
SetFlags(bit32 flags)522     void SetFlags(bit32 flags) { m_Flags = flags; }
523 
524     //! 指定のフラグの値を直接設定します。
525     //!
526     //! @param[in] flags  フラグを指定します。
527     //! @param[in] values フラグに設定する値です。
528     //!
RestoreFlags(bit32 flags,bit32 values)529     void RestoreFlags(bit32 flags, bit32 values) { m_Flags = (m_Flags & ~flags) | (values & flags); }
530 
531     //! 任意のフラグが有効になっているか取得します。
IsEnabledFlags(bit32 flags)532     bool IsEnabledFlags(bit32 flags) const { return ut::CheckFlag(m_Flags, flags); }
533 
534     //! 任意のフラグのいずれかが有効になっているか取得します。
IsEnabledFlagsOr(bit32 flags)535     bool IsEnabledFlagsOr(bit32 flags) const { return ut::CheckFlagOr(m_Flags, flags); }
536 
537     //! 任意のフラグを有効に設定します。
EnableFlags(bit32 flags)538     void EnableFlags(bit32 flags) { m_Flags = ut::EnableFlag(m_Flags, flags); }
539 
540     //! 任意のフラグを無効に設定します。
DisableFlags(bit32 flags)541     void DisableFlags(bit32 flags) { m_Flags = ut::DisableFlag(m_Flags, flags);  }
542 
543     //! 任意のフラグの有効/無効を設定します。
EnableFlags(bit32 flags,bool enable)544     void EnableFlags(bit32 flags, bool enable)
545     {
546         if (enable)
547         {
548             EnableFlags(flags);
549         }
550         else
551         {
552             DisableFlags(flags);
553         }
554     }
555 
556     //! 全てのフラグを無効にします。
ResetFlags()557     void ResetFlags() { m_Flags = 0x0; }
558 
559     //! 全てのトランスフォームのフラグを無効にします。
ResetTransformFlags()560     void ResetTransformFlags()
561     {
562         m_Flags &=
563             (~(FLAG_IS_IDENTITY |
564             FLAG_IS_ROTATE_TRANSLATE_ZERO |
565             FLAG_IS_ROTATE_ZERO |
566             FLAG_IS_TRANSLATE_ZERO |
567             FLAG_IS_SCALE_ONE |
568             FLAG_IS_UNIFORM_SCALE));
569     }
570 
571     //! @brief トランスフォーム情報からすべてのフラグを更新します。
572     //!
573     //!        UpdateRotateFlags() の代わりに UpdateRotateFlagsStrictly() を呼び出します。
574     void UpdateFlagsStrictly();
575 
576     //! @brief トランスフォーム情報からすべてのフラグを更新します。
577     //!
578     //!        UpdateRotateFlags() を呼び出すため、
579     //!        回転行列のノルム 1 でない場合、フラグが不正になることがあります。
580     void UpdateFlags();
581 
582     //! トランスフォーム情報からスケールのフラグのみを更新します。
UpdateScaleFlags()583     void UpdateScaleFlags()
584     {
585         if (this->IsEnabledFlags(FLAG_IS_IGNORE_SCALE))
586         {
587             return;
588         }
589 
590         this->DisableFlags(FLAG_IS_UNIFORM_SCALE | FLAG_IS_SCALE_ONE);
591 
592         const math::VEC3& scale = this->m_Scale;
593         if (scale.x == scale.y && scale.x == scale.z)
594         {
595             this->EnableFlags(FLAG_IS_UNIFORM_SCALE);
596 
597             if (scale.x == 1.0f)
598             {
599                 this->EnableFlags(FLAG_IS_SCALE_ONE);
600             }
601         }
602     }
603 
604     //! @brief トランスフォーム情報から回転のフラグのみを更新します。
605     //!
606     //!        回転行列部分のすべての成分をチェックしてフラグを更新します。
607     //!        そのため、UpdateRotateFlags() に比べてわずかながら低速です。
608     void UpdateRotateFlagsStrictly();
609 
610     //! @brief トランスフォーム情報から回転のフラグのみを更新します。
611     //!
612     //!        回転行列のノルムが 1 であるという前提で、
613     //!        対角成分の 11 成分と 22 成分のみをチェックしてフラグ更新を行ないます。
614     //!        そのため、UpdateRotateFlagsStrictly() に比べてわずかながら高速です。
615     //!        ノルム 1 でない場合はフラグ更新が不正になることがあります。
616     void UpdateRotateFlags();
617 
618     //! トランスフォーム情報から平行移動のフラグのみを更新します。
619     void UpdateTranslateFlags();
620 
621     //! 各成分のフラグから行列全体のフラグを更新します。
622     void UpdateCompositeFlags();
623 
624     //@}
625 
626 private:
627     math::MTX34 m_TransformMatrix;
628     math::VEC3  m_Scale;
629     bit32 m_Flags;
630 
631     friend class WorldMatrixUpdater;
632     friend class TransformAnimEvaluator;
633     friend class TransformAnimBlendOp;
634 };
635 
636 } // gfx
637 } // nw
638 
639 #endif // NW_GFX_CALCULATED_TRANSFORM_H_
640