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