1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_TransformAnimAdder.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/anim/anim_AnimBlend.h>
21 #include <nw/gfx/gfx_AnimGroup.h>
22 #include <nw/gfx/gfx_CalculatedTransform.h>
23 #include <nw/gfx/gfx_TransformAnimAdder.h>
24 #include <nw/gfx/gfx_TransformAnimBlendOp.h>
25 #include <nw/gfx/gfx_TransformAnimEvaluator.h>
26 
27 namespace nw
28 {
29 namespace gfx
30 {
31 
32 NW_UT_RUNTIME_TYPEINFO_DEFINITION(TransformAnimAdder       , AnimAdder);
33 
34 //----------------------------------------------------------
35 const anim::AnimResult*
GetResult(void * target,int memberIdx) const36 TransformAnimAdder::GetResult(
37     void* target,
38     int memberIdx
39 ) const
40 {
41     //----------------------------------------------------------
42     // ブレンドオペレーションを取得
43     const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
44 
45     //----------------------------------------------------------
46     // 補間は操作空間があればそこで行われるべきなので
47     // target の CONVERTED フラグを退避してからオンに
48     CalculatedTransform* transform =
49         reinterpret_cast<CalculatedTransform*>(target);
50     const bit32 flagsBak = transform->GetFlags();
51     const bool convertedBak = transform->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
52     transform->EnableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
53 
54     //----------------------------------------------------------
55     // target の IGNORE フラグをオンにして未書き込み状態とする
56     transform->EnableFlags(CalculatedTransform::FLAG_IS_IGNORE_ALL);
57 
58     //----------------------------------------------------------
59     // すべての子アニメーションについてループ
60     CalculatedTransform workResult;
61     bool written = false;
62     bool firstRotateFlag = true;
63     math::MTX34 firstRotateMtx;
64     //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
65     for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
66     {
67         const AnimObject* animObj = m_AnimObjects[animIdx];
68         if (animObj == NULL)
69         {
70             continue;
71         }
72 
73         const float childWeight = m_Weights[animIdx];
74         float srcWeights[3] = { childWeight, childWeight, childWeight };
75         TransformAnimEvaluator::DisableSRTWeightsIfNeeded(srcWeights, animObj);
76 
77         if (!TransformAnimEvaluator::CheckWeightsNearlyZero(srcWeights))
78         {
79             // 退避した CONVERTED フラグを work に反映
80             // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
81             // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
82             workResult.EnableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND, convertedBak);
83 
84             // 評価
85             const anim::AnimResult* childResult =
86                 animObj->GetResult(&workResult, memberIdx);
87             if (childResult != NULL)
88             {
89                 written = true;
90                 const bool evaluatorFlag =
91                     ut::DynamicCast<const TransformAnimEvaluator*>(animObj) != NULL;
92 
93                 // ブレンド結果の回転行列の行がゼロベクトルになった場合のために
94                 // 最初のアニメーションの回転行列を保存しておく
95                 if (evaluatorFlag && firstRotateFlag &&
96                     !workResult.IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
97                 {
98                     firstRotateFlag = false;
99                     firstRotateMtx = workResult.TransformMatrix();
100                 }
101 
102                 // ブレンド
103                 if (!blendOp->Blend(reinterpret_cast<anim::AnimResult*>(transform),
104                     NULL, childResult, srcWeights))
105                 {
106                     break;
107                 }
108             }
109         }
110     }
111 
112     //----------------------------------------------------------
113     // target の CONVERTED フラグを復元
114     if (!convertedBak)
115     {
116         transform->DisableFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
117     }
118 
119     if (!written) // 有効な子アニメーションなし
120     {
121         transform->RestoreFlags(CalculatedTransform::FLAG_IS_IGNORE_ALL, flagsBak);
122         return NULL;
123     }
124 
125     //----------------------------------------------------------
126     // ブレンド後の処理があれば実行
127     if (!convertedBak && blendOp->HasPostBlend())
128     {
129         if (!blendOp->PostBlend(reinterpret_cast<anim::AnimResult*>(transform), NULL))
130         {
131             // ブレンド結果の回転行列の行がゼロベクトルなら
132             // 最初のアニメーションの回転行列を採用します。
133             // 結果が品質上問題となる場合は
134             // 元データを微妙にずらして回避する必要があります。
135             transform->AdjustZeroRotateMatrix(!firstRotateFlag, firstRotateMtx);
136         }
137     }
138     transform->UpdateScaleFlags();
139     transform->UpdateRotateFlagsStrictly();
140     transform->UpdateTranslateFlags();
141     transform->UpdateCompositeFlags();
142 
143     // target を AnimResult にキャストして返す(親のブレンダで使用)
144     return reinterpret_cast<anim::AnimResult*>(target);
145 }
146 
147 } // namespace gfx
148 } // namespace nw
149