1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: gfx_SkeletalModel.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_SKELETALMODEL_H_ 19 #define NW_GFX_SKELETALMODEL_H_ 20 21 #include <nw/gfx/gfx_Model.h> 22 #include <nw/gfx/gfx_Skeleton.h> 23 #include <nw/gfx/gfx_StandardSkeleton.h> 24 #include <nw/gfx/gfx_AnimObject.h> 25 26 namespace nw 27 { 28 namespace anim 29 { 30 namespace res 31 { 32 class ResAnimGroupMember; 33 } 34 } 35 } 36 37 namespace nw 38 { 39 namespace gfx 40 { 41 42 //--------------------------------------------------------------------------- 43 //! @brief 内部に軽量な階層構造を持てるモデルクラスです。 44 //--------------------------------------------------------------------------- 45 class SkeletalModel : public Model 46 { 47 private: 48 NW_DISALLOW_COPY_AND_ASSIGN(SkeletalModel); 49 50 public: 51 NW_UT_RUNTIME_TYPEINFO; 52 53 //! @brief 設定内容です。 54 struct Description : public Model::Description 55 { 56 Skeleton* sharedSkeleton; //!< 共有するスケルトンです。 57 58 //! @brief コンストラクタです。 DescriptionDescription59 Description() 60 : sharedSkeleton(NULL) 61 {} 62 }; 63 64 //! @brief スケルタルモデルを構築するためのクラスです。 65 //! 66 //! IsFixedSizeMemory の初期値は true です。false に変更すると、各種最大数の設定は一部を除いて無視されます。 67 class Builder 68 { 69 public: 70 //! コンストラクタです。 Builder()71 Builder() {} 72 73 //! デストラクタです。 ~Builder()74 ~Builder() {} 75 76 //! @brief 生成時以外にもメモリを確保するかどうかのフラグを設定します。 77 //! 78 //! true を指定すると、生成時のみ固定サイズのメモリ確保を行います。 79 //! 80 //! false を指定すると、生成時以外にも必要に応じて動的にメモリ確保が行われます。 IsFixedSizeMemory(bool isFixedSizeMemory)81 Builder& IsFixedSizeMemory(bool isFixedSizeMemory) 82 { 83 m_Description.isFixedSizeMemory = isFixedSizeMemory; 84 return *this; 85 } 86 87 //! 子の最大数を設定します。 MaxChildren(int maxChildren)88 Builder& MaxChildren(int maxChildren) 89 { 90 m_Description.maxChildren = maxChildren; 91 return *this; 92 } 93 94 //! 管理できるコールバックの最大数を設定します。 MaxCallbacks(int maxCallbacks)95 Builder& MaxCallbacks(int maxCallbacks) 96 { 97 m_Description.maxCallbacks = maxCallbacks; 98 return *this; 99 } 100 101 //! @brief バッファの生成オプションを設定します。 102 //! 103 //! 104 //! @param bufferOption Model::BufferOptionで定義されるフラグの組み合わせです。 105 //! SharedMaterialModel が指定された場合、BufferOption は指定することができません。 106 //! BufferOption が指定された場合は動作を停止します。 107 //! 108 //! @param[in] bufferOption Model::BufferOptionで定義されるフラグの組み合わせです。 109 //! BufferOption(bit32 bufferOption)110 Builder& BufferOption(bit32 bufferOption) 111 { 112 m_Description.bufferOption = bufferOption; 113 return *this; 114 } 115 116 //! @brief マテリアルを共有する場合に共有元のモデルを設定します。 117 //! 118 //! 所有権の移動を行いません。 119 //! マテリアルを最初に生成したモデルがマテリアルの所有権を持ちます。 120 //! 共有元のモデルが先に破棄された場合は未定義の動作となります。 121 //! 122 //! @param[in] model 共有するマテリアルを持つモデルです。 123 //! SharedMaterialModel(Model * model)124 Builder& SharedMaterialModel(Model* model) 125 { 126 m_Description.sharedMaterialModel = model; 127 return *this; 128 } 129 130 //! @brief 共有するスケルトンを設定します。 131 //! 132 //! 作成時には所有権の移動を行いません。 133 //! スケルトンを最初に生成したモデルがスケルトンの所有権を持ちます。 134 //! 共有元のモデルが先に破棄された場合は未定義の動作となります。 135 //! 描画前には所有権を持つ SkeletalModel は必ず SubmitView を行う必要があります。 136 //! 所有権を持つ SkeletalModel の SubmitView を行わないと、スケルトンを共有している他の SkeletalModel の更新が行われません。 137 //! 138 //! @param[in] sharedSkeleton 共有するスケルトンです。 139 //! 140 //! @sa SwapSkeleton SharedSkeleton(Skeleton * sharedSkeleton)141 Builder& SharedSkeleton(Skeleton* sharedSkeleton) 142 { 143 m_Description.sharedSkeleton = sharedSkeleton; 144 return *this; 145 } 146 147 //! @brief AnimGroup ごとの AnimObject の最大数を指定します。 148 //! 149 //! MaxAnimObjectsPerGroup の指定は IsFixedSizeMemory が false でも有効になります。 MaxAnimObjectsPerGroup(s32 maxAnimObjectCount)150 Builder& MaxAnimObjectsPerGroup(s32 maxAnimObjectCount) 151 { 152 m_Description.maxAnimObjectsPerGroup = maxAnimObjectCount; 153 return *this; 154 } 155 156 //! @brief アニメーション可能かを設定します。 157 //! 158 //! false を指定すると AnimBinding の生成を行いません。 159 //! そのためアニメーションのバインドができなくなりますが、 160 //! アニメーション更新の処理が行われなくなるため、 161 //! シーンアップデートのパフォーマンスが向上します。 IsAnimationEnabled(bool isAnimationEnabled)162 Builder& IsAnimationEnabled(bool isAnimationEnabled) 163 { 164 m_Description.isAnimationEnabled = isAnimationEnabled; 165 return *this; 166 } 167 168 //! @brief スケルタルモデルを生成します。 169 //! 170 //! parent に NULL を指定した場合は、親ノードへの取り付けを行いません。 171 //! 172 //! @param[in] allocator アロケータです。 173 //! @param[in] parent 親ノードです。 174 //! @param[in] resource リソースです。 175 //! 176 //! @return 生成したスケルタルモデルを返します。 177 //! 178 SkeletalModel* Create( 179 SceneNode* parent, 180 ResSceneObject resource, 181 os::IAllocator* allocator); 182 183 //! @brief 生成時に必要なメモリサイズを取得します。 184 //! 185 //! @param[in] resModel リソースです。 186 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 187 size_t GetMemorySize( 188 ResSkeletalModel resModel, 189 size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const 190 { 191 os::MemorySizeCalculator size(alignment); 192 193 GetMemorySizeInternal(&size, resModel); 194 195 return size.GetSizeWithPadding(alignment); 196 } 197 198 //! @brief 生成時に必要なデバイスメモリサイズを取得します。 199 //! 200 //! @param[in] alignment 計算に用いるアライメントです。2 のべき乗である必要があります。 201 size_t GetDeviceMemorySize( 202 ResSkeletalModel, 203 size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const 204 { 205 NW_UNUSED_VARIABLE(alignment); 206 207 return 0; 208 } 209 210 //! @details :private GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResSkeletalModel resModel)211 void GetMemorySizeInternal( 212 os::MemorySizeCalculator* pSize, 213 ResSkeletalModel resModel) const 214 { 215 os::MemorySizeCalculator& size = *pSize; 216 217 if (m_Description.sharedSkeleton == NULL) 218 { 219 ResSkeleton resSkeleton = resModel.GetSkeleton(); 220 221 #ifdef NW_MOVE_ARRAY_CACHE_LINE_ALIGNMENT_ENABLED 222 size.Add( 223 sizeof(Skeleton::TransformPose::Transform) * resSkeleton.GetBonesCount(), 224 Skeleton::TransformPose::TransformArray::MEMORY_ALIGNMENT); 225 #else 226 size += sizeof(Skeleton::TransformPose::Transform) * resSkeleton.GetBonesCount(); 227 #endif 228 StandardSkeleton::GetMemorySizeInternal( 229 pSize, 230 resSkeleton, 231 m_Description.maxCallbacks); 232 } 233 234 // モデル作成 235 size += sizeof(SkeletalModel); 236 SkeletalModel::GetMemorySizeForInitialize(pSize, resModel, m_Description); 237 } 238 239 //! @details :private GetDeviceMemorySizeInternal(os::MemorySizeCalculator *,ResSkeletalModel)240 void GetDeviceMemorySizeInternal( 241 os::MemorySizeCalculator*, 242 ResSkeletalModel) const 243 { 244 } 245 246 private: 247 SkeletalModel::Description m_Description; 248 }; 249 250 //---------------------------------------- 251 //! @name シーンツリー 252 //@{ 253 254 //! @brief ビジターを受け付けます。 255 //! 256 //! @param[in] visitor ビジターです。 257 //! 258 virtual void Accept(ISceneVisitor* visitor); 259 260 //@} 261 262 //---------------------------------------- 263 //! @name リソース 264 //@{ 265 266 //! スケルタルモデルのリソースを取得します。 GetResSkeletalModel()267 ResSkeletalModel GetResSkeletalModel() 268 { 269 return ResDynamicCast<ResSkeletalModel>(this->GetResSceneObject()); 270 } 271 272 //! スケルタルモデルのリソースを取得します。 GetResSkeletalModel()273 const ResSkeletalModel GetResSkeletalModel() const 274 { 275 return ResDynamicCast<ResSkeletalModel>(this->GetResSceneObject()); 276 } 277 278 //@} 279 280 //---------------------------------------- 281 //! @name スケルトン 282 //@{ 283 284 //! スケルトンを取得します。 GetSkeleton()285 Skeleton* GetSkeleton() { return m_Skeleton.Get(); } 286 287 //! スケルトンを取得します。 GetSkeleton()288 const Skeleton* GetSkeleton() const { return m_Skeleton.Get(); } 289 290 //! 他モデルのスケルトンを共有している場合は true を返します。 IsSharingSkeleton()291 bool IsSharingSkeleton() const { return this->m_SharingSkeleton; } 292 293 //! @brief スケルトンの所有権を交換します。 294 //! 295 //! 保有するスケルトンの所有権を交換します。 296 //! 共有スケルトンのオーナーとなる SkeletalModel を変更する場合などに用いることができます。 297 //! 298 //! @param[in] skeletalModel スケルトンを交換するスケルタルモデルです。 299 //! SwapSkeleton(SkeletalModel * skeletalModel)300 void SwapSkeleton( SkeletalModel* skeletalModel ) 301 { 302 this->m_Skeleton.Swap(skeletalModel->m_Skeleton); 303 bool sharingSkeleton = this->m_SharingSkeleton; 304 this->m_SharingSkeleton = skeletalModel->m_SharingSkeleton; 305 skeletalModel->m_SharingSkeleton = sharingSkeleton; 306 } 307 308 //@} 309 310 //---------------------------------------- 311 //! @name アニメーション 312 //@{ 313 314 //! スケルタルアニメーショングループを取得します。 GetSkeletalAnimGroup()315 AnimGroup* GetSkeletalAnimGroup() { return m_SkeletalAnimGroup; } 316 317 //! スケルタルアニメーショングループを取得します。 GetSkeletalAnimGroup()318 const AnimGroup* GetSkeletalAnimGroup() const { return m_SkeletalAnimGroup; } 319 320 //! スケルタルアニメーショングループのアニメーションバインディング中のインデックスを取得します。 GetSkeletalAnimBindingIndex()321 int GetSkeletalAnimBindingIndex() const { return m_SkeletalAnimBindingIndex; } 322 323 //! スケルタルアニメーションオブジェクトを取得します。 324 const AnimObject* GetSkeletalAnimObject(int objectIndex = 0) const 325 { 326 NW_NULL_ASSERT(m_AnimBinding); 327 return m_AnimBinding->GetAnimObject(m_SkeletalAnimBindingIndex, objectIndex); 328 } 329 330 //! スケルタルアニメーションオブジェクトを取得します。 331 AnimObject* GetSkeletalAnimObject(int objectIndex = 0) 332 { 333 NW_NULL_ASSERT(m_AnimBinding); 334 return m_AnimBinding->GetAnimObject(m_SkeletalAnimBindingIndex, objectIndex); 335 } 336 337 //! @brief スケルタルアニメーションオブジェクトを設定します。 338 //! 339 //! @param[in] animObject 設定するアニメーションオブジェクトです。NULL を指定するとアニメーションを解除します。 340 void SetSkeletalAnimObject(AnimObject* animObject, int objectIndex = 0) 341 { 342 NW_NULL_ASSERT(m_AnimBinding); 343 m_AnimBinding->SetAnimObject(m_SkeletalAnimBindingIndex, animObject, objectIndex); 344 } 345 346 //! フルベイクアニメーションを使用するかを取得します。 GetFullBakedAnimEnabled()347 bool GetFullBakedAnimEnabled() const 348 { 349 return m_FullBakedAnimEnabled; 350 } 351 352 //! @brief フルベイクアニメーションを使用するかを設定します。 353 //! 354 //! true を指定すると、スケルトンの更新処理が省略されます。 355 //! また、 ResSkeletonData::FLAG_MODEL_COORDINATE フラグが有効に設定されます。 356 //! true を指定した状態では、通常のアニメーションは正常に再生できませんので注意してください。 357 //! 358 //! false を指定すると、 ResSkeletonData::FLAG_MODEL_COORDINATE フラグが無効に設定されます。 359 //! 360 //! 共有スケルトンを使用している場合は、 361 //! 共有元のスケルトンの上記フラグが変更されますので注意してください。 362 void SetFullBakedAnimEnabled(bool enable); 363 364 //@} 365 366 protected: 367 virtual Result Initialize(os::IAllocator* allocator); 368 369 //! @brief Initialize() の実行に必要なメモリサイズを取得します。 370 //! 371 //! @details :private GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,ResSkeletalModel resModel,Description description)372 static void GetMemorySizeForInitialize( 373 os::MemorySizeCalculator* pSize, 374 ResSkeletalModel resModel, 375 Description description) 376 { 377 // SkeletalModel::Initialize 378 os::MemorySizeCalculator& size = *pSize; 379 380 Model::GetMemorySizeForInitialize(pSize, resModel, description); 381 382 // SkeletalModel::CreateSkeletalAnimGroup 383 if (description.isAnimationEnabled) 384 { 385 const int animGroupCount = resModel.GetAnimGroupsCount(); 386 for (int animGroupIdx = 0; animGroupIdx < animGroupCount; ++animGroupIdx) 387 { 388 anim::ResAnimGroup resAnimGroup = resModel.GetAnimGroups(animGroupIdx); 389 const int targetType = resAnimGroup.GetTargetType(); 390 const bool transformFlag = 391 (resAnimGroup.GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM) != 0; 392 if (transformFlag && 393 targetType == anim::ResGraphicsAnimGroup::TARGET_TYPE_BONE) 394 { 395 AnimGroup::Builder() 396 .ResAnimGroup(resAnimGroup) 397 .UseOriginalValue(true) 398 .GetMemorySizeInternal(pSize); 399 break; // 他にスケルタルモデル専用のアニメーショングループがないので 400 } 401 } 402 } 403 } 404 405 //---------------------------------------- 406 //! @name コンストラクタ/デストラクタ 407 //@{ 408 409 //! コンストラクタです。 SkeletalModel(os::IAllocator * allocator,ResSkeletalModel resource,GfxPtr<Skeleton> & skeleton,bool isSharingSkeleton,const SkeletalModel::Description & description)410 SkeletalModel( 411 os::IAllocator* allocator, 412 ResSkeletalModel resource, 413 GfxPtr<Skeleton>& skeleton, 414 bool isSharingSkeleton, 415 const SkeletalModel::Description& description) 416 : Model( 417 allocator, 418 resource, 419 description), 420 m_Skeleton(skeleton), 421 m_SkeletalAnimGroup(NULL), 422 m_SkeletalAnimBindingIndex(-1), 423 m_SharingSkeleton(isSharingSkeleton), 424 m_FullBakedAnimEnabled(false) 425 { 426 if (!isSharingSkeleton) 427 { 428 m_Skeleton->SetOwnerSkeletalModel(this); 429 } 430 } 431 432 //! デストラクタです。 ~SkeletalModel()433 virtual ~SkeletalModel() 434 { 435 SafeDestroy(m_SkeletalAnimGroup); 436 } 437 438 //@} 439 440 //! スケルタルアニメーション用のアニメーショングループを生成します。 441 Result CreateSkeletalAnimGroup(os::IAllocator* allocator); 442 443 //! スケルタルアニメーションに登録するモデルデータのポインタを取得します。 444 void* GetAnimTargetObject(const anim::ResAnimGroupMember& anim); 445 446 private: 447 void SetupAnimGroup(AnimGroup* animGroup, bool fullBakedAnimEnabled) const; 448 449 GfxPtr<Skeleton> m_Skeleton; 450 AnimGroup* m_SkeletalAnimGroup; 451 int m_SkeletalAnimBindingIndex; 452 bool m_SharingSkeleton; 453 bool m_FullBakedAnimEnabled; 454 }; 455 456 } // namespace gfx 457 } // namespace nw 458 459 #endif // NW_GFX_SKELETALMODEL_H_ 460