1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_TransformAnimBlendOp.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_TransformAnimBlendOp.h>
21 
22 namespace nw
23 {
24 namespace gfx
25 {
26 
27 //! トランスフォームアニメーションのブレンドオペレーションで使用する定数です。
28 const float TransformAnimBlendOp::WeightDiscard = -1.0f;
29 
30 namespace {
31 
32 /*!--------------------------------------------------------------------------*
33   @brief Vector3 の値をすべて Flog で変換します。
34  *---------------------------------------------------------------------------*/
35 void
FlogVector3(math::VEC3 * dst)36 FlogVector3(math::VEC3* dst)
37 {
38     dst->x = math::FLog(dst->x);
39     dst->y = math::FLog(dst->y);
40     dst->z = math::FLog(dst->z);
41 }
42 
43 /*!--------------------------------------------------------------------------*
44   @brief Vector3 のブレンド処理を行います。
45 
46   @param[in,out] dst ブレンド処理結果です。
47   @param[in] src ブレンド処理の入力です。
48   @param[in] weight ブレンド比率です。
49   @param[in] overrideFlag 値を上書き更新するかどうかのフラグです。
50  *---------------------------------------------------------------------------*/
51 void
BlendVector3(math::VEC3 * dst,const math::VEC3 * src,const float weight,const bool overrideFlag)52 BlendVector3(
53     math::VEC3* dst,
54     const math::VEC3* src,
55     const float weight,
56     const bool overrideFlag
57 )
58 {
59     if (overrideFlag)
60     {
61         VEC3Scale(dst, src, weight);
62     }
63     else
64     {
65         math::VEC3 tmp;
66         VEC3Scale(&tmp, src, weight);
67         VEC3Add(dst, dst, &tmp);
68     }
69 }
70 
71 } // namespace
72 
73 //----------------------------------------------------------
74 void
Apply(void * target,const anim::AnimResult * result) const75 TransformAnimBlendOp::Apply(void* target, const anim::AnimResult* result) const
76 {
77     *reinterpret_cast<CalculatedTransform*>(target) =
78         *reinterpret_cast<const CalculatedTransform*>(result->GetValueBuffer());
79 }
80 
81 //----------------------------------------------------------
82 void
ConvertToAnimResult(anim::AnimResult * result,const void * source) const83 TransformAnimBlendOp::ConvertToAnimResult(
84     anim::AnimResult* result,
85     const void* source
86     ) const
87 {
88     *reinterpret_cast<CalculatedTransform*>(result->GetValueBuffer()) =
89         *reinterpret_cast<const CalculatedTransform*>(source);
90 }
91 
92 //----------------------------------------------------------
93 void
BlendScaleStandard(CalculatedTransform * dst,const CalculatedTransform * src,const float weight) const94 TransformAnimBlendOp::BlendScaleStandard(
95     CalculatedTransform* dst,
96     const CalculatedTransform* src,
97     const float weight
98 ) const
99 {
100     if (weight != TransformAnimBlendOp::WeightDiscard)
101     {
102         // スケール値を直接ブレンド
103         BlendVector3(&dst->m_Scale, &src->Scale(),
104             weight, dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE));
105 
106         dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE);
107         dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
108     }
109 }
110 
111 //----------------------------------------------------------
112 void
BlendScaleAccurate(CalculatedTransform * dst,const CalculatedTransform * src,const float weight) const113 TransformAnimBlendOp::BlendScaleAccurate(
114     CalculatedTransform* dst,
115     const CalculatedTransform* src,
116     const float weight
117 ) const
118 {
119     if (weight != TransformAnimBlendOp::WeightDiscard)
120     {
121          // 正確なスケールブレンド
122         // s = Π(s(i)^weight) = exp(Σ(log(s(i)) * weight))
123         // exp の計算は最後に行う
124         math::VEC3 logScale = src->Scale();
125         FlogVector3(&logScale);
126         BlendVector3(&dst->m_Scale, &logScale,
127             weight, dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE));
128 
129         dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE);
130         dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
131     }
132 }
133 
134 //----------------------------------------------------------
135 bool
PostBlendAccurateScale(CalculatedTransform * transform) const136 TransformAnimBlendOp::PostBlendAccurateScale(CalculatedTransform* transform) const
137 {
138     math::VEC3& scale = transform->m_Scale;
139     scale.x = math::FExp(scale.x);
140     scale.y = math::FExp(scale.y);
141     scale.z = math::FExp(scale.z);
142     transform->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
143     return true;
144 }
145 
146 //----------------------------------------------------------
147 void
BlendRotateMatrix(CalculatedTransform * dst,const CalculatedTransform * src,const float weight) const148 TransformAnimBlendOp::BlendRotateMatrix(
149     CalculatedTransform* dst,
150     const CalculatedTransform* src,
151     const float weight
152 ) const
153 {
154     if (weight != TransformAnimBlendOp::WeightDiscard)
155     {
156         math::MTX34& dstMtx = dst->m_TransformMatrix;
157         const math::MTX34& srcMtx = src->TransformMatrix();
158 
159         if (dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
160         {
161             dstMtx.f._00 = srcMtx.f._00 * weight;
162             dstMtx.f._01 = srcMtx.f._01 * weight;
163             dstMtx.f._02 = srcMtx.f._02 * weight;
164 
165             dstMtx.f._10 = srcMtx.f._10 * weight;
166             dstMtx.f._11 = srcMtx.f._11 * weight;
167             dstMtx.f._12 = srcMtx.f._12 * weight;
168 
169             // ブレンド後の処理で回転行列を正規直交化するので、 2 行目の計算は不要
170         }
171         else
172         {
173             dstMtx.f._00 += srcMtx.f._00 * weight;
174             dstMtx.f._01 += srcMtx.f._01 * weight;
175             dstMtx.f._02 += srcMtx.f._02 * weight;
176 
177             dstMtx.f._10 += srcMtx.f._10 * weight;
178             dstMtx.f._11 += srcMtx.f._11 * weight;
179             dstMtx.f._12 += srcMtx.f._12 * weight;
180 
181             // ブレンド後の処理で回転行列を正規直交化するので、 2 行目の計算は不要
182         }
183 
184         dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE);
185         dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
186     }
187 }
188 
189 //----------------------------------------------------------
190 void
BlendRotateQuaternion(CalculatedTransform * dst,const CalculatedTransform * src,const float weight) const191 TransformAnimBlendOp::BlendRotateQuaternion(
192     CalculatedTransform* dst,
193     const CalculatedTransform* src,
194     const float weight
195 ) const
196 {
197     if (weight != TransformAnimBlendOp::WeightDiscard)
198     {
199         math::MTX34& dstMtx = dst->m_TransformMatrix;
200         const math::MTX34& srcMtx = src->TransformMatrix();
201 
202         float& addedWeight = dstMtx.f._11;
203         math::QUAT srcQ;
204         if (src->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND))
205         {
206             srcQ = math::QUAT(srcMtx.f._00, srcMtx.f._01, srcMtx.f._02, srcMtx.f._10);
207         }
208         else
209         {
210             math::MTX34ToQUAT(&srcQ, &srcMtx);
211         }
212         math::QUAT dstQ;
213         if (dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
214         {
215             addedWeight = weight;
216             dstQ = srcQ;
217         }
218         else
219         {
220             dstQ = math::QUAT(dstMtx.f._00, dstMtx.f._01, dstMtx.f._02, dstMtx.f._10);
221             addedWeight += weight;
222             const float t = (addedWeight != 0.0f) ? weight / addedWeight : 0.0f;
223             math::QUATSlerp(&dstQ, &dstQ, &srcQ, t);
224         }
225         dstMtx.f._00 = dstQ.x;
226         dstMtx.f._01 = dstQ.y;
227         dstMtx.f._02 = dstQ.z;
228         dstMtx.f._10 = dstQ.w;
229 
230         dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE);
231         dst->SetTransformMatrix(dstMtx);
232     }
233 }
234 
235 //----------------------------------------------------------
236 void
BlendTranslate(CalculatedTransform * dst,const CalculatedTransform * src,const float weight) const237 TransformAnimBlendOp::BlendTranslate(
238     CalculatedTransform* dst,
239     const CalculatedTransform* src,
240     const float weight
241 ) const
242 {
243     if (weight != TransformAnimBlendOp::WeightDiscard)
244     {
245         const math::MTX34& dstMtx = dst->TransformMatrix();
246         const math::MTX34& srcMtx = src->TransformMatrix();
247 
248         math::VEC3 srcT(srcMtx.f._03, srcMtx.f._13, srcMtx.f._23);
249         if (dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE))
250         {
251             VEC3Scale(&srcT, &srcT, weight);
252             dst->SetTranslate(srcT);
253             dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE);
254         }
255         else
256         {
257             math::VEC3 dstT(dstMtx.f._03, dstMtx.f._13, dstMtx.f._23);
258             BlendVector3(&dstT, &srcT, weight, false);
259             dst->SetTranslate(dstT);
260         }
261     }
262 }
263 
264 //----------------------------------------------------------
265 bool
OverrideTransform(CalculatedTransform * dst,const CalculatedTransform * src,const bit32 blendFlags) const266 TransformAnimBlendOp::OverrideTransform(
267     CalculatedTransform* dst,
268     const CalculatedTransform* src,
269     const bit32 blendFlags
270 ) const
271 {
272     const bool needToConverted =
273          dst->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND) &&
274         !src->IsEnabledFlags(CalculatedTransform::FLAG_CONVERTED_FOR_BLEND);
275 
276     math::MTX34 dstMtx = dst->TransformMatrix();
277     const math::MTX34& srcMtx = src->TransformMatrix();
278 
279     if ( dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE) &&
280         !src->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE))
281     {
282         dst->SetScale(src->Scale());
283 
284         dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE);
285 
286         if (needToConverted && (blendFlags & FLAG_ACCURATE_SCALE))
287         {
288             math::VEC3& dstScale = dst->m_Scale;
289             FlogVector3(&dstScale);
290             dst->EnableFlags(CalculatedTransform::FLAG_IS_DIRTY);
291         }
292     }
293 
294     if ( dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE) &&
295         !src->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE))
296     {
297         dstMtx.f._00 = srcMtx.f._00;
298         dstMtx.f._01 = srcMtx.f._01;
299         dstMtx.f._02 = srcMtx.f._02;
300 
301         dstMtx.f._10 = srcMtx.f._10;
302         dstMtx.f._11 = srcMtx.f._11;
303         dstMtx.f._12 = srcMtx.f._12;
304 
305         dstMtx.f._20 = srcMtx.f._20;
306         dstMtx.f._21 = srcMtx.f._21;
307         dstMtx.f._22 = srcMtx.f._22;
308 
309         dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE);
310 
311         if (needToConverted && (blendFlags & FLAG_QUATERNION_ROTATE))
312         {
313             dst->RotateMatrixToQuaternion();
314         }
315     }
316 
317     if ( dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE) &&
318         !src->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE))
319     {
320         dstMtx.f._03 = srcMtx.f._03;
321         dstMtx.f._13 = srcMtx.f._13;
322         dstMtx.f._23 = srcMtx.f._23;
323 
324         dst->DisableFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE);
325     }
326 
327     dst->SetTransformMatrix(dstMtx);
328 
329     return
330         !dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_SCALE) &&
331         !dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_ROTATE) &&
332         !dst->IsEnabledFlags(CalculatedTransform::FLAG_IS_IGNORE_TRANSLATE);
333 }
334 
335 } // namespace gfx
336 } // namespace nw
337