1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: gfx_AnimEvaluator.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: 31563 $ 16 *---------------------------------------------------------------------------*/ 17 18 #ifndef NW_GFX_ANIMEVALUATOR_H_ 19 #define NW_GFX_ANIMEVALUATOR_H_ 20 21 #include <nw/gfx/gfx_BaseAnimEvaluator.h> 22 #include <nw/gfx/gfx_SharedAnimCache.h> 23 #include <nw/ut/ut_MoveArray.h> 24 #include <nw/ut/ut_RuntimeTypeInfo.h> 25 26 namespace nw { 27 namespace gfx { 28 29 //--------------------------------------------------------------------------- 30 //! @brief 汎用アニメーションを評価するクラスです。 31 //! 32 //! アニメーションデータを保持し、ファンクションカーブの評価を行います。 33 //--------------------------------------------------------------------------- 34 class AnimEvaluator : public BaseAnimEvaluator 35 { 36 public: 37 NW_UT_RUNTIME_TYPEINFO; 38 39 //---------------------------------------- 40 //! @name 作成 41 //@{ 42 43 //! 汎用アニメーション評価を構築するクラスです。 44 class Builder 45 { 46 public: 47 //! コンストラクタです。 Builder()48 Builder() 49 : m_AnimData(NULL), 50 m_MaxMembers(64), 51 m_MaxAnimMembers(64), 52 m_AllocCache(false) {} 53 54 //! アニメーションデータを設定します。 AnimData(const nw::anim::ResAnim & animData)55 Builder& AnimData(const nw::anim::ResAnim& animData) { m_AnimData = animData; return *this; } 56 57 //! @brief アニメーション対象メンバの最大数を設定します。 58 //! 59 //! AnimEvaluator::Bind に渡す AnimGroup の AnimGroup::GetMemberCount の値を設定してください。 60 //! 複数の AnimGroup に Bind する場合は、最大値を設定してください。 MaxMembers(int maxMembers)61 Builder& MaxMembers(int maxMembers) 62 { 63 NW_ASSERT(maxMembers > 0); 64 m_MaxMembers = maxMembers; 65 return *this; 66 } 67 68 //! @brief 実際にアニメーションするメンバの最大数を設定します。 69 //! 70 //! AnimData() に渡す anim::res::ResAnim の anim::res::ResAnim::GetMemberAnimSetCount の値を設定してください。 71 //! AnimEvaluator::ChangeAnim で複数の ResAnim を切り替える場合は、最大値を設定してください。 MaxAnimMembers(int maxAnimMembers)72 Builder& MaxAnimMembers(int maxAnimMembers) 73 { 74 NW_ASSERT(maxAnimMembers > 0); 75 m_MaxAnimMembers = maxAnimMembers; 76 return *this; 77 } 78 79 //! キャッシュバッファを確保してキャッシュを有効にするかどうかを設定します。 AllocCache(bool allocCache)80 Builder& AllocCache(bool allocCache) { m_AllocCache = allocCache; return *this; } 81 82 //! @brief 生成時に必要なメモリサイズを取得します。 83 //! 84 //! メモリサイズは Builder の設定によって変化します。 85 //! すべての設定が終わった後にこの関数を呼び出してください。 86 //! 87 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 88 size_t GetMemorySize(size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const 89 { 90 os::MemorySizeCalculator size(alignment); 91 92 GetMemorySizeInternal(&size); 93 94 return size.GetSizeWithPadding(alignment); 95 } 96 97 //! @details :private GetMemorySizeInternal(os::MemorySizeCalculator * pSize)98 void GetMemorySizeInternal(os::MemorySizeCalculator* pSize) const 99 { 100 os::MemorySizeCalculator& size = *pSize; 101 102 size += sizeof(AnimEvaluator); 103 AnimEvaluator::GetMemorySizeForInitialize(pSize, m_AnimData, m_MaxMembers, m_MaxAnimMembers, m_AllocCache); 104 } 105 106 //! @brief 汎用アニメーション評価を生成します。 107 //! 108 //! @param[in] allocator アロケータです。 109 //! 110 //! @return 生成された汎用アニメーション評価です。 111 //! Create(os::IAllocator * allocator)112 AnimEvaluator* Create(os::IAllocator* allocator) 113 { 114 void* buf = allocator->Alloc(sizeof(AnimEvaluator)); 115 116 if (buf == NULL) 117 { 118 return NULL; 119 } 120 121 AnimEvaluator* animEvaluator = new(buf) AnimEvaluator(allocator); 122 123 Result result = animEvaluator->Initialize(m_AnimData, m_MaxMembers, m_MaxAnimMembers, m_AllocCache); 124 NW_ASSERT(result.IsSuccess()); 125 126 return animEvaluator; 127 } 128 129 private: 130 nw::anim::ResAnim m_AnimData; 131 int m_MaxMembers; 132 int m_MaxAnimMembers; 133 bool m_AllocCache; 134 }; 135 136 //@} 137 138 //---------------------------------------- 139 //! @name 基本操作 140 //@{ 141 142 //! @brief アニメーションを変更します。 143 //! 144 //! GetCacheBufferSizeNeeded() の値が変化しますので、 145 //! SetCacheBuffer() や SetSharedCacheBuffer() を使用している場合はバッファの再設定が必要です。 146 //! 147 //! 内部で確保したキャッシュバッファは、自動的にサイズ変更されます。 148 //! 149 //! @param animData アニメーションデータです。 150 //! @sa BaseAnimEvaluator::ChangeAnim ChangeAnim(const nw::anim::ResAnim animData)151 virtual void ChangeAnim(const nw::anim::ResAnim animData) 152 { 153 // キャッシュサイズを求めるのにm_AnimDataを参照するので、 154 // 先に更新する必要がある 155 BaseAnimEvaluator::ChangeAnim(animData); 156 157 m_CachePtrs.Resize(animData.GetMemberAnimSetCount()); 158 159 if (!m_IsCacheExternal && m_CacheBuf != NULL) 160 { 161 os::SafeFree(m_CacheBuf, &GetAllocator()); 162 163 // サイズ0でのAllocを回避する 164 // CreateEmpty~Anim()などを使用した場合に起こりうる 165 if (animData.GetMemberAnimSetCount() != 0) 166 { 167 m_CacheBuf = GetAllocator().Alloc(GetCacheBufferSizeNeeded()); 168 NW_NULL_ASSERT(m_CacheBuf); 169 170 SetCacheBufferPointers(); 171 } 172 } 173 } 174 175 //! @brief マテリアル名を置き換えてアニメーションを関連付けます。 176 //! 177 //! マテリアルアニメーションのバインド先を 178 //! 名前が materialName であるマテリアルに置き換えてバインドします。 179 //! 180 //! マテリアルアニメーション以外では使用できません。 181 //! 182 //! materialName の文字数が長すぎるとバインドに失敗することがあります。 183 //! 184 //! @param[in] animGroup アニメーショングループです。 185 //! @param[in] materialName バインドするマテリアル名です。文字数の制限があります。 186 //! 187 //! @return バインドの結果を返します。 188 //! 189 //! @sa TryBind 190 Result ForceBindMaterialAnim(AnimGroup* animGroup, const char* materialName); 191 192 //@} 193 194 //---------------------------------------- 195 //! @name 評価 196 //@{ 197 198 //! @brief メンバ単位でアニメーション結果を取得します。 199 //! 200 //! @param[out] target アニメーション結果を書き込む対象です。 201 //! @param[in] memberIdx メンバインデックスです。 202 //! 203 //! @return アニメーション結果を返します。 204 //! ブレンドオペレーションを使用する場合は、返り値のアニメーション結果を使用してください。 205 //! 206 virtual const anim::AnimResult* GetResult( 207 void* target, 208 int memberIdx) const; 209 210 //@} 211 212 //---------------------------------------- 213 //! @name 取得/設定 214 //@{ 215 216 //! @brief メンバに関連付けられたアニメーションが存在するかどうかを取得します。 217 //! 218 //! @param[in] memberIdx メンバインデックスです。 219 //! 220 //! @return アニメーションが存在すれば true を返します。 221 //! HasMemberAnim(int memberIdx)222 virtual bool HasMemberAnim(int memberIdx) const 223 { 224 NW_MINMAXLT_ASSERT(memberIdx, 0, m_BindIndexTable.Size()); 225 return m_BindIndexTable[memberIdx] != NotFoundIndex; 226 } 227 228 //@} 229 230 //---------------------------------------- 231 //! @name キャッシュ 232 //@{ 233 234 //! アニメーション評価結果の内部キャッシュが古ければ更新します。 UpdateCache()235 virtual void UpdateCache() { this->UpdateCacheNonVirtual(); } 236 237 //! :private 238 void UpdateCacheNonVirtual(); 239 240 //! :private 241 void UpdateCacheImpl(); 242 243 //! キャッシュバッファに必要なサイズ(バイト数)を取得します。 244 //! @return 必要なサイズ(バイト数)です。 245 virtual int GetCacheBufferSizeNeeded() const; 246 247 //! キャッシュバッファを取得します。 GetCacheBuffer()248 virtual const void* GetCacheBuffer() const { return m_CacheBuf; } 249 250 //! @brief キャッシュバッファを設定します。 251 //! この関数で指定したキャッシュバッファはデストラクタで解放されません。 252 //! 253 //! @param[in] buf キャッシュバッファ用のメモリの先頭アドレスです。 254 //! NULL の場合、キャッシュが無効になります。 255 //! @param[in] size キャッシュバッファのサイズ(バイト数)です。 256 //! SetCacheBuffer(void * buf,int size)257 virtual void SetCacheBuffer(void* buf, int size) 258 { 259 m_CacheBuf = buf; 260 if (buf != NULL) 261 { 262 NW_ASSERT(size >= GetCacheBufferSizeNeeded()); 263 (void)size; 264 m_IsCacheDirty = true; 265 m_IsCacheExternal = true; 266 SetCacheBufferPointers(); 267 } 268 } 269 270 //! @brief 他のAnimEvaluatorと共有可能なキャッシュを使用するように設定します。 SetSharedCacheBuffer(SharedAnimCache * cache)271 void SetSharedCacheBuffer(SharedAnimCache* cache) 272 { 273 // 他の形式のキャッシュが指定されているならアサートで止める 274 NW_ASSERT(m_CacheBuf == NULL); 275 NW_ASSERT(!m_IsCacheExternal); 276 277 m_SharedCache = cache; 278 if (cache != NULL) 279 { 280 m_IsCacheDirty = true; 281 m_IsCacheExternal = true; 282 m_UseSharedCache = true; 283 m_CacheBuf = cache->GetCacheBuffer(); 284 SetCacheBufferPointers(); 285 } 286 else 287 { 288 m_CacheBuf = NULL; 289 } 290 } 291 292 //@} 293 294 protected: 295 //---------------------------------------- 296 //! @name コンストラクタ/デストラクタ 297 //@{ 298 299 //! コンストラクタです。 300 //! 301 //! :private 302 AnimEvaluator( 303 os::IAllocator* allocator); 304 305 //! デストラクタです。 306 //! 307 //! :private ~AnimEvaluator()308 virtual ~AnimEvaluator() 309 { 310 if (!m_IsCacheExternal && m_CacheBuf != NULL) 311 { 312 GetAllocator().Free(m_CacheBuf); 313 } 314 } 315 316 //@} 317 318 //! Initialize() の実行に必要なメモリサイズを取得します。 319 //! 320 //! :private 321 static void GetMemorySizeForInitialize( 322 os::MemorySizeCalculator* pSize, 323 const nw::anim::ResAnim& animData, 324 const int maxMembers, 325 const int maxAnimMembers, 326 bool allocCache); 327 328 //! @details :private 329 Result Initialize( 330 const nw::anim::ResAnim& animData, 331 const int maxMembers, 332 const int maxAnimMembers, 333 bool allocCache); 334 335 //! キャッシュバッファに必要なサイズ(バイト数)を取得します。 336 //! 337 //! :private 338 static int GetCacheBufferSizeNeeded(const anim::ResAnim& animData); 339 340 //! 各メンバアニメのキャッシュバッファへのポインタを設定します。 341 //! 342 //! :private 343 void SetCacheBufferPointers(); 344 345 //! AnimResult を実サイズで詰めたバッファ 346 //! 347 //! :private 348 void* m_CacheBuf; 349 350 //! 共有するキャッシュのポインタ 351 SharedAnimCache* m_SharedCache; 352 353 //! 各メンバアニメの m_CacheBuf 中のポインタ 354 //! 355 //! :private 356 ut::MoveArray<anim::AnimResult*> m_CachePtrs; 357 358 private: 359 //! マテリアル名を置き換えてメンバインデックスを引く関数オブジェクトです。 360 //! 361 //! :private 362 class ReplaceMaterialNameIndexGetterFunctor 363 { 364 private: 365 static const int MAX_BUFFER_LENGTH = 256; 366 367 public: ReplaceMaterialNameIndexGetterFunctor(const char * materialName)368 ReplaceMaterialNameIndexGetterFunctor(const char* materialName) 369 : m_MaterialName(materialName), 370 m_LenMaterialName(0) 371 { 372 NW_NULL_ASSERT(materialName); 373 m_LenMaterialName = std::strlen(m_MaterialName); 374 } 375 operator()376 int operator() (AnimGroup* animGroup, anim::ResMemberAnim member) 377 { 378 const char MATERIAL_PREFIX[] = "Materials[\""; 379 const size_t MATERIAL_PREFIX_LEN = sizeof(MATERIAL_PREFIX) - 1; 380 381 const char* path = member.GetPath(); 382 size_t lenPath = std::strlen(path); 383 384 NW_ASSERTMSG(std::strncmp(path, MATERIAL_PREFIX, MATERIAL_PREFIX_LEN) == 0, "Not material animation member."); 385 386 NW_FAILSAFE_IF (lenPath <= MATERIAL_PREFIX_LEN) 387 { 388 // 書き換え対象のパスの長さが異常なので 389 // リソースが壊れている可能性がある。 390 391 // -1 は辞書引きで見つからない場合の戻り値 392 return -1; 393 } 394 395 // "Materials[\"" は確定しているので、その次の文字列までポインタを進める。 396 path += MATERIAL_PREFIX_LEN; 397 lenPath -= MATERIAL_PREFIX_LEN; 398 399 // 次の " を探す。 400 while ((*path != 0) && (*path != '\"')) 401 { 402 ++path; 403 --lenPath; 404 } 405 406 // この時点で path は '\"' からはじまるか、NULL 終端を指している。 407 408 NW_FAILSAFE_IF (MATERIAL_PREFIX_LEN + m_LenMaterialName + lenPath + 1 > MAX_BUFFER_LENGTH) 409 { 410 // 書き換えたパスがバッファに収まらない。 411 412 // -1 は辞書引きで見つからない場合の戻り値 413 return -1; 414 } 415 416 // パスを作成する。 417 char replacedPath[MAX_BUFFER_LENGTH]; 418 ut::strncpy(replacedPath, MAX_BUFFER_LENGTH, MATERIAL_PREFIX, MATERIAL_PREFIX_LEN); 419 ut::strncat(replacedPath, MAX_BUFFER_LENGTH, m_MaterialName, m_LenMaterialName); 420 ut::strncat(replacedPath, MAX_BUFFER_LENGTH, path, lenPath); 421 422 return animGroup->GetResAnimGroupMemberIndex(replacedPath); 423 } 424 425 private: 426 const char* m_MaterialName; 427 size_t m_LenMaterialName; 428 }; 429 }; 430 431 } // namespace gfx 432 } // namespace nw 433 434 #endif // NW_GFX_ANIMEVALUATOR_H_ 435