1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: gfx_TransformAnimEvaluator.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_TRANSFORMANIMEVALUATOR_H_ 19 #define NW_GFX_TRANSFORMANIMEVALUATOR_H_ 20 21 #include <nw/gfx/gfx_BaseAnimEvaluator.h> 22 23 namespace nw { 24 namespace gfx { 25 26 //--------------------------------------------------------------------------- 27 //! @brief トランスフォームアニメーションを評価するクラスです。 28 //! 29 //! アニメーションデータを保持し、ファンクションカーブの評価を行います。 30 //--------------------------------------------------------------------------- 31 class TransformAnimEvaluator : public BaseAnimEvaluator 32 { 33 public: 34 NW_UT_RUNTIME_TYPEINFO; 35 36 //---------------------------------------- 37 //! @name 作成 38 //@{ 39 40 //! トランスフォームアニメーション評価を構築するクラスです。 41 class Builder 42 { 43 public: 44 //! コンストラクタです。 Builder()45 Builder() 46 : m_AnimData(NULL), 47 m_MaxMembers(64), 48 m_MaxAnimMembers(64), 49 m_AllocCache(false) {} 50 51 //! アニメーションデータを設定します。 AnimData(const anim::ResAnim & animData)52 Builder& AnimData(const anim::ResAnim& animData) { m_AnimData = animData; return *this; } 53 54 //! @brief アニメーション対象メンバの最大数を設定します。 55 //! 56 //! TransformAnimEvaluator::Bind に渡す AnimGroup の AnimGroup::GetMemberCount の値を設定してください。 57 //! 複数の AnimGroup に Bind する場合は、最大値を設定してください。 MaxMembers(int maxMembers)58 Builder& MaxMembers(int maxMembers) 59 { 60 NW_ASSERT(maxMembers > 0); 61 m_MaxMembers = maxMembers; 62 return *this; 63 } 64 65 //! @brief 実際にアニメーションするメンバの最大数を設定します。 66 //! 67 //! AnimData() に渡す anim::res::ResAnim の anim::res::ResAnim::GetMemberAnimSetCount の値を設定してください。 68 //! TransformAnimEvaluator::ChangeAnim で複数の ResAnim を切り替える場合は、最大値を設定してください。 MaxAnimMembers(int maxAnimMembers)69 Builder& MaxAnimMembers(int maxAnimMembers) 70 { 71 NW_ASSERT(maxAnimMembers > 0); 72 m_MaxAnimMembers = maxAnimMembers; 73 return *this; 74 } 75 76 //! キャッシュバッファを確保してキャッシュを有効にするかどうかを設定します。 AllocCache(bool allocCache)77 Builder& AllocCache(bool allocCache) { m_AllocCache = allocCache; return *this; } 78 79 //! @brief 生成時に必要なメモリサイズを取得します。 80 //! 81 //! メモリサイズは Builder の設定によって変化します。 82 //! すべての設定が終わった後にこの関数を呼び出してください。 83 //! 84 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 85 size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const 86 { 87 os::MemorySizeCalculator size(alignment); 88 89 GetMemorySizeInternal(&size); 90 91 return size.GetSizeWithPadding(alignment); 92 } 93 94 //! @details :private GetMemorySizeInternal(os::MemorySizeCalculator * pSize)95 void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const 96 { 97 os::MemorySizeCalculator& size = *pSize; 98 99 size += sizeof(TransformAnimEvaluator); 100 BaseAnimEvaluator::GetMemorySizeForInitialize(pSize, m_MaxMembers, m_MaxAnimMembers); 101 102 if (m_AllocCache) 103 { 104 size += sizeof(CalculatedTransform) * m_MaxAnimMembers; 105 } 106 } 107 108 //! @brief トランスフォームアニメーション評価を生成します。 109 //! 110 //! @param[in] allocator アロケータです。 111 //! 112 //! @return 生成されたトランスフォームアニメーション評価です。 113 //! Create(os::IAllocator * allocator)114 TransformAnimEvaluator* Create(os::IAllocator* allocator) 115 { 116 void* buf = allocator->Alloc(sizeof(TransformAnimEvaluator)); 117 118 if (buf == NULL) 119 { 120 return NULL; 121 } 122 123 TransformAnimEvaluator* evaluator = new(buf) TransformAnimEvaluator(allocator); 124 125 Result result = evaluator->Initialize(m_AnimData, m_MaxMembers, m_MaxAnimMembers, m_AllocCache); 126 NW_ASSERT(result.IsSuccess()); 127 128 return evaluator; 129 } 130 131 private: 132 anim::ResAnim m_AnimData; 133 int m_MaxMembers; 134 int m_MaxAnimMembers; 135 bool m_AllocCache; 136 }; 137 138 //@} 139 140 //---------------------------------------- 141 //! @name 基本操作 142 //@{ 143 144 //! @brief アニメーションを関連付けます。 145 //! 146 //! Bind() よりも詳細なバインド結果を得ることができます。 147 //! 148 //! アニメーションデータがあるボーンの、アニメーションカーブがないSRT要素に、 149 //! この時点でバインドポーズをコピーします。 150 //! そのため、この関数を呼び出した後からアニメーション評価を行うまでの間は 151 //! スケルトンの姿勢が正しくない状態になりますのでご注意ください。 152 //! 153 //! @param[in] animGroup アニメーショングループです。 154 //! 155 //! @return バインドの結果を返します。 156 //! 157 //! @sa Bind 158 //! @sa BindResult 159 virtual Result TryBind(AnimGroup* animGroup); 160 161 //! @brief アニメーションを変更します。 162 //! 163 //! 内部で Bind() を呼び出すため、スケルトンの姿勢が変化します。 164 //! 165 //! GetCacheBufferSizeNeeded() の値が変化しますので、 166 //! SetCacheBuffer() している場合はバッファの再設定が必要です。 167 //! 168 //! 内部で確保したキャッシュバッファは、自動的にサイズ変更されます。 169 //! 170 //! @sa Bind 171 //! @sa BaseAnimEvaluator::ChangeAnim 172 //! @param animData アニメーションデータです。 ChangeAnim(const nw::anim::ResAnim animData)173 virtual void ChangeAnim(const nw::anim::ResAnim animData) 174 { 175 // BaseAnimEvaluator::ChangeAnim()内でBind()が呼ばれ、 176 // そこでキャッシュを書き換えるので、キャッシュのResizeを先に行う 177 if (!m_IsCacheExternal && !m_CacheTransforms.Empty()) 178 { 179 m_CacheTransforms.Resize(animData.GetMemberAnimSetCount()); 180 } 181 182 BaseAnimEvaluator::ChangeAnim(animData); 183 } 184 185 //@} 186 187 //---------------------------------------- 188 //! @name 評価 189 //@{ 190 191 //! @brief メンバ単位でアニメーション結果を取得します。 192 //! 193 //! @param[out] target アニメーション結果を書き込む対象です。 194 //! @param[in] memberIdx メンバインデックスです。 195 //! 196 //! @return アニメーション結果を適用した場合は NULL でない値を返します。 197 //! 198 virtual const anim::AnimResult* GetResult( 199 void* target, 200 int memberIdx) const; 201 202 //@} 203 204 //---------------------------------------- 205 //! @name 取得/設定 206 //@{ 207 208 //! スケールアニメを無効化しているかを取得します。 GetIsScaleDisabled()209 bool GetIsScaleDisabled() const { return m_IsScaleDisabled; } 210 211 //! スケールアニメを無効化しているかを設定します。 SetIsScaleDisabled(bool isDisabled)212 void SetIsScaleDisabled(bool isDisabled) { m_IsScaleDisabled = isDisabled; } 213 214 //! 回転アニメを無効化しているかを取得します。 GetIsRotateDisabled()215 bool GetIsRotateDisabled() const { return m_IsRotateDisabled; } 216 217 //! 回転アニメを無効化しているかを設定します。 SetIsRotateDisabled(bool isDisabled)218 void SetIsRotateDisabled(bool isDisabled) { m_IsRotateDisabled = isDisabled; } 219 220 //! 移動アニメを無効化しているかを取得します。 GetIsTranslateDisabled()221 bool GetIsTranslateDisabled() const { return m_IsTranslateDisabled; } 222 223 //! 移動アニメを無効化しているかを設定します。 SetIsTranslateDisabled(bool isDisabled)224 void SetIsTranslateDisabled(bool isDisabled) { m_IsTranslateDisabled = isDisabled; } 225 226 //! @brief メンバに関連付けられたアニメーションが存在するかどうかを取得します。 227 //! 228 //! @param[in] memberIdx メンバインデックスです。 229 //! 230 //! @return アニメーションが存在すれば true を返します。 231 //! HasMemberAnim(int memberIdx)232 virtual bool HasMemberAnim(int memberIdx) const 233 { 234 NW_MINMAXLT_ASSERT(memberIdx, 0, m_BindIndexTable.Size()); 235 if (m_AnimData.ptr() == NULL) 236 { 237 return (0 <= memberIdx && memberIdx < m_AnimGroup->GetMemberCount()); 238 } 239 else 240 { 241 return m_BindIndexTable[memberIdx] != NotFoundIndex; 242 } 243 } 244 245 //@} 246 247 //---------------------------------------- 248 //! @name キャッシュ 249 //@{ 250 251 //---------------------------------------------------------- 252 //! :private UpdateCacheNonVirtual()253 void UpdateCacheNonVirtual() 254 { 255 if (!m_CacheTransforms.Empty() && m_IsCacheDirty) 256 { 257 if (m_AnimData.ptr() != NULL) 258 { 259 for (int memberIdx = 0; memberIdx < m_AnimGroup->GetMemberCount(); ++memberIdx) 260 { 261 const int animIdx = m_BindIndexTable[memberIdx]; 262 if (animIdx != NotFoundIndex) 263 { 264 GetResult(&m_CacheTransforms[animIdx], memberIdx); 265 } 266 } 267 } 268 m_IsCacheDirty = false; 269 } 270 } 271 272 //! アニメーション評価結果の内部キャッシュが古ければ更新します。 UpdateCache()273 virtual void UpdateCache() { this->UpdateCacheNonVirtual(); } 274 275 //! キャッシュバッファに必要なサイズ(バイト数)を取得します。 GetCacheBufferSizeNeeded()276 virtual int GetCacheBufferSizeNeeded() const 277 { 278 return m_AnimData.GetMemberAnimSetCount() * sizeof(CalculatedTransform); 279 } 280 281 //! キャッシュバッファを取得します。 GetCacheBuffer()282 virtual const void* GetCacheBuffer() const { return m_CacheTransforms.Elements(); } 283 284 //! @brief キャッシュバッファを設定します。 285 //! この関数で指定したキャッシュバッファはデストラクタで開放されません。 286 //! 287 //! @param[in] buf キャッシュバッファ用のメモリの先頭アドレスです。 288 //! NULL の場合、キャッシュが無効になります。 289 //! @param[in] size キャッシュバッファのサイズ(バイト数)です。 290 //! SetCacheBuffer(void * buf,int size)291 virtual void SetCacheBuffer(void* buf, int size) 292 { 293 if (buf != NULL) 294 { 295 NW_ASSERT(size >= GetCacheBufferSizeNeeded()); 296 const int maxCalculatedTransforms = size / sizeof(CalculatedTransform); 297 m_CacheTransforms = ut::MoveArray<CalculatedTransform>(buf, maxCalculatedTransforms); 298 m_CacheTransforms.Resize(maxCalculatedTransforms); 299 m_IsCacheDirty = true; 300 m_IsCacheExternal = true; 301 } 302 else 303 { 304 m_CacheTransforms = ut::MoveArray<CalculatedTransform>(); 305 } 306 } 307 308 //! @brief 必要があれば SRT ごとの重みを無効化します。 309 //! 310 //! @details 311 //! 引数 animObj が TransformAnimEvaluator のインスタンスの場合に、 312 //! アニメーション無効化の設定を重みに反映します。 313 //! 314 //! @param[in] weights SRT ごとの重みです。 315 //! @param[in] animObj アニメーションオブジェクトです。 316 //! 317 //! @sa GetIsScaleDisabled 318 //! @sa GetIsRotateDisabled 319 //! @sa GetIsTranslateDisabled 320 //! 321 //! :private DisableSRTWeightsIfNeeded(float * weights,const AnimObject * animObj)322 static void DisableSRTWeightsIfNeeded(float* weights, const AnimObject* animObj) 323 { 324 const TransformAnimEvaluator* evaluator = 325 ut::DynamicCast<const TransformAnimEvaluator*>(animObj); 326 if (evaluator != NULL) 327 { 328 if (evaluator->GetIsScaleDisabled()) 329 { 330 weights[0] = TransformAnimBlendOp::WeightDiscard; 331 } 332 333 if (evaluator->GetIsRotateDisabled()) 334 { 335 weights[1] = TransformAnimBlendOp::WeightDiscard; 336 } 337 338 if (evaluator->GetIsTranslateDisabled()) 339 { 340 weights[2] = TransformAnimBlendOp::WeightDiscard; 341 } 342 } 343 } 344 345 //! @brief SRT ごとの重みがすべてゼロかどうか判定します。 346 //! 347 //! @param[in] weights SRT ごとの重みです。 348 //! 349 //! @return 重みがすべてゼロなら true を返します。 350 //! 351 //! :private CheckWeightsNearlyZero(const float * weights)352 static bool CheckWeightsNearlyZero(const float* weights) 353 { 354 NW_NULL_ASSERT(weights); 355 356 return 357 AnimWeightNearlyEqualZero(weights[0]) && 358 AnimWeightNearlyEqualZero(weights[1]) && 359 AnimWeightNearlyEqualZero(weights[2]); 360 } 361 362 //@} 363 364 protected: 365 //---------------------------------------- 366 //! @name コンストラクタ/デストラクタ 367 //@{ 368 369 //! コンストラクタです。 370 //! 371 //! :private TransformAnimEvaluator(os::IAllocator * allocator)372 TransformAnimEvaluator( 373 os::IAllocator* allocator) 374 : BaseAnimEvaluator(allocator, ANIMTYPE_TRANSFORM_SIMPLE), 375 m_IsScaleDisabled(false), 376 m_IsRotateDisabled(false), 377 m_IsTranslateDisabled(false) 378 { 379 } 380 381 //! デストラクタです。 382 //! 383 //! :private ~TransformAnimEvaluator()384 virtual ~TransformAnimEvaluator() {} 385 386 //@} 387 388 //! @details :private Initialize(const anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)389 Result Initialize( 390 const anim::ResAnim& animData, 391 const int maxMembers, 392 const int maxAnimMembers, 393 bool allocCache) 394 { 395 Result result = BaseAnimEvaluator::Initialize(animData, maxMembers, maxAnimMembers); 396 NW_ENSURE_AND_RETURN(result); 397 398 if (allocCache) 399 { 400 void* memory = GetAllocator().Alloc(sizeof(CalculatedTransform) * maxAnimMembers); 401 if (memory == NULL) 402 { 403 result |= Result::MASK_FAIL_BIT; 404 } 405 NW_ENSURE_AND_RETURN(result); 406 407 m_CacheTransforms = ut::MoveArray<CalculatedTransform>(memory, maxAnimMembers, &GetAllocator()); 408 m_CacheTransforms.Resize(animData.GetMemberAnimSetCount()); 409 } 410 411 return result; 412 } 413 414 bool m_IsScaleDisabled; //!< @details :private 415 bool m_IsRotateDisabled; //!< @details :private 416 bool m_IsTranslateDisabled; //!< @details :private 417 418 ut::MoveArray<CalculatedTransform> m_CacheTransforms; //!< @details :private 419 420 private: 421 // アニメーションカーブが存在しないメンバを、OriginalValueで初期化します。 422 void ResetNoAnimMember(AnimGroup* animGroup, anim::ResAnim animData); 423 424 const anim::AnimResult* GetResultFast(void* target, int memberIdx) const; 425 const anim::AnimResult* GetResultCommon(void* target, int memberIdx, bool writeNoAnimMember) const; 426 427 // メンバアニメーションを評価します。 428 // @param[in] writeNoAnimMember trueなら、アニメーションのない要素にOriginalValueを上書きします。 429 void EvaluateMemberAnim( 430 CalculatedTransform* result, 431 anim::ResTransformAnim transformAnim, 432 float frame, 433 const math::Transform3* originalTransform, 434 bool writeNoAnimMember) const; 435 436 // ベイク済みのメンバアニメーションを評価します。 437 // @param[in] writeNoAnimMember trueなら、アニメーションのない要素にOriginalValueを上書きします。 438 void EvaluateMemberBakedAnim( 439 CalculatedTransform* result, 440 anim::ResBakedTransformAnim transformAnim, 441 float frame, 442 const math::Transform3* originalTransform, 443 bool writeNoAnimMember) const; 444 445 void UpdateFlagsCommon(CalculatedTransform* transform) const; 446 void UpdateFlags(CalculatedTransform* transform) const; 447 448 // CalculatedTransformのフラグを、Bakeされた情報をもとにして更新します。 449 void ApplyBakedFlags(CalculatedTransform* transform, bit32 flags) const; 450 451 friend class AnimBinding; 452 }; 453 454 } // namespace gfx 455 } // namespace nw 456 457 #endif // NW_GFX_TRANSFORMANIMEVALUATOR_H_ 458