1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: gfx_BaseAnimEvaluator.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: 32369 $ 16 *---------------------------------------------------------------------------*/ 17 18 #ifndef NW_GFX_BASEANIMEVALUATOR_H_ 19 #define NW_GFX_BASEANIMEVALUATOR_H_ 20 21 #include <nw/anim/anim_AnimFrameController.h> 22 #include <nw/anim/res/anim_ResAnim.h> 23 #include <nw/gfx/gfx_AnimGroup.h> 24 #include <nw/gfx/gfx_AnimObject.h> 25 #include <nw/ut/ut_MoveArray.h> 26 #include <nw/ut/ut_RuntimeTypeInfo.h> 27 28 namespace nw { 29 namespace gfx { 30 31 namespace internal 32 { 33 //! :private 34 void ClearMaterialHash(anim::ResAnimGroupMember member); 35 } 36 37 //--------------------------------------------------------------------------- 38 //! @brief アニメーション評価の基底クラスです。 39 //! 抽象クラスですのでインスタンス化して使用することはできません。 40 //--------------------------------------------------------------------------- 41 class BaseAnimEvaluator : public AnimObject 42 { 43 public: 44 NW_UT_RUNTIME_TYPEINFO; 45 46 //! 関連付け対象がない場合のインデックスです。 47 //! 48 //! :private 49 static const int NotFoundIndex; 50 51 //---------------------------------------- 52 //! @name コンストラクタ/デストラクタ 53 //@{ 54 55 //! コンストラクタです。 BaseAnimEvaluator(os::IAllocator * allocator,u32 animType)56 BaseAnimEvaluator( 57 os::IAllocator* allocator, u32 animType) 58 : AnimObject(allocator, animType), 59 m_IsCacheDirty(true), 60 m_IsCacheExternal(false), 61 m_UseSharedCache(false) 62 { 63 } 64 65 //! デストラクタです。 ~BaseAnimEvaluator()66 virtual ~BaseAnimEvaluator() {} 67 68 //@} 69 70 //---------------------------------------- 71 //! @name 基本操作 72 //@{ 73 74 //! @brief アニメーションを関連付けます。 75 //! 76 //! Bind よりも詳細なバインド結果を得ることができます。 77 //! 78 //! @param[in] animGroup アニメーショングループです。 79 //! 80 //! @return バインドの結果を返します。 81 //! 82 //! @sa Bind 83 virtual Result TryBind(AnimGroup* animGroup); 84 85 //! アニメーションの関連付けを解除します。 Release()86 virtual void Release() 87 { 88 m_AnimGroup = NULL; 89 } 90 91 //! フレームを更新します。 UpdateFrame()92 virtual void UpdateFrame() 93 { 94 // 更新フレームが 0 の場合は、SetStepFrame() で 95 // キャッシュを更新済みです。 96 if (GetStepFrame() != 0.0f) 97 { 98 m_AnimFrameController.UpdateFrame(); 99 m_IsCacheDirty = true; 100 } 101 } 102 103 //! @brief アニメーションを変更します。 104 //! 105 //! AnimEvaluator::Bind の後でアニメーションを差し替える場合に使用します。 106 //! AnimEvaluator を破棄して再生成するより高速です。 107 //! 108 //! 再生フレームは 0.0f にリセットされます。 109 //! 110 //! @param animData アニメーションデータです。 ChangeAnim(const nw::anim::ResAnim animData)111 virtual void ChangeAnim(const nw::anim::ResAnim animData) 112 { 113 NW_NULL_ASSERT(m_AnimGroup); 114 115 // このASSERTが失敗した場合は、Builder::MaxAnimMembers の値を大きくしてください 116 NW_ASSERT(animData.GetMemberAnimSetCount() <= m_ReverseBindIndexTable.Capacity()); 117 118 SetResAnim(animData); 119 120 AnimGroup* animGroup = m_AnimGroup; 121 Release(); 122 Bind(animGroup); 123 } 124 125 //! @brief すべてのアニメーション対象メンバーを生成時の状態に戻します。 126 //! 127 //! マテリアルに対して行う場合、マテリアルのバッファを生成する必要があります。 128 //! SceneBuilder クラスでモデルを作成する際のオプションで、 129 //! SceneBuilder::BufferOption を設定してください。 130 //! BufferOption には、 Model::MULTI_FLAG_ANIMATABLE_MATERIAL の内容が最低限必要です。 Reset()131 void Reset() 132 { 133 for (int i = (m_AnimGroup->GetMemberCount() - 1); i >= 0; --i) 134 { 135 this->ResetMember(i); 136 } 137 } 138 139 //! @brief 指定されたメンバーを生成時の状態に戻します。 140 //! @param memberIdx 対象のメンバーです。 141 void ResetMember(int memberIdx); 142 143 //@} 144 145 //---------------------------------------- 146 //! @name フレーム制御 147 //@{ 148 149 //! フレームを取得します。 GetFrame()150 float GetFrame() const { return m_AnimFrameController.GetFrame(); } 151 152 //! @brief フレームを設定します。 153 //! 154 //! @param[in] frame 設定するフレームです。 155 //! SetFrame(float frame)156 void SetFrame(float frame) 157 { 158 m_AnimFrameController.SetFrame(frame); 159 m_IsCacheDirty = true; 160 } 161 162 //! @brief フレームをリセットします。 163 //! 164 //! @param[in] frame 設定するフレームです。 165 //! ResetFrame(f32 frame)166 void ResetFrame(f32 frame) 167 { 168 m_AnimFrameController.GetAnimFrame().ResetFrame(frame); 169 m_IsCacheDirty = true; 170 } 171 172 //! @brief フレームの増分を取得します。 173 //! @sa SetStepFrame GetStepFrame()174 float GetStepFrame() const { return m_AnimFrameController.GetStepFrame(); } 175 176 //! @brief フレームの増分を設定します。 177 //! 178 //! UpdateFrame() を呼び出すと、現在のフレームにフレームの増分が加算されます。 179 //! 例えば SetStepFrame(2.0f) とすると、2倍速再生になります。 180 //! 181 //! @param[in] stepFrame フレームの増分です。 SetStepFrame(float stepFrame)182 void SetStepFrame(float stepFrame) 183 { 184 m_AnimFrameController.SetStepFrame(stepFrame); 185 if (stepFrame == 0.0f) 186 { 187 m_IsCacheDirty = true; 188 UpdateCache(); 189 } 190 } 191 192 //! @brief 開始フレームを取得します。 193 //! @sa SetStartFrame GetStartFrame()194 float GetStartFrame() const { return m_AnimFrameController.GetStartFrame(); } 195 196 //! @brief 開始フレームを設定します。 197 //! 198 //! 開始フレームを現在のフレームより後に設定した場合、 199 //! 現在のフレームを開始フレームに移動します。 200 //! 201 //! @param[in] startFrame 開始フレームです。 SetStartFrame(float startFrame)202 void SetStartFrame(float startFrame) 203 { 204 m_AnimFrameController.SetStartFrame(startFrame); 205 if (startFrame > GetFrame()) 206 { 207 SetFrame(startFrame); 208 } 209 } 210 211 //! @brief 終了フレームを取得します。 212 //! @sa SetEndFrame GetEndFrame()213 float GetEndFrame() const { return m_AnimFrameController.GetEndFrame(); } 214 215 //! @brief 終了フレームを設定します。 216 //! 217 //! 終了フレームを現在のフレームより前に設定した場合、 218 //! 現在のフレームを終了フレームに移動します。 219 //! 220 //! @param[in] endFrame 終了フレームです。 SetEndFrame(float endFrame)221 void SetEndFrame(float endFrame) 222 { 223 m_AnimFrameController.SetEndFrame(endFrame); 224 if (endFrame < GetFrame()) 225 { 226 SetFrame(endFrame); 227 } 228 } 229 230 //! アニメーション再生方法を取得します。 GetPlayPolicy()231 nw::anim::AnimFrameController::PlayPolicy GetPlayPolicy() const 232 { 233 return m_AnimFrameController.GetPlayPolicy(); 234 } 235 236 //! @brief アニメーション再生方法を設定します。 237 //! 238 //! @param[in] playPolicy 設定するアニメーション再生方法です。 239 //! @sa nw::anim::AnimFrameController::SetPlayPolicy SetPlayPolicy(nw::anim::AnimFrameController::PlayPolicy playPolicy)240 void SetPlayPolicy(nw::anim::AnimFrameController::PlayPolicy playPolicy) 241 { 242 m_AnimFrameController.SetPlayPolicy(playPolicy); 243 m_IsCacheDirty = true; 244 } 245 246 //! アニメーションフレーム制御情報を取得します。 AnimFrameController()247 const nw::anim::AnimFrameController& AnimFrameController() const { return m_AnimFrameController; } 248 249 //@} 250 251 //---------------------------------------- 252 //! @name 取得/設定 253 //@{ 254 255 //! ユーザーデータを取得します。 GetUserData()256 const void* GetUserData() const { return m_AnimFrameController.GetUserData(); } 257 258 //! ユーザーデータを取得します。 GetUserData()259 void* GetUserData() { return m_AnimFrameController.GetUserData(); } 260 261 //! @brief ユーザーデータを設定します。 262 //! 263 //! @param[in] userData 設定するユーザーデータです。 264 //! @sa nw::anim::AnimFrameController::SetUserData 265 //! SetUserData(void * userData)266 void SetUserData(void* userData) { m_AnimFrameController.SetUserData(userData); } 267 268 //! ResAnimGroupMember のインデックスから ResMemberAnim のインデックスへの変換テーブルを取得します。 BindIndexTable()269 const ut::MoveArray<int>& BindIndexTable() const { return m_BindIndexTable; } 270 271 //! ResAnimGroupMember のインデックスから ResMemberAnim のインデックスへの変換テーブルを取得します。 BindIndexTable()272 ut::MoveArray<int>& BindIndexTable() { return m_BindIndexTable; } 273 274 //! ResMemberAnim のインデックスから ResAnimGroupMember のインデックスへの変換テーブルを取得します。 ReverseBindIndexTable()275 const ut::MoveArray<int>& ReverseBindIndexTable() const { return m_ReverseBindIndexTable; } 276 277 //! ResMemberAnim のインデックスから ResAnimGroupMember のインデックスへの変換テーブルを取得します。 ReverseBindIndexTable()278 ut::MoveArray<int>& ReverseBindIndexTable() { return m_ReverseBindIndexTable; } 279 280 //! アニメーションデータを取得します。 GetAnimData()281 const nw::anim::ResAnim GetAnimData() const { return m_AnimData; } 282 283 //@} 284 285 //---------------------------------------- 286 //! @name キャッシュ 287 //@{ 288 289 //! キャッシュバッファを取得します。 GetCacheBuffer()290 virtual const void* GetCacheBuffer() const { return NULL; } 291 292 //! キャッシュバッファに必要なサイズ(バイト数)を取得します。 GetCacheBufferSizeNeeded()293 virtual int GetCacheBufferSizeNeeded() const { return 0; } 294 295 //! @brief キャッシュバッファを設定します。 296 //! この関数で指定したキャッシュバッファはデストラクタで解放されません。 297 //! 298 //! @param[in] buf キャッシュバッファ用のメモリの先頭アドレスです。 299 //! NULL の場合、キャッシュが無効になります。 300 //! @param[in] size キャッシュバッファのサイズ(バイト数)です。 301 //! SetCacheBuffer(void * buf,int size)302 virtual void SetCacheBuffer(void* buf, int size) 303 { 304 (void)buf; 305 (void)size; 306 } 307 308 //@} 309 310 protected: 311 //! Initialize() の実行に必要なメモリサイズを取得します。 312 //! 313 //! :private GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,const int maxMembers,const int maxAnimMembers)314 static void GetMemorySizeForInitialize( 315 os::MemorySizeCalculator* pSize, 316 const int maxMembers, 317 const int maxAnimMembers) 318 { 319 os::MemorySizeCalculator& size = *pSize; 320 321 size += sizeof(int) * maxMembers; 322 size += sizeof(int) * maxAnimMembers; 323 } 324 325 //! メンバを初期化します。 326 //! 327 //! :private Initialize(const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers)328 Result Initialize( 329 const nw::anim::ResAnim& animData, 330 const int maxMembers, 331 const int maxAnimMembers) 332 { 333 Result result = INITIALIZE_RESULT_OK; 334 335 SetResAnim(animData); 336 337 { 338 void* memory = GetAllocator().Alloc(sizeof(int) * maxMembers); 339 if (memory == NULL) 340 { 341 result |= Result::MASK_FAIL_BIT; 342 } 343 NW_ENSURE_AND_RETURN(result); 344 345 m_BindIndexTable = ut::MoveArray<int>(memory, maxMembers, &GetAllocator()); 346 } 347 348 { 349 void* memory = GetAllocator().Alloc(sizeof(int) * maxAnimMembers); 350 if (memory == NULL) 351 { 352 result |= Result::MASK_FAIL_BIT; 353 } 354 NW_ENSURE_AND_RETURN(result); 355 356 m_ReverseBindIndexTable = ut::MoveArray<int>(memory, maxAnimMembers, &GetAllocator()); 357 } 358 359 return result; 360 } 361 362 //! @brief TryBind のテンプレート関数です。 363 //! 364 //! メンバアニメのバインドをカスタマイズできます。 365 //! 366 //! @tparam T アニメメンバのインデックスを引く関数オブジェクトです。 367 //! 368 //! :private 369 template <class T> 370 Result TryBindTemplate(AnimGroup * animGroup,T indexGetter)371 TryBindTemplate(AnimGroup* animGroup, T indexGetter) 372 { 373 NW_NULL_ASSERT(animGroup); 374 NW_ASSERT(std::strcmp(m_AnimData.GetTargetAnimGroupName(), animGroup->GetName()) == 0); 375 NW_ASSERT(m_AnimGroup == NULL); 376 377 const int memberCount = animGroup->GetMemberCount(); 378 bool resultResize = m_BindIndexTable.Resize(memberCount); 379 NW_ASSERTMSG(resultResize, 380 "Member count exceeded upper limit. Increase AnimEvaluator::Builder::MaxMembers."); 381 382 const int animMemberCount = m_AnimData.GetMemberAnimSetCount(); 383 bool resultReverseResize = m_ReverseBindIndexTable.Resize(animMemberCount); 384 NW_ASSERTMSG(resultReverseResize, 385 "Animation member count exceeded upper limit. Increase AnimEvaluator::Builder::MaxAnimMembers."); 386 387 NW_ASSERTMSG(animGroup->GetFullBakedAnimEnabled() == m_AnimData.IsFullBakedAnim(), 388 "To use full baked animation, call SkeletalModel::SetFullBakedAnimEnabled(true) before Bind."); 389 390 int boundAnimCount = 0; 391 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) 392 { 393 // 見つからなかったときのインデックスで埋める 394 m_BindIndexTable[memberIdx] = NotFoundIndex; 395 } 396 397 for (int animIdx = 0; animIdx < animMemberCount; ++animIdx) 398 { 399 anim::ResMemberAnim member = m_AnimData.GetMemberAnimSet(animIdx); 400 const int bindTargetIdx = indexGetter(animGroup, member); 401 402 // 辞書引きで見つからなかったときは、モデルに対象が存在しない 403 if (bindTargetIdx == -1) 404 { 405 m_ReverseBindIndexTable[animIdx] = NotFoundIndex; 406 continue; 407 } 408 409 m_BindIndexTable[bindTargetIdx] = animIdx; 410 m_ReverseBindIndexTable[animIdx] = bindTargetIdx; 411 ++boundAnimCount; 412 413 //HACK 414 anim::ResAnimGroupMember resAnimGroupMember = 415 animGroup->GetResAnimGroupMember(bindTargetIdx); 416 internal::ClearMaterialHash(resAnimGroupMember); 417 } 418 419 m_AnimGroup = animGroup; 420 421 // すべてのメンバアニメーションがバインドされました。 422 if (boundAnimCount == m_AnimData.GetMemberAnimSetCount()) 423 { 424 return Result(BIND_RESULT_OK); 425 } 426 427 // バインドされたメンバアニメーションが無かったので失敗とします。 428 if (boundAnimCount == 0) 429 { 430 return Result(BIND_RESULT_NO_MEMBER_BOUND | Result::MASK_FAIL_BIT); 431 } 432 433 // 上のどちらでもない場合は、バインドには成功したが 434 // すべてのメンバアニメがバインドされなかったことを通知します。 435 return Result(BIND_RESULT_NOT_ALL_ANIM_MEMBER_BOUND); 436 } 437 438 //! AnimGroupMemberのIndex -> MemberAnimのIndex 439 //! 440 //! :private 441 ut::MoveArray<int> m_BindIndexTable; 442 443 //! MemberAnimのIndex -> AnimGroupMemberのIndex 444 //! 445 //! :private 446 ut::MoveArray<int> m_ReverseBindIndexTable; 447 448 anim::AnimFrameController m_AnimFrameController; //!< @details :private 449 anim::ResAnim m_AnimData; //!< @details :private 450 451 //! キャッシュの内容が古ければ true 452 //! 453 //! :private 454 bool m_IsCacheDirty; 455 456 //! 外部から指定したキャッシュバッファなら true 457 //! 458 //! :private 459 bool m_IsCacheExternal; 460 461 //! キャッシュを他のAnimEvaluatorと共有するなら true ( SharedAnimCache を使用します。) 462 //! 463 //! :private 464 bool m_UseSharedCache; 465 466 private: 467 //! アニメデータに対応するメンバインデックスをそのまま引く関数オブジェクトです。 468 //! 469 //! :private 470 class BasicIndexGetterFunctor 471 { 472 public: operator()473 int operator() (AnimGroup* animGroup, anim::ResMemberAnim member) 474 { 475 return animGroup->GetResAnimGroupMemberIndex(member.GetPath()); 476 } 477 }; 478 SetResAnim(const nw::anim::ResAnim animData)479 void SetResAnim(const nw::anim::ResAnim animData) 480 { 481 m_AnimData = animData; 482 m_AnimFrameController.SetStepFrame(1.0f); 483 m_AnimFrameController.SetStartFrame(0.0f); 484 m_AnimFrameController.SetEndFrame(animData.GetFrameSize()); 485 m_AnimFrameController.GetAnimFrame().ResetFrame(0.0f); 486 487 switch (animData.GetLoopMode()) 488 { 489 case nw::anim::ResAnimData::LOOP_MODE_ONETIME: 490 m_AnimFrameController.SetPlayPolicy(nw::anim::PlayPolicy_Onetime); 491 break; 492 493 case nw::anim::ResAnimData::LOOP_MODE_LOOP: 494 m_AnimFrameController.SetPlayPolicy(nw::anim::PlayPolicy_Loop); 495 break; 496 497 default: 498 NW_ASSERT(false); 499 } 500 501 m_IsCacheDirty = true; 502 } 503 }; 504 505 } // namespace gfx 506 } // namespace nw 507 508 #endif // NW_GFX_BASEANIMEVALUATOR_H_ 509