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: 25986 $ 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 //! 現在の実装では0か1を指定する必要があります。 102 //! NW_DEPRECATED_FUNCTION(Builder & MaterialBufferCount (int bufferCount))103 NW_DEPRECATED_FUNCTION(Builder& MaterialBufferCount(int bufferCount)) 104 { 105 NW_UNUSED_VARIABLE(bufferCount); 106 return *this; 107 } 108 109 //! @brief バッファの生成オプションを設定します。 110 //! 111 //! 112 //! @param bufferOption Model::BufferOptionで定義されるフラグの組み合わせです。 113 //! SharedMaterialModel が指定された場合、BufferOption は指定することができません。 114 //! BufferOption が指定された場合は動作を停止します。 115 //! 116 //! @param[in] bufferOption Model::BufferOptionで定義されるフラグの組み合わせです。 117 //! BufferOption(bit32 bufferOption)118 Builder& BufferOption(bit32 bufferOption) 119 { 120 m_Description.bufferOption = bufferOption; 121 return *this; 122 } 123 124 //! @brief マテリアルを共有する場合に共有元のモデルを設定します。 125 //! 126 //! 所有権の移動を行いません。 127 //! マテリアルを最初に生成したモデルがマテリアルの所有権を持ちます。 128 //! 共有元のモデルが先に破棄された場合は未定義の動作となります。 129 //! 130 //! @param[in] model 共有するマテリアルを持つモデルです。 131 //! SharedMaterialModel(Model * model)132 Builder& SharedMaterialModel(Model* model) 133 { 134 m_Description.sharedMaterialModel = model; 135 return *this; 136 } 137 138 //! @brief 共有するスケルトンを設定します。 139 //! 140 //! 所有権の移動を行いません。 141 //! スケルトンを最初に生成したモデルがスケルトンの所有権を持ちます。 142 //! 共有元のモデルが先に破棄された場合は未定義の動作となります。 143 //! 144 //! @param[in] sharedSkeleton 共有するスケルトンです。 SharedSkeleton(Skeleton * sharedSkeleton)145 Builder& SharedSkeleton(Skeleton* sharedSkeleton) 146 { 147 m_Description.sharedSkeleton = sharedSkeleton; 148 return *this; 149 } 150 151 //! @brief AnimGroup ごとの AnimObject の最大数を指定します。 152 //! 153 //! IsFixedSizeMemory に false を指定しても、この最大数は有効です。 MaxAnimObjectsPerGroup(s32 maxAnimObjectCount)154 Builder& MaxAnimObjectsPerGroup(s32 maxAnimObjectCount) 155 { 156 m_Description.maxAnimObjectsPerGroup = maxAnimObjectCount; 157 return *this; 158 } 159 160 //! @brief アニメーション可能かを設定します。 161 //! 162 //! false を指定すると AnimBinding の生成を行いません。 163 //! そのためアニメーションのバインドができなくなりますが、 164 //! アニメーション更新の処理が行われなくなるため、 165 //! シーンアップデートのパフォーマンスが向上します。 IsAnimationEnabled(bool isAnimationEnabled)166 Builder& IsAnimationEnabled(bool isAnimationEnabled) 167 { 168 m_Description.isAnimationEnabled = isAnimationEnabled; 169 return *this; 170 } 171 172 //! @brief スケルタルモデルを生成します。 173 //! 174 //! parent に NULL を指定した場合は、親ノードへの取り付けを行いません。 175 //! 176 //! @param[in] allocator アロケータです。 177 //! @param[in] parent 親ノードです。 178 //! @param[in] resource リソースです。 179 //! 180 //! @return 生成したスケルタルモデルを返します。 181 //! 182 SkeletalModel* Create( 183 SceneNode* parent, 184 ResSceneObject resource, 185 os::IAllocator* allocator); 186 187 //! @brief 生成時に必要なメモリサイズを取得します。 188 //! 189 //! @param[in] resource リソースです。 190 size_t GetMemorySize( 191 ResSkeletalModel resModel, 192 size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT) const 193 { 194 os::MemorySizeCalculator size(alignment); 195 196 GetMemorySizeInternal(&size, resModel); 197 198 return size.GetSizeWithPadding(alignment); 199 } 200 201 //! @details :private GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResSkeletalModel resModel)202 void GetMemorySizeInternal( 203 os::MemorySizeCalculator* pSize, 204 ResSkeletalModel resModel) const 205 { 206 os::MemorySizeCalculator& size = *pSize; 207 208 if (m_Description.sharedSkeleton == NULL) 209 { 210 ResSkeleton resSkeleton = resModel.GetSkeleton(); 211 212 #ifdef NW_MOVE_ARRAY_CACHE_LINE_ALIGNMENT_ENABLED 213 size.Add( 214 sizeof(Skeleton::TransformPose::Transform) * resSkeleton.GetBonesCount(), 215 Skeleton::TransformPose::TransformArray::MEMORY_ALIGNMENT); 216 #else 217 size += sizeof(Skeleton::TransformPose::Transform) * resSkeleton.GetBonesCount(); 218 #endif 219 StandardSkeleton::GetMemorySizeInternal( 220 pSize, 221 resSkeleton, 222 m_Description.maxCallbacks); 223 } 224 225 // モデル作成 226 size += sizeof(SkeletalModel); 227 SkeletalModel::GetMemorySizeForInitialize(pSize, resModel, m_Description); 228 } 229 230 private: 231 SkeletalModel::Description m_Description; 232 }; 233 234 //---------------------------------------- 235 //! @name シーンツリー 236 //@{ 237 238 //! @brief ビジターを受け付けます。 239 //! 240 //! @param[in] visitor ビジターです。 241 //! 242 virtual void Accept(ISceneVisitor* visitor); 243 244 //@} 245 246 //---------------------------------------- 247 //! @name リソース 248 //@{ 249 250 //! スケルタルモデルのリソースを取得します。 GetResSkeletalModel()251 ResSkeletalModel GetResSkeletalModel() 252 { 253 return ResDynamicCast<ResSkeletalModel>(this->GetResSceneObject()); 254 } 255 256 //! スケルタルモデルのリソースを取得します。 GetResSkeletalModel()257 const ResSkeletalModel GetResSkeletalModel() const 258 { 259 return ResDynamicCast<ResSkeletalModel>(this->GetResSceneObject()); 260 } 261 262 //@} 263 264 //---------------------------------------- 265 //! @name スケルトン 266 //@{ 267 268 //! スケルトンを取得します。 GetSkeleton()269 Skeleton* GetSkeleton() { return m_Skeleton.Get(); } 270 271 //! スケルトンを取得します。 GetSkeleton()272 const Skeleton* GetSkeleton() const { return m_Skeleton.Get(); } 273 274 //! 他モデルのスケルトンを共有している場合は true を返します。 IsSharingSkeleton()275 bool IsSharingSkeleton() const { return this->m_SharingSkeleton; } 276 277 //@} 278 279 //---------------------------------------- 280 //! @name アニメーション 281 //@{ 282 283 //! スケルタルアニメーショングループを取得します。 GetSkeletalAnimGroup()284 AnimGroup* GetSkeletalAnimGroup() { return m_SkeletalAnimGroup; } 285 286 //! スケルタルアニメーショングループを取得します。 GetSkeletalAnimGroup()287 const AnimGroup* GetSkeletalAnimGroup() const { return m_SkeletalAnimGroup; } 288 289 //! スケルタルアニメーショングループのアニメーションバインディング中のインデックスを取得します。 GetSkeletalAnimBindingIndex()290 int GetSkeletalAnimBindingIndex() const { return m_SkeletalAnimBindingIndex; } 291 292 //! スケルタルアニメーションオブジェクトを取得します。 293 const AnimObject* GetSkeletalAnimObject(int objectIndex = 0) const 294 { 295 NW_NULL_ASSERT(m_AnimBinding); 296 return m_AnimBinding->GetAnimObject(m_SkeletalAnimBindingIndex, objectIndex); 297 } 298 299 //! スケルタルアニメーションオブジェクトを取得します。 300 AnimObject* GetSkeletalAnimObject(int objectIndex = 0) 301 { 302 NW_NULL_ASSERT(m_AnimBinding); 303 return m_AnimBinding->GetAnimObject(m_SkeletalAnimBindingIndex, objectIndex); 304 } 305 306 //! スケルタルアニメーションオブジェクトを設定します。 307 void SetSkeletalAnimObject(AnimObject* animObject, int objectIndex = 0) 308 { 309 NW_NULL_ASSERT(m_AnimBinding); 310 m_AnimBinding->SetAnimObject(m_SkeletalAnimBindingIndex, animObject, objectIndex); 311 } 312 313 //@} 314 315 protected: 316 virtual Result Initialize(os::IAllocator* allocator); 317 318 //! @brief Initialize() の実行に必要なメモリサイズを取得します。 319 //! 320 //! @details :private GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,ResSkeletalModel resModel,Description description)321 static void GetMemorySizeForInitialize( 322 os::MemorySizeCalculator* pSize, 323 ResSkeletalModel resModel, 324 Description description) 325 { 326 // SkeletalModel::Initialize 327 os::MemorySizeCalculator& size = *pSize; 328 329 Model::GetMemorySizeForInitialize(pSize, resModel, description); 330 331 // SkeletalModel::CreateSkeletalAnimGroup 332 if (description.isAnimationEnabled) 333 { 334 const int animGroupCount = resModel.GetAnimGroupsCount(); 335 for (int animGroupIdx = 0; animGroupIdx < animGroupCount; ++animGroupIdx) 336 { 337 anim::ResAnimGroup resAnimGroup = resModel.GetAnimGroups(animGroupIdx); 338 const int targetType = resAnimGroup.GetTargetType(); 339 const bool transformFlag = 340 (resAnimGroup.GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM) != 0; 341 if (transformFlag && 342 targetType == anim::ResGraphicsAnimGroup::TARGET_TYPE_BONE) 343 { 344 AnimGroup::Builder() 345 .ResAnimGroup(resAnimGroup) 346 .UseOriginalValue(true) 347 .GetMemorySizeInternal(pSize); 348 break; // 他にスケルタルモデル専用のアニメーショングループがないので 349 } 350 } 351 } 352 } 353 354 //---------------------------------------- 355 //! @name コンストラクタ/デストラクタ 356 //@{ 357 358 //! コンストラクタです。 SkeletalModel(os::IAllocator * allocator,ResSkeletalModel resource,GfxPtr<Skeleton> & skeleton,bool isSharingSkeleton,const SkeletalModel::Description & description)359 SkeletalModel( 360 os::IAllocator* allocator, 361 ResSkeletalModel resource, 362 GfxPtr<Skeleton>& skeleton, 363 bool isSharingSkeleton, 364 const SkeletalModel::Description& description) 365 : Model( 366 allocator, 367 resource, 368 description), 369 m_Skeleton(skeleton), 370 m_SkeletalAnimGroup(NULL), 371 m_SkeletalAnimBindingIndex(-1), 372 m_SharingSkeleton(isSharingSkeleton) 373 { 374 if (!isSharingSkeleton) 375 { 376 m_Skeleton->SetOwnerSkeletalModel(this); 377 } 378 } 379 380 //! デストラクタです。 ~SkeletalModel()381 virtual ~SkeletalModel() 382 { 383 SafeDestroy(m_SkeletalAnimGroup); 384 } 385 386 //@} 387 388 //! スケルタルアニメーション用のアニメーショングループを生成します。 389 Result CreateSkeletalAnimGroup(os::IAllocator* allocator); 390 391 //! スケルタルアニメーションに登録するモデルデータのポインタを取得します。 392 void* GetAnimTargetObject(const anim::ResAnimGroupMember& anim); 393 394 private: 395 GfxPtr<Skeleton> m_Skeleton; 396 AnimGroup* m_SkeletalAnimGroup; 397 int m_SkeletalAnimBindingIndex; 398 bool m_SharingSkeleton; 399 }; 400 401 } // namespace gfx 402 } // namespace nw 403 404 #endif // NW_GFX_SKELETALMODEL_H_ 405