1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_TransformAnim.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: 28677 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_GFX_TRANSFORMANIM_H_
17 #define NW_GFX_TRANSFORMANIM_H_
18 
19 #include <nw/gfx/gfx_AnimObject.h>
20 #include <nw/gfx/gfx_CalculatedTransform.h>
21 
22 namespace nw {
23 namespace gfx {
24 
25 //---------------------------------------------------------------------------
26 //! @brief トランスフォームアニメーションのブレンドオペレーションの基底クラスです。
27 //---------------------------------------------------------------------------
28 class TransformAnimBlendOp : public anim::AnimBlendOp
29 {
30 public:
31     //! 無効な重み値です。
32     //!
33     //! :private
34     static const float WeightDiscard;
35 
36     //----------------------------------------
37     //! @name コンストラクタ/デストラクタ
38     //@{
39 
40     //! @brief コンストラクタです。
41     //!
42     //! @param[in] hasBlend ブレンド処理があるかどうかです。
43     //! @param[in] hasPostBlend ブレンド後の処理があるかどうかです。
44     //!
TransformAnimBlendOp(bool hasBlend,bool hasPostBlend)45     TransformAnimBlendOp(bool hasBlend, bool hasPostBlend)
46     : AnimBlendOp(hasBlend, hasPostBlend) {}
47 
48     //! デストラクタです。
~TransformAnimBlendOp()49     virtual ~TransformAnimBlendOp() {}
50 
51     //@}
52 
53 
54     //----------------------------------------
55     //! @name 適用
56     //@{
57 
58     //! @brief ブレンド処理結果を対象に適用します。
59     //!
60     //! @param[out] target ブレンド処理結果を適用する対象です。
61     //! @param[in] result ブレンド処理結果です。
62     //!
63     virtual void Apply(void* target, const anim::AnimResult* result) const;
64 
65     //! @brief 対象を AnimResult に変換します。
66     //!
67     //! @param[out] result 出力の AnimResult です。
68     //! @param[in] source 変換元へのポインタです。
69     //!
70     //! :private
71     virtual void ConvertToAnimResult(anim::AnimResult* result, const void* source) const;
72 
73     //@}
74 
75 protected:
76     //----------------------------------------
77     //! @name 基本ブレンド処理
78     //@{
79 
80     //! @details :private
81     enum BasicBlendFlags
82     {
83         FLAG_ACCURATE_SCALE_SHIFT = 0,
84         FLAG_QUATERNION_ROTATE_SHIFT = 1,
85 
86         // 正確なスケールブレンドをするかどうかです。
87         FLAG_ACCURATE_SCALE = 0x1 << FLAG_ACCURATE_SCALE_SHIFT,
88 
89         // クォータニオンで回転をブレンドするかどうかです。オフなら行列の回転成分をブレンドします。
90         FLAG_QUATERNION_ROTATE = 0x1 << FLAG_QUATERNION_ROTATE_SHIFT
91     };
92 
93     //! @brief 標準的なスケールのブレンド処理を行います。
94     //!
95     //! @param[in,out] dst ブレンド処理結果です。
96     //! @param[in] src ブレンド処理の入力です。
97     //! @param[in] weight ブレンド処理の入力の重みです。
98     //!
99     //! :private
100     void BlendScaleStandard(
101         CalculatedTransform* dst,
102         const CalculatedTransform* src,
103         const float weight) const;
104 
105     //! @brief 正確なスケールのブレンド処理を行います。
106     //!
107     //! @param[in,out] dst ブレンド処理結果です。
108     //! @param[in] src ブレンド処理の入力です。
109     //! @param[in] weight ブレンド処理の入力の重みです。
110     //!
111     //! :private
112     void BlendScaleAccurate(
113         CalculatedTransform* dst,
114         const CalculatedTransform* src,
115         const float weight) const;
116 
117     //! @brief 正確なスケールブレンドのブレンド後の処理を行います。
118     //!
119     //! :private
120     //!
121     //! @param[in,out] transform トランスフォームです。
122     //!
123     //! @return 正しく処理できれば true を返します。
124     bool PostBlendAccurateScale(CalculatedTransform* transform) const;
125 
126     //! @brief 行列の回転のブレンド処理を行います。
127     //!
128     //! @param[in,out] dst ブレンド処理結果です。
129     //! @param[in] src ブレンド処理の入力です。
130     //! @param[in] weight ブレンド処理の入力の重みです。
131     //!
132     //! :private
133     void BlendRotateMatrix(
134         CalculatedTransform* dst,
135         const CalculatedTransform* src,
136         const float weight) const;
137 
138     //! @brief クォータニオンの回転のブレンド処理を行います。
139     //!
140     //! @param[in,out] dst ブレンド処理結果です。
141     //! @param[in] src ブレンド処理の入力です。
142     //! @param[in] weight ブレンド処理の入力の重みです。
143     //!
144     //! :private
145     void BlendRotateQuaternion(
146         CalculatedTransform* dst,
147         const CalculatedTransform* src,
148         const float weight) const;
149 
150     //! @brief 移動のブレンド処理を行います。
151     //!
152     //! @param[in,out] dst ブレンド処理結果です。
153     //! @param[in] src ブレンド処理の入力です。
154     //! @param[in] weight ブレンド処理の入力の重みです。
155     //!
156     //! :private
157     void BlendTranslate(
158         CalculatedTransform* dst,
159         const CalculatedTransform* src,
160         const float weight) const;
161 
162     //! @brief トランスフォームの上書き処理を行います。
163     //!
164     //! :private
165     //!
166     //! @param[in,out] dst ブレンド処理結果です。
167     //! @param[in] src ブレンド処理の入力です。
168     //! @param[in] blendFlags ブレンド処理のフラグです。
169     //!
170     //! @return すべての成分が上書きされたら true を返します。
171     bool OverrideTransform(
172         CalculatedTransform* dst,
173         const CalculatedTransform* src,
174         const bit32 blendFlags
175     ) const;
176 
177     //@}
178 };
179 
180 //---------------------------------------------------------------------------
181 //! @brief トランスフォームアニメーションの標準的なブレンドオペレーションのクラスです。
182 //! 回転行列の各成分をブレンドした後に、正規直交化します。
183 //---------------------------------------------------------------------------
184 class TransformAnimBlendOpStandard : public TransformAnimBlendOp
185 {
186 public:
187     //----------------------------------------
188     //! @name コンストラクタ/デストラクタ
189     //@{
190 
191     //! コンストラクタです。
TransformAnimBlendOpStandard()192     TransformAnimBlendOpStandard()
193     : TransformAnimBlendOp(true, true)
194     {}
195 
196     //! デストラクタです。
~TransformAnimBlendOpStandard()197     virtual ~TransformAnimBlendOpStandard() {}
198 
199     //@}
200 
201     //----------------------------------------
202     //! @name ブレンド
203     //@{
204 
205     //! @brief ブレンド処理を行います。
206     //!
207     //! @param[in,out] dst ブレンド処理結果です。
208     //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。
209     //! このブレンドオペレーションでは使用しません。
210     //! @param[in] src ブレンド処理の入力です。
211     //! @param[in] srcWeights ブレンド処理の入力の重みです。
212     //!
213     //! @return ブレンド処理のループを継続するなら true を返します。
214     //!
Blend(anim::AnimResult * dst,float * dstWeights,const anim::AnimResult * src,const float * srcWeights)215     virtual bool Blend(
216         anim::AnimResult* dst,
217         float* dstWeights,
218         const anim::AnimResult* src,
219         const float* srcWeights) const
220     {
221         (void)dstWeights;
222         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
223         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
224         BlendScaleStandard(dstX, srcX, srcWeights[0]);
225         BlendRotateMatrix (dstX, srcX, srcWeights[1]);
226         BlendTranslate    (dstX, srcX, srcWeights[2]);
227         return true;
228     }
229 
230     //! @brief ブレンド後の処理を行います。
231     //!
232     //! @param[in,out] result ブレンド処理結果です。
233     //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。
234     //! このブレンドオペレーションでは使用しません。
235     //!
236     //! @return 成功すれば true を返します。
237     //!
PostBlend(anim::AnimResult * result,const float * weights)238     virtual bool PostBlend(anim::AnimResult* result, const float* weights) const
239     {
240         (void)weights;
241         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(result);
242         return dstX->NormalizeRotateMatrix();
243     }
244 
245     //! @brief 上書き処理を行います。
246     //!
247     //! @param[in,out] dst ブレンド処理結果です。
248     //! @param[in] src ブレンド処理の入力です。
249     //!
250     //! @return すべての成分が上書きされたら true を返します。
251     //!
Override(anim::AnimResult * dst,const anim::AnimResult * src)252     virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const
253     {
254         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
255         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
256         return OverrideTransform(dstX, srcX, 0);
257     }
258 
259     //@}
260 };
261 
262 //---------------------------------------------------------------------------
263 //! @brief トランスフォームアニメーションの正確なスケールブレンドに対応したブレンドオペレーションのクラスです。
264 //---------------------------------------------------------------------------
265 class TransformAnimBlendOpAccScale : public TransformAnimBlendOp
266 {
267 public:
268     //----------------------------------------
269     //! @name コンストラクタ/デストラクタ
270     //@{
271 
272     //! コンストラクタです。
TransformAnimBlendOpAccScale()273     TransformAnimBlendOpAccScale()
274     : TransformAnimBlendOp(true, true)
275     {}
276 
277     //! デストラクタです。
~TransformAnimBlendOpAccScale()278     virtual ~TransformAnimBlendOpAccScale() {}
279 
280     //@}
281 
282     //----------------------------------------
283     //! @name ブレンド
284     //@{
285 
286     //! @brief ブレンド処理を行います。
287     //!
288     //! @param[in,out] dst ブレンド処理結果です。
289     //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。
290     //! このブレンドオペレーションでは使用しません。
291     //! @param[in] src ブレンド処理の入力です。
292     //! @param[in] srcWeights ブレンド処理の入力の重みです。
293     //!
294     //! @return ブレンド処理のループを継続するなら true を返します。
295     //!
Blend(anim::AnimResult * dst,float * dstWeights,const anim::AnimResult * src,const float * srcWeights)296     virtual bool Blend(
297         anim::AnimResult* dst,
298         float* dstWeights,
299         const anim::AnimResult* src,
300         const float* srcWeights) const
301     {
302         (void)dstWeights;
303         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
304         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
305         BlendScaleAccurate(dstX, srcX, srcWeights[0]);
306         BlendRotateMatrix (dstX, srcX, srcWeights[1]);
307         BlendTranslate    (dstX, srcX, srcWeights[2]);
308         return true;
309     }
310 
311     //! @brief ブレンド後の処理を行います。
312     //!
313     //! @param[in,out] result ブレンド処理結果です。
314     //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。
315     //! このブレンドオペレーションでは使用しません。
316     //!
317     //! @return 成功すれば true を返します。
318     //!
PostBlend(anim::AnimResult * result,const float * weights)319     virtual bool PostBlend(anim::AnimResult* result, const float* weights) const
320     {
321         (void)weights;
322         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(result);
323         const bool scaleRet = PostBlendAccurateScale(dstX);
324         return dstX->NormalizeRotateMatrix() && scaleRet;
325     }
326 
327     //! @brief 上書き処理を行います。
328     //!
329     //! @param[in,out] dst ブレンド処理結果です。
330     //! @param[in] src ブレンド処理の入力です。
331     //!
332     //! @return すべての成分が上書きされたら true を返します。
333     //!
Override(anim::AnimResult * dst,const anim::AnimResult * src)334     virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const
335     {
336         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
337         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
338         return OverrideTransform(dstX, srcX, FLAG_ACCURATE_SCALE);
339     }
340 
341     //@}
342 };
343 
344 //---------------------------------------------------------------------------
345 //! @brief トランスフォームアニメーションのクォータニオンによる回転ブレンドに対応したブレンドオペレーションのクラスです。
346 //---------------------------------------------------------------------------
347 class TransformAnimBlendOpQuat : public TransformAnimBlendOp
348 {
349 public:
350     //----------------------------------------
351     //! @name コンストラクタ/デストラクタ
352     //@{
353 
354     //! コンストラクタです。
TransformAnimBlendOpQuat()355     TransformAnimBlendOpQuat()
356     : TransformAnimBlendOp(true, true)
357     {}
358 
359     //! デストラクタです。
~TransformAnimBlendOpQuat()360     virtual ~TransformAnimBlendOpQuat() {}
361 
362     //@}
363 
364     //----------------------------------------
365     //! @name ブレンド
366     //@{
367 
368     //! @brief ブレンド処理を行います。
369     //!
370     //! @param[in,out] dst ブレンド処理結果です。
371     //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。
372     //! このブレンドオペレーションでは使用しません。
373     //! @param[in] src ブレンド処理の入力です。
374     //! @param[in] srcWeights ブレンド処理の入力の重みです。
375     //!
376     //! @return ブレンド処理のループを継続するなら true を返します。
377     //!
Blend(anim::AnimResult * dst,float * dstWeights,const anim::AnimResult * src,const float * srcWeights)378     virtual bool Blend(
379         anim::AnimResult* dst,
380         float* dstWeights,
381         const anim::AnimResult* src,
382         const float* srcWeights) const
383     {
384         (void)dstWeights;
385         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
386         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
387         BlendScaleStandard   (dstX, srcX, srcWeights[0]);
388         BlendRotateQuaternion(dstX, srcX, srcWeights[1]);
389         BlendTranslate       (dstX, srcX, srcWeights[2]);
390         return true;
391     }
392 
393     //! @brief ブレンド後の処理を行います。
394     //!
395     //! @param[in,out] result ブレンド処理結果です。
396     //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。
397     //! このブレンドオペレーションでは使用しません。
398     //!
399     //! @return 成功すれば true を返します。
400     //!
PostBlend(anim::AnimResult * result,const float * weights)401     virtual bool PostBlend(anim::AnimResult* result, const float* weights) const
402     {
403         (void)weights;
404         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(result);
405         return dstX->QuaternionToRotateMatrix();
406     }
407 
408     //! @brief 上書き処理を行います。
409     //!
410     //! @param[in,out] dst ブレンド処理結果です。
411     //! @param[in] src ブレンド処理の入力です。
412     //!
413     //! @return すべての成分が上書きされたら true を返します。
414     //!
Override(anim::AnimResult * dst,const anim::AnimResult * src)415     virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const
416     {
417         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
418         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
419         return OverrideTransform(dstX, srcX, FLAG_QUATERNION_ROTATE);
420     }
421 
422     //@}
423 };
424 
425 //---------------------------------------------------------------------------
426 //! @brief トランスフォームアニメーションの正確なスケールブレンドとクォータニオンによる回転ブレンドに対応したブレンドオペレーションのクラスです。
427 //---------------------------------------------------------------------------
428 class TransformAnimBlendOpAccScaleQuat : public TransformAnimBlendOp
429 {
430 public:
431     //----------------------------------------
432     //! @name コンストラクタ/デストラクタ
433     //@{
434 
435     //! コンストラクタです。
TransformAnimBlendOpAccScaleQuat()436     TransformAnimBlendOpAccScaleQuat()
437     : TransformAnimBlendOp(true, true)
438     {}
439 
440     //! デストラクタです。
~TransformAnimBlendOpAccScaleQuat()441     virtual ~TransformAnimBlendOpAccScaleQuat() {}
442 
443     //@}
444 
445     //----------------------------------------
446     //! @name ブレンド
447     //@{
448 
449     //! @brief ブレンド処理を行います。
450     //!
451     //! @param[in,out] dst ブレンド処理結果です。
452     //! @param[in,out] dstWeights ブレンド処理結果の成分ごとの重みの累積値です。
453     //! このブレンドオペレーションでは使用しません。
454     //! @param[in] src ブレンド処理の入力です。
455     //! @param[in] srcWeights ブレンド処理の入力の重みです。
456     //!
457     //! @return ブレンド処理のループを継続するなら true を返します。
458     //!
Blend(anim::AnimResult * dst,float * dstWeights,const anim::AnimResult * src,const float * srcWeights)459     virtual bool Blend(
460         anim::AnimResult* dst,
461         float* dstWeights,
462         const anim::AnimResult* src,
463         const float* srcWeights) const
464     {
465         (void)dstWeights;
466         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
467         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
468         BlendScaleAccurate   (dstX, srcX, srcWeights[0]);
469         BlendRotateQuaternion(dstX, srcX, srcWeights[1]);
470         BlendTranslate       (dstX, srcX, srcWeights[2]);
471         return true;
472     }
473 
474     //! @brief ブレンド後の処理を行います。
475     //!
476     //! @param[in,out] result ブレンド処理結果です。
477     //! @param[in] weights ブレンド処理結果の成分ごとの重みの累積値です。
478     //! このブレンドオペレーションでは使用しません。
479     //!
480     //! @return 成功すれば true を返します。
481     //!
PostBlend(anim::AnimResult * result,const float * weights)482     virtual bool PostBlend(anim::AnimResult* result, const float* weights) const
483     {
484         (void)weights;
485         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(result);
486         const bool scaleRet = PostBlendAccurateScale(dstX);
487         return dstX->QuaternionToRotateMatrix() && scaleRet;
488     }
489 
490     //! @brief 上書き処理を行います。
491     //!
492     //! @param[in,out] dst ブレンド処理結果です。
493     //! @param[in] src ブレンド処理の入力です。
494     //!
495     //! @return すべての成分が上書きされたら true を返します。
496     //!
Override(anim::AnimResult * dst,const anim::AnimResult * src)497     virtual bool Override(anim::AnimResult* dst, const anim::AnimResult* src) const
498     {
499         CalculatedTransform* dstX = reinterpret_cast<CalculatedTransform*>(dst);
500         const CalculatedTransform* srcX = reinterpret_cast<const CalculatedTransform*>(src);
501         return OverrideTransform(dstX, srcX, FLAG_ACCURATE_SCALE | FLAG_QUATERNION_ROTATE);
502     }
503 
504     //@}
505 };
506 
507 //---------------------------------------------------------------------------
508 //! @brief トランスフォームアニメーションを評価するクラスです。
509 //!
510 //! アニメーションデータを保持し、ファンクションカーブの評価を行います。
511 //---------------------------------------------------------------------------
512 class TransformAnimEvaluator : public BaseAnimEvaluator
513 {
514 public:
515     NW_UT_RUNTIME_TYPEINFO;
516 
517     //----------------------------------------
518     //! @name 作成
519     //@{
520 
521     //! トランスフォームアニメーション評価を構築するクラスです。
522     class Builder
523     {
524     public:
525         //! コンストラクタです。
Builder()526         Builder()
527         : m_AnimData(NULL),
528           m_MaxMembers(64),
529           m_MaxAnimMembers(64),
530           m_AllocCache(false) {}
531 
532         //! アニメーションデータを設定します。
AnimData(const anim::ResAnim & animData)533         Builder& AnimData(const anim::ResAnim& animData) { m_AnimData = animData; return *this; }
534 
535         //! @brief アニメーション対象メンバの最大数を設定します。
536         //!
537         //! TransformAnimEvaluator::Bind に渡す AnimGroup の AnimGroup::GetMemberCount の値を設定してください。
538         //! 複数の AnimGroup に Bind する場合は、最大値を設定してください。
MaxMembers(int maxMembers)539         Builder& MaxMembers(int maxMembers)
540         {
541             NW_ASSERT(maxMembers > 0);
542             m_MaxMembers = maxMembers;
543             return *this;
544         }
545 
546         //! @brief 実際にアニメーションするメンバの最大数を設定します。
547         //!
548         //! AnimData() に渡す anim::res::ResAnim の anim::res::ResAnim::GetMemberAnimSetCount の値を設定してください。
549         //! TransformAnimEvaluator::ChangeAnim で複数の ResAnim を切り替える場合は、最大値を設定してください。
MaxAnimMembers(int maxAnimMembers)550         Builder& MaxAnimMembers(int maxAnimMembers)
551         {
552             NW_ASSERT(maxAnimMembers > 0);
553             m_MaxAnimMembers = maxAnimMembers;
554             return *this;
555         }
556 
557         //! キャッシュバッファを確保してキャッシュを有効にするかどうかを設定します。
AllocCache(bool allocCache)558         Builder& AllocCache(bool allocCache) { m_AllocCache = allocCache; return *this; }
559 
560         //! @brief 生成時に必要なメモリサイズを取得します。
561         //!
562         //! メモリサイズは Builder の設定によって変化します。
563         //! すべての設定が終わった後にこの関数を呼び出してください。
564         //!
565         //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
566         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
567         {
568             os::MemorySizeCalculator size(alignment);
569 
570             GetMemorySizeInternal(&size);
571 
572             return size.GetSizeWithPadding(alignment);
573         }
574 
575         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)576         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
577         {
578             os::MemorySizeCalculator& size = *pSize;
579 
580             size += sizeof(TransformAnimEvaluator);
581             BaseAnimEvaluator::GetMemorySizeForInitialize(pSize, m_MaxMembers, m_MaxAnimMembers);
582 
583             if (m_AllocCache)
584             {
585                 size += sizeof(CalculatedTransform) * m_MaxAnimMembers;
586             }
587         }
588 
589         //! @brief トランスフォームアニメーション評価を生成します。
590         //!
591         //! @param[in] allocator アロケータです。
592         //!
593         //! @return 生成されたトランスフォームアニメーション評価です。
594         //!
Create(os::IAllocator * allocator)595         TransformAnimEvaluator* Create(os::IAllocator* allocator)
596         {
597             void* buf = allocator->Alloc(sizeof(TransformAnimEvaluator));
598 
599             if (buf == NULL)
600             {
601                 return NULL;
602             }
603 
604             TransformAnimEvaluator* evaluator = new(buf) TransformAnimEvaluator(allocator);
605 
606             Result result = evaluator->Initialize(m_AnimData, m_MaxMembers, m_MaxAnimMembers, m_AllocCache);
607             NW_ASSERT(result.IsSuccess());
608 
609             return evaluator;
610         }
611 
612     private:
613         anim::ResAnim m_AnimData;
614         int m_MaxMembers;
615         int m_MaxAnimMembers;
616         bool m_AllocCache;
617     };
618 
619     //@}
620 
621     //----------------------------------------
622     //! @name 基本操作
623     //@{
624 
625     //! @brief  アニメーションを関連付けます。
626     //!
627     //!         Bind() よりも詳細なバインド結果を得ることができます。
628     //!
629     //!         アニメーションデータがあるボーンの、アニメーションカーブがないSRT要素に、
630     //!         この時点でバインドポーズをコピーします。
631     //!         そのため、この関数を呼び出した後からアニメーション評価を行うまでの間は
632     //!         スケルトンの姿勢が正しくない状態になりますのでご注意ください。
633     //!
634     //! @param[in] animGroup アニメーショングループです。
635     //!
636     //! @return バインドの結果を返します。
637     //!
638     //! @sa Bind
639     //! @sa BindResult
640     virtual Result TryBind(AnimGroup* animGroup);
641 
642     //! @brief アニメーションを変更します。
643     //!
644     //! 内部で Bind() を呼び出すため、スケルトンの姿勢が変化します。
645     //!
646     //! GetCacheBufferSizeNeeded() の値が変化しますので、
647     //! SetCacheBuffer() している場合はバッファの再設定が必要です。
648     //!
649     //! 内部で確保したキャッシュバッファは、自動的にサイズ変更されます。
650     //!
651     //! @sa Bind
652     //! @sa BaseAnimEvaluator::ChangeAnim
653     //! @param animData アニメーションデータです。
ChangeAnim(const nw::anim::ResAnim animData)654     virtual void ChangeAnim(const nw::anim::ResAnim animData)
655     {
656         // BaseAnimEvaluator::ChangeAnim()内でBind()が呼ばれ、
657         // そこでキャッシュを書き換えるので、キャッシュのResizeを先に行う
658         if (!m_IsCacheExternal && !m_CacheTransforms.Empty())
659         {
660             m_CacheTransforms.Resize(animData.GetMemberAnimSetCount());
661         }
662 
663         BaseAnimEvaluator::ChangeAnim(animData);
664     }
665 
666     //@}
667 
668     //----------------------------------------
669     //! @name 評価
670     //@{
671 
672     //! @brief メンバ単位でアニメーション結果を取得します。
673     //!
674     //! @param[out] target アニメーション結果を書き込む対象です。
675     //! @param[in] memberIdx メンバインデックスです。
676     //!
677     //! @return アニメーション結果を適用した場合は NULL でない値を返します。
678     //!
679     virtual const anim::AnimResult* GetResult(
680         void* target,
681         int memberIdx) const;
682 
683     //@}
684 
685     //----------------------------------------
686     //! @name 取得/設定
687     //@{
688 
689     //! スケールアニメを無効化しているかを取得します。
GetIsScaleDisabled()690     bool GetIsScaleDisabled() const { return m_IsScaleDisabled; }
691 
692     //! スケールアニメを無効化しているかを設定します。
SetIsScaleDisabled(bool isDisabled)693     void SetIsScaleDisabled(bool isDisabled) { m_IsScaleDisabled = isDisabled; }
694 
695     //! 回転アニメを無効化しているかを取得します。
GetIsRotateDisabled()696     bool GetIsRotateDisabled() const { return m_IsRotateDisabled; }
697 
698     //! 回転アニメを無効化しているかを設定します。
SetIsRotateDisabled(bool isDisabled)699     void SetIsRotateDisabled(bool isDisabled) { m_IsRotateDisabled = isDisabled; }
700 
701     //! 移動アニメを無効化しているかを取得します。
GetIsTranslateDisabled()702     bool GetIsTranslateDisabled() const { return m_IsTranslateDisabled; }
703 
704     //! 移動アニメを無効化しているかを設定します。
SetIsTranslateDisabled(bool isDisabled)705     void SetIsTranslateDisabled(bool isDisabled) { m_IsTranslateDisabled = isDisabled; }
706 
707     //! @brief メンバに関連付けられたアニメーションが存在するかどうかを取得します。
708     //!
709     //! @param[in] memberIdx メンバインデックスです。
710     //!
711     //! @return アニメーションが存在すれば true を返します。
712     //!
HasMemberAnim(int memberIdx)713     virtual bool HasMemberAnim(int memberIdx) const
714     {
715         NW_MINMAXLT_ASSERT(memberIdx, 0, m_BindIndexTable.Size());
716         if (m_AnimData.ptr() == NULL)
717         {
718             return (0 <= memberIdx && memberIdx < m_AnimGroup->GetMemberCount());
719         }
720         else
721         {
722             return m_BindIndexTable[memberIdx] != NotFoundIndex;
723         }
724     }
725 
726     //@}
727 
728     //----------------------------------------
729     //! @name キャッシュ
730     //@{
731 
732     //----------------------------------------------------------
733     //! :private
UpdateCacheNonVirtual()734     void UpdateCacheNonVirtual()
735     {
736         if (!m_CacheTransforms.Empty() && m_IsCacheDirty)
737         {
738             if (m_AnimData.ptr() != NULL)
739             {
740                 for (int memberIdx = 0; memberIdx < m_AnimGroup->GetMemberCount(); ++memberIdx)
741                 {
742                     const int animIdx = m_BindIndexTable[memberIdx];
743                     if (animIdx != NotFoundIndex)
744                     {
745                         GetResult(&m_CacheTransforms[animIdx], memberIdx);
746                     }
747                 }
748             }
749             m_IsCacheDirty = false;
750         }
751     }
752 
753     //! アニメーション評価結果の内部キャッシュが古ければ更新します。
UpdateCache()754     virtual void UpdateCache() { this->UpdateCacheNonVirtual(); }
755 
756     //! キャッシュバッファに必要なサイズ(バイト数)を取得します。
GetCacheBufferSizeNeeded()757     virtual int GetCacheBufferSizeNeeded() const
758     {
759         return m_AnimData.GetMemberAnimSetCount() * sizeof(CalculatedTransform);
760     }
761 
762     //! キャッシュバッファを取得します。
GetCacheBuffer()763     virtual const void* GetCacheBuffer() const { return m_CacheTransforms.Elements(); }
764 
765     //! @brief キャッシュバッファを設定します。
766     //! この関数で指定したキャッシュバッファはデストラクタで開放されません。
767     //!
768     //! @param[in] buf キャッシュバッファ用のメモリの先頭アドレスです。
769     //! NULL の場合、キャッシュが無効になります。
770     //! @param[in] size キャッシュバッファのサイズ(バイト数)です。
771     //!
SetCacheBuffer(void * buf,int size)772     virtual void SetCacheBuffer(void* buf, int size)
773     {
774         if (buf != NULL)
775         {
776             NW_ASSERT(size >= GetCacheBufferSizeNeeded());
777             const int maxCalculatedTransforms = size / sizeof(CalculatedTransform);
778             m_CacheTransforms = ut::MoveArray<CalculatedTransform>(buf, maxCalculatedTransforms);
779             m_CacheTransforms.Resize(maxCalculatedTransforms);
780             m_IsCacheDirty = true;
781             m_IsCacheExternal = true;
782         }
783         else
784         {
785             m_CacheTransforms = ut::MoveArray<CalculatedTransform>();
786         }
787     }
788 
789     //@}
790 
791 protected:
792     //----------------------------------------
793     //! @name コンストラクタ/デストラクタ
794     //@{
795 
796     //! コンストラクタです。
797     //!
798     //! :private
TransformAnimEvaluator(os::IAllocator * allocator)799     TransformAnimEvaluator(
800         os::IAllocator* allocator)
801     : BaseAnimEvaluator(allocator, ANIMTYPE_TRANSFORM_SIMPLE),
802       m_IsScaleDisabled(false),
803       m_IsRotateDisabled(false),
804       m_IsTranslateDisabled(false)
805     {
806     }
807 
808     //! デストラクタです。
809     //!
810     //! :private
~TransformAnimEvaluator()811     virtual ~TransformAnimEvaluator() {}
812 
813     //@}
814 
815     //! @details :private
Initialize(const anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)816     virtual Result Initialize(
817         const anim::ResAnim& animData,
818         const int maxMembers,
819         const int maxAnimMembers,
820         bool allocCache)
821     {
822         Result result = BaseAnimEvaluator::Initialize(animData, maxMembers, maxAnimMembers);
823         NW_ENSURE_AND_RETURN(result);
824 
825         if (allocCache)
826         {
827             void* memory = GetAllocator().Alloc(sizeof(CalculatedTransform) * maxAnimMembers);
828             if (memory == NULL)
829             {
830                 result |= Result::MASK_FAIL_BIT;
831             }
832             NW_ENSURE_AND_RETURN(result);
833 
834             m_CacheTransforms = ut::MoveArray<CalculatedTransform>(memory, maxAnimMembers, &GetAllocator());
835             m_CacheTransforms.Resize(animData.GetMemberAnimSetCount());
836         }
837 
838         return result;
839     }
840 
841     bool m_IsScaleDisabled; //!< @details :private
842     bool m_IsRotateDisabled; //!< @details :private
843     bool m_IsTranslateDisabled; //!< @details :private
844 
845     ut::MoveArray<CalculatedTransform> m_CacheTransforms; //!< @details :private
846 
847 private:
848     // アニメーションカーブが存在しないメンバを、OriginalValueで初期化します。
849     void ResetNoAnimMember(AnimGroup* animGroup, anim::ResAnim animData);
850 
851     const anim::AnimResult* GetResultFast(void* target, int memberIdx) const;
852     const anim::AnimResult* GetResultCommon(void* target, int memberIdx, bool writeNoAnimMember) const;
853 
854     // メンバアニメーションを評価します。
855     // @param[in] writeNoAnimMember trueなら、アニメーションのない要素にOriginalValueを上書きします。
856     void EvaluateMemberAnim(
857         CalculatedTransform* result,
858         anim::ResTransformAnim transformAnim,
859         float frame,
860         const math::Transform3* originalTransform,
861         bool writeNoAnimMember) const;
862 
863     // ベイク済みのメンバアニメーションを評価します。
864     // @param[in] writeNoAnimMember trueなら、アニメーションのない要素にOriginalValueを上書きします。
865     void EvaluateMemberBakedAnim(
866         CalculatedTransform* result,
867         anim::ResBakedTransformAnim transformAnim,
868         float frame,
869         const math::Transform3* originalTransform,
870         bool writeNoAnimMember) const;
871 
872     void UpdateFlagsCommon(CalculatedTransform* transform) const;
873     void UpdateFlags(CalculatedTransform* transform) const;
874 
875     // CalculatedTransformのフラグを、Bakeされた情報をもとにして更新します。
876     void ApplyBakedFlags(CalculatedTransform* transform, bit32 flags) const;
877 
878     friend class AnimBinding;
879 };
880 
881 //---------------------------------------------------------------------------
882 //! @brief トランスフォームアニメーション評価結果を補間ブレンドするクラスです。
883 //!
884 //! ブレンドは各メンバの移動・回転・スケール成分ごとに行われます。
885 //!
886 //! 動作の詳細は、 AnimInterpolator をご覧ください。
887 //---------------------------------------------------------------------------
888 class TransformAnimInterpolator : public AnimInterpolator
889 {
890 public:
891     NW_UT_RUNTIME_TYPEINFO;
892 
893     //----------------------------------------
894     //! @name 作成
895     //@{
896 
897     //! @brief トランスフォームアニメーション補間を構築するクラスです。
898     //!
899     //! バージョン 1.0.1 以前の補間法に戻すためには、IsOldMethod か IgnoreNoAnimMember に true を指定してください。
900     //!
901     //! 1.0.1 以前の補間方法と現在の補間方法の違いの詳細については、アニメーションのドキュメント(高度な機能)を参照ください。
902     class Builder
903     {
904     public:
905         //! コンストラクタです。
Builder()906         Builder()
907         : m_MaxAnimObjects(2),
908           m_IgnoreNoAnimMember(false) {}
909 
910         //! 最大アニメーションオブジェクト数を設定します。
MaxAnimObjects(int maxAnimObjects)911         Builder& MaxAnimObjects(int maxAnimObjects)
912         {
913             NW_ASSERT(maxAnimObjects > 0);
914             m_MaxAnimObjects = maxAnimObjects;
915             return *this;
916         }
917 
918         //! @brief アニメーションが存在しないメンバを無視するかどうかを設定します。
919         //!
920         //! デフォルトでは、アニメーションが存在しないメンバはバインド時の値がブレンドされます。
921         //! IgnoreNoAnimMember に true を設定すると、
922         //! 重みの正規化がメンバ毎に行なわれ、アニメーションが存在しないメンバは重み 0 としてブレンドされます。
923         //!
924         //! この挙動は バージョン 1.0.1 以前の補間法と同じです。
925         //!
IgnoreNoAnimMember(bool ignoreNoAnimMember)926         Builder& IgnoreNoAnimMember(bool ignoreNoAnimMember) { m_IgnoreNoAnimMember = ignoreNoAnimMember; return *this; }
927 
928         //! @brief 生成時に必要なメモリサイズを取得します。
929         //!
930         //! メモリサイズは Builder の設定によって変化します。
931         //! すべての設定が終わった後にこの関数を呼び出してください。
932         //!
933         //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
934         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
935         {
936             os::MemorySizeCalculator size(alignment);
937 
938             GetMemorySizeInternal(&size);
939 
940             return size.GetSizeWithPadding(alignment);
941         }
942 
943         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)944         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
945         {
946             os::MemorySizeCalculator& size = *pSize;
947 
948             size += sizeof(TransformAnimInterpolator);
949             TransformAnimInterpolator::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects);
950         }
951 
952         //! @brief トランスフォームアニメーション補間を生成します。
953         //!
954         //! @param[in] allocator アロケータです。
955         //!
956         //! @return 生成されたトランスフォームアニメーション補間です。
957         //!
Create(os::IAllocator * allocator)958         TransformAnimInterpolator* Create(os::IAllocator* allocator)
959         {
960             void* buf = allocator->Alloc(sizeof(TransformAnimInterpolator));
961 
962             if (buf == NULL)
963             {
964                 return NULL;
965             }
966 
967             TransformAnimInterpolator* interpolator = new(buf) TransformAnimInterpolator(allocator);
968 
969             Result result = interpolator->Initialize(m_MaxAnimObjects, m_IgnoreNoAnimMember);
970             NW_ASSERT(result.IsSuccess());
971 
972             return interpolator;
973         }
974 
975     private:
976         int m_MaxAnimObjects;
977         bool m_IgnoreNoAnimMember;
978     };
979 
980     //@}
981 
982     //----------------------------------------
983     //! @name 評価
984     //@{
985 
986     //! @brief メンバ単位でアニメーション結果を取得します。
987     //!
988     //! @param[out] target アニメーション結果を書き込む対象です。
989     //! @param[in] memberIdx メンバインデックスです。
990     //!
991     //! @return アニメーション結果を適用した場合は NULL でない値を返します。
992     //!
993     virtual const anim::AnimResult* GetResult(
994         void* target,
995         int memberIdx) const;
996 
997     //@}
998 
999 protected:
1000     //----------------------------------------
1001     //! @name コンストラクタ/デストラクタ
1002     //@{
1003 
1004     //! コンストラクタです。
1005     //!
1006     //! :private
TransformAnimInterpolator(os::IAllocator * allocator)1007     TransformAnimInterpolator(
1008         os::IAllocator* allocator)
1009     : AnimInterpolator(allocator)
1010     {}
1011 
1012     //! デストラクタです。
1013     //!
1014     //! :private
~TransformAnimInterpolator()1015     virtual ~TransformAnimInterpolator() {}
1016 
1017     //@}
1018 };
1019 
1020 //---------------------------------------------------------------------------
1021 //! @details :private
1022 //! @brief トランスフォームアニメーション評価結果を加算ブレンドするクラスです。
1023 //!
1024 //! ブレンドは各メンバの移動・回転・スケール成分ごとに行われます。
1025 //---------------------------------------------------------------------------
1026 class TransformAnimAdder : public AnimAdder
1027 {
1028 public:
1029     NW_UT_RUNTIME_TYPEINFO;
1030 
1031     //----------------------------------------
1032     //! @name 作成
1033     //@{
1034 
1035     //! トランスフォームアニメーション加算を構築するクラスです。
1036     class Builder
1037     {
1038     public:
1039         //! コンストラクタです。
Builder()1040         Builder()
1041         : m_MaxAnimObjects(2) {}
1042 
1043         //! 最大アニメーションオブジェクト数を設定します。
MaxAnimObjects(int maxAnimObjects)1044         Builder& MaxAnimObjects(int maxAnimObjects)
1045         {
1046             NW_ASSERT(maxAnimObjects > 0);
1047             m_MaxAnimObjects = maxAnimObjects;
1048             return *this;
1049         }
1050 
1051         //! @brief 生成時に必要なメモリサイズを取得します。
1052         //!
1053         //! メモリサイズは Builder の設定によって変化します。
1054         //! すべての設定が終わった後にこの関数を呼び出してください。
1055         //!
1056         //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
1057         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
1058         {
1059             os::MemorySizeCalculator size(alignment);
1060 
1061             GetMemorySizeInternal(&size);
1062 
1063             return size.GetSizeWithPadding(alignment);
1064         }
1065 
1066         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)1067         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
1068         {
1069             os::MemorySizeCalculator& size = *pSize;
1070 
1071             size += sizeof(TransformAnimAdder);
1072             TransformAnimAdder::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects);
1073         }
1074 
1075         //! @brief トランスフォームアニメーション加算を生成します。
1076         //!
1077         //! @param[in] allocator アロケータです。
1078         //!
1079         //! @return 生成されたトランスフォームアニメーション加算です。
1080         //!
Create(os::IAllocator * allocator)1081         TransformAnimAdder* Create(os::IAllocator* allocator)
1082         {
1083             void* buf = allocator->Alloc(sizeof(TransformAnimAdder));
1084 
1085             if (buf == NULL)
1086             {
1087                 return NULL;
1088             }
1089 
1090             TransformAnimAdder* adder = new(buf) TransformAnimAdder(allocator);
1091 
1092             Result result = adder->Initialize(m_MaxAnimObjects);
1093             NW_ASSERT(result.IsSuccess());
1094 
1095             return adder;
1096         }
1097 
1098     private:
1099         int m_MaxAnimObjects;
1100     };
1101 
1102     //@}
1103 
1104     //----------------------------------------
1105     //! @name 評価
1106     //@{
1107 
1108     //! @brief メンバ単位でアニメーション結果を取得します。
1109     //!
1110     //! @param[out] target アニメーション結果を書き込む対象です。
1111     //! @param[in] memberIdx メンバインデックスです。
1112     //!
1113     //! @return アニメーション結果を適用した場合は NULL でない値を返します。
1114     //!
1115     virtual const anim::AnimResult* GetResult(
1116         void* target,
1117         int memberIdx) const;
1118 
1119     //@}
1120 
1121 protected:
1122     //----------------------------------------
1123     //! @name コンストラクタ/デストラクタ
1124     //@{
1125 
1126     //! コンストラクタです。
TransformAnimAdder(os::IAllocator * allocator)1127     TransformAnimAdder(
1128         os::IAllocator* allocator)
1129     : AnimAdder(allocator)
1130     {}
1131 
1132     //! デストラクタです。
~TransformAnimAdder()1133     virtual ~TransformAnimAdder() {}
1134 
1135     //@}
1136 };
1137 
1138 //---------------------------------------------------------------------------
1139 //! @brief トランスフォームアニメーション評価結果を上書きブレンドするクラスです。
1140 //!
1141 //! ブレンドは各メンバの移動・回転・スケール成分ごとに行われます。
1142 //!
1143 //! 動作の詳細は、 AnimOverrider をご覧ください。
1144 //---------------------------------------------------------------------------
1145 class TransformAnimOverrider : public AnimOverrider
1146 {
1147 public:
1148     NW_UT_RUNTIME_TYPEINFO;
1149 
1150     //----------------------------------------
1151     //! @name 作成
1152     //@{
1153 
1154     //! トランスフォームアニメーション上書きを構築するクラスです。
1155     class Builder
1156     {
1157     public:
1158         //! コンストラクタです。
Builder()1159         Builder()
1160         : m_MaxAnimObjects(2) {}
1161 
1162         //! 最大アニメーションオブジェクト数を設定します。
MaxAnimObjects(int maxAnimObjects)1163         Builder& MaxAnimObjects(int maxAnimObjects)
1164         {
1165             NW_ASSERT(maxAnimObjects > 0);
1166             m_MaxAnimObjects = maxAnimObjects;
1167             return *this;
1168         }
1169 
1170         //! @brief 生成時に必要なメモリサイズを取得します。
1171         //!
1172         //! メモリサイズは Builder の設定によって変化します。
1173         //! すべての設定が終わった後にこの関数を呼び出してください。
1174         //!
1175         //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。
1176         size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const
1177         {
1178             os::MemorySizeCalculator size(alignment);
1179 
1180             GetMemorySizeInternal(&size);
1181 
1182             return size.GetSizeWithPadding(alignment);
1183         }
1184 
1185         //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize)1186         void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const
1187         {
1188             os::MemorySizeCalculator& size = *pSize;
1189 
1190             size += sizeof(TransformAnimOverrider);
1191             TransformAnimOverrider::GetMemorySizeForInitialize(pSize, m_MaxAnimObjects);
1192         }
1193 
1194         //! @brief トランスフォームアニメーション上書きを生成します。
1195         //!
1196         //! @param[in] allocator アロケータです。
1197         //!
1198         //! @return 生成されたトランスフォームアニメーション上書きです。
1199         //!
Create(os::IAllocator * allocator)1200         TransformAnimOverrider* Create(os::IAllocator* allocator)
1201         {
1202             void* buf = allocator->Alloc(sizeof(TransformAnimOverrider));
1203 
1204             if (buf == NULL)
1205             {
1206                 return NULL;
1207             }
1208 
1209             TransformAnimOverrider* overrider = new(buf) TransformAnimOverrider(allocator);
1210 
1211             Result result = overrider->Initialize(m_MaxAnimObjects);
1212             NW_ASSERT(result.IsSuccess());
1213 
1214             return overrider;
1215         }
1216 
1217     private:
1218         int m_MaxAnimObjects;
1219     };
1220 
1221     //@}
1222 
1223     //----------------------------------------
1224     //! @name 評価
1225     //@{
1226 
1227     //! @brief メンバ単位でアニメーション結果を取得します。
1228     //!
1229     //! @param[out] target アニメーション結果を書き込む対象です。
1230     //! @param[in] memberIdx メンバインデックスです。
1231     //!
1232     //! @return アニメーション結果を適用した場合は NULL でない値を返します。
1233     //!
1234     virtual const anim::AnimResult* GetResult(
1235         void* target,
1236         int memberIdx) const;
1237 
1238     //@}
1239 
1240 protected:
1241     //----------------------------------------
1242     //! @name コンストラクタ/デストラクタ
1243     //@{
1244 
1245     //! コンストラクタです。
1246     //!
1247     //! :private
TransformAnimOverrider(os::IAllocator * allocator)1248     TransformAnimOverrider(
1249         os::IAllocator* allocator)
1250     : AnimOverrider(allocator)
1251     {}
1252 
1253     //! デストラクタです。
1254     //!
1255     //! :private
~TransformAnimOverrider()1256     virtual ~TransformAnimOverrider() {}
1257 
1258     //@}
1259 };
1260 
1261 } // namespace gfx
1262 } // namespace nw
1263 
1264 #endif // NW_GFX_TRANSFORMANIM_H_
1265