1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_Model.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: 26457 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_GFX_MODEL_H_
17 #define NW_GFX_MODEL_H_
18 
19 #include <nw/gfx/gfx_TransformNode.h>
20 #include <nw/gfx/res/gfx_ResModel.h>
21 #include <nw/ut/ut_Flag.h>
22 #include <nw/ut/ut_MoveArray.h>
23 #include <nw/gfx/gfx_Material.h>
24 #include <nw/gfx/gfx_MaterialActivator.h>
25 #include <nw/gfx/gfx_SimpleMaterialActivator.h>
26 
27 namespace nw
28 {
29 namespace gfx
30 {
31 
32 class IMaterialActivator;
33 
34 //---------------------------------------------------------------------------
35 //! @brief        シーン上に表示されるオブジェクトを表すためのクラスです。
36 //---------------------------------------------------------------------------
37 class Model : public TransformNode
38 {
39 private:
40     NW_DISALLOW_COPY_AND_ASSIGN(Model);
41 
42 public:
43     NW_UT_RUNTIME_TYPEINFO;
44 
45     //! @brief 描画時に呼ばれるコールバック用スロットの定義です。
46     //!
47     //! @sa PreRenderSignal
48     //! @sa PostRenderSignal
49     typedef ut::Signal3<void, Model*, ResMesh, RenderContext*> RenderSignal;
50 
51     //! @brief 描画時に呼ばれるコールバック用スロットの定義です。
52     typedef RenderSignal::SlotType RenderSlot;
53 
54     //! バッファオプションのビットフラグの定義です。
55     enum BufferOption
56     {
57         //! @details :private
58         FLAG_BUFFER_SHADER_PARAMETER_SHIFT,
59         //! @details :private
60         FLAG_BUFFER_SHADING_PARAMETER_SHIFT,
61         //! @details :private
62         FLAG_BUFFER_MATERIAL_COLOR_SHIFT,
63         //! @details :private
64         FLAG_BUFFER_RASTERIZATION_SHIFT,
65         //! @details :private
66         FLAG_BUFFER_TEXTURE_COORDINATOR_SHIFT,
67         //! @details :private
68         FLAG_BUFFER_TEXTURE_MAPPER_SHIFT,
69         //! @details :private
70         FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER_SHIFT,
71         //! @details :private
72         FLAG_BUFFER_FRAGMENT_LIGHTING_SHIFT,
73         //! @details :private
74         FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE_SHIFT,
75         //! @details :private
76         FLAG_BUFFER_TEXTURE_COMBINER_SHIFT,
77         //! @details :private
78         FLAG_BUFFER_ALPHA_TEST_SHIFT,
79         //! @details :private
80         FLAG_BUFFER_FRAGMENT_OPERATION_SHIFT,
81         //! @details :private
82         FLAG_BUFFER_SCENE_ENVIRONMENT_SHIFT,
83 
84         //! シェーダーパラメータを利用するならば、1になります。
85         FLAG_BUFFER_SHADER_PARAMETER                = 0x1 << FLAG_BUFFER_SHADER_PARAMETER_SHIFT,
86         //! シェーディングパラメータを利用するならば、1になります。
87         FLAG_BUFFER_SHADING_PARAMETER               = 0x1 << FLAG_BUFFER_SHADING_PARAMETER_SHIFT,
88         //! マテリアルカラーを利用するならば、1になります。
89         FLAG_BUFFER_MATERIAL_COLOR                  = 0x1 << FLAG_BUFFER_MATERIAL_COLOR_SHIFT,
90         //! ラスタライゼーションを利用するならば、1になります。
91         FLAG_BUFFER_RASTERIZATION                   = 0x1 << FLAG_BUFFER_RASTERIZATION_SHIFT,
92         //! テクスチャコーディネータを利用するならば、1になります。
93         FLAG_BUFFER_TEXTURE_COORDINATOR             = 0x1 << FLAG_BUFFER_TEXTURE_COORDINATOR_SHIFT,
94         //! テクスチャマッパーを利用するならば、1になります。
95         FLAG_BUFFER_TEXTURE_MAPPER                  = 0x1 << FLAG_BUFFER_TEXTURE_MAPPER_SHIFT,
96         //! 未実装です。
97         FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER       = 0x1 << FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER_SHIFT,
98         //! フラグメントライティングを利用するならば、1になります。
99         FLAG_BUFFER_FRAGMENT_LIGHTING               = 0x1 << FLAG_BUFFER_FRAGMENT_LIGHTING_SHIFT,
100         //! @brief フラグメントライティングテーブルを利用するならば、1になります。
101         FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE         = 0x1 << FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE_SHIFT,
102         //! テクスチャコンバイナを利用するならば、1になります。
103         FLAG_BUFFER_TEXTURE_COMBINER                = 0x1 << FLAG_BUFFER_TEXTURE_COMBINER_SHIFT,
104         //! アルファテストを利用するならば、1になります。
105         FLAG_BUFFER_ALPHA_TEST                      = 0x1 << FLAG_BUFFER_ALPHA_TEST_SHIFT,
106         //! フラグメントオペレーションを利用するならば、1になります。
107         FLAG_BUFFER_FRAGMENT_OPERATION              = 0x1 << FLAG_BUFFER_FRAGMENT_OPERATION_SHIFT,
108         //! シーン環境を利用するならば、1になります。
109         FLAG_BUFFER_SCENE_ENVIRONMENT               = 0x1 << FLAG_BUFFER_SCENE_ENVIRONMENT_SHIFT,
110 
111         FLAG_BUFFER_NOT_USE = 0, //!< バッファオプションを使用しません。
112 
113         //! フラグメントシェーダーを一括指定するためのフラグです。
114         MULTI_FLAG_BUFFER_FRAGMENT_SHADER =
115             FLAG_BUFFER_FRAGMENT_LIGHTING         |
116             FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE   |
117             FLAG_BUFFER_TEXTURE_COMBINER          |
118             FLAG_BUFFER_ALPHA_TEST,
119 
120         //! マテリアルを一括指定するためのフラグです。
121         MULTI_FLAG_BUFFER_MATERIAL =
122             FLAG_BUFFER_SHADER_PARAMETER          |
123             FLAG_BUFFER_SHADING_PARAMETER         |
124             FLAG_BUFFER_MATERIAL_COLOR            |
125             FLAG_BUFFER_RASTERIZATION             |
126             FLAG_BUFFER_TEXTURE_COORDINATOR       |
127             FLAG_BUFFER_TEXTURE_MAPPER            |
128             FLAG_BUFFER_PROCEDURAL_TEXTURE_MAPPER |
129             FLAG_BUFFER_FRAGMENT_LIGHTING         |
130             FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE   |
131             FLAG_BUFFER_TEXTURE_COMBINER          |
132             FLAG_BUFFER_ALPHA_TEST                |
133             FLAG_BUFFER_FRAGMENT_OPERATION        |
134             FLAG_BUFFER_SCENE_ENVIRONMENT,
135 
136         //! マテリアルのうち、アニメーションする要素を一括指定するためのフラグです。
137         MULTI_FLAG_ANIMATABLE_MATERIAL =
138             FLAG_BUFFER_MATERIAL_COLOR      |
139             FLAG_BUFFER_TEXTURE_COORDINATOR |
140             FLAG_BUFFER_TEXTURE_MAPPER      |
141             FLAG_BUFFER_FRAGMENT_OPERATION
142     };
143 
144     //! @brief 設定内容です。
145     struct Description : public TransformNode::Description
146     {
147         bit32 bufferOption;          //!< バッファの生成オプションです。
148         Model* sharedMaterialModel; //!< 共有元のマテリアルを持つモデルです。
149 
150         //! @brief コンストラクタです。
DescriptionDescription151         Description() :
152             bufferOption(0),
153             sharedMaterialModel(NULL)
154         {}
155     };
156 
157     //---------------------------------------------------------------------------
158     //! @brief デフォルトのモデル表示フラグ判定関数オブジェクトです。
159     //---------------------------------------------------------------------------
160     struct IsVisibleModelDefaultFunctor
161     {
IsVisibleIsVisibleModelDefaultFunctor162         bool IsVisible(const nw::gfx::Model* model)
163         {
164             return model->IsVisible() && model->IsEnabledResults(SceneNode::FLAG_IS_VISIBLE);
165         }
166     };
167 
168     //----------------------------------------
169     //! @name 作成/破棄
170     //@{
171 
172     //! @brief        モデルを生成します。
173     //!
174     //! @param[in]    parent 親のノードです。
175     //! @param[in]    resource リソースです。
176     //! @param[in]    description 設定内容です。
177     //! @param[in]    allocator アロケータです。
178     //!
179     //! @return       生成されたモデルです。
180     //!
181     static Model* Create(
182         SceneNode* parent,
183         ResSceneObject resource,
184         const Model::Description& description,
185         os::IAllocator* allocator);
186 
187     //! @brief        生成時に必要なメモリサイズを取得します。
188     //!
189     //! @param[in]    resource リソースです。
190     //! @param[in]    description 設定内容です。
191     static size_t GetMemorySize(
192         ResModel resModel,
193         Description description,
194         size_t alignment = os::IAllocator::DEFAULT_ALIGNMENT)
195     {
196         os::MemorySizeCalculator size(alignment);
197 
198         GetMemorySizeInternal(&size, resModel, description);
199 
200         return size.GetSizeWithPadding(alignment);
201     }
202 
203 
204     //! @details :private
GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResModel resModel,Description description)205     static void GetMemorySizeInternal(
206         os::MemorySizeCalculator* pSize,
207         ResModel resModel,
208         Description description)
209     {
210         os::MemorySizeCalculator& size = *pSize;
211 
212         size += sizeof(Model);
213         GetMemorySizeForInitialize(pSize, resModel, description);
214     }
215 
216     //@}
217 
218     //----------------------------------------
219     //! @name シーンツリー
220     //@{
221 
222     //! @brief        ビジターを受け付けます。
223     //!
224     //! @param[in]    visitor ビジターです。
225     //!
226     virtual void Accept(ISceneVisitor* visitor);
227 
228     //@}
229 
230     //----------------------------------------
231     //! @name リソース
232     //@{
233 
234     //! @brief モデルのリソースを取得します。
GetResModel()235     ResModel GetResModel()
236     {
237         // return ResDynamicCast<ResModel>(this->GetResSceneObject());
238         return ResModel(this->GetResSceneObject().ptr());
239     }
240 
241     //! @brief モデルのリソースを取得します。
GetResModel()242     const ResModel GetResModel() const
243     {
244         // return ResDynamicCast<ResModel>(this->GetResSceneObject());
245         return ResModel(this->GetResSceneObject().ptr());
246     }
247 
248     //! @brief メッシュのリソースの配列を取得します。
249     //!
250     //! メッシュのリソースはモデルリソースから取得するのではなく、
251     //! このメソッドを使って取得するようにしてください。
252     //!
253     //! @return メッシュのリソースの配列を取得します。
254     //!
GetResMeshes()255     ResMeshArray GetResMeshes()
256     {
257         if (this->m_MeshBuffers.empty())
258         {
259             ResModel model = this->GetResModel();
260             NW_ASSERT(model.IsValid());
261             return model.GetMeshes();
262         }
263         return this->m_MeshBuffers;
264     }
265 
266     //! @brief インデックスを指定して MeshNodeVisibility のリソースを取得します。
267     //!
268     //! MeshNodeVisibility のリソースはモデルリソースから取得するのではなく、
269     //! このメソッドを使って取得するようにしてください。
270     //!
271     //! @param[in] idx インデックスです。
272     //!
273     //! @return MeshNodeVisibility のリソースを取得します。
274     //!
GetResMeshNodeVisibilities(int idx)275     ResMeshNodeVisibility GetResMeshNodeVisibilities(int idx)
276     {
277         if (this->m_MeshNodeVisibilityBuffers.empty())
278         {
279             ResModel model = this->GetResModel();
280             NW_ASSERT(model.IsValid());
281             return model.GetMeshNodeVisibilities(idx);
282         }
283         return ResMeshNodeVisibility( &this->m_MeshNodeVisibilityBuffers[idx] );
284     }
285 
286     //@}
287 
288     //----------------------------------------
289     //! @name アニメーション
290     //@{
291 
292     //! @brief マテリアルアニメーショングループを取得します。
GetMaterialAnimGroup()293     AnimGroup* GetMaterialAnimGroup() { return m_MaterialAnimGroup; }
294 
295     //! @brief マテリアルアニメーショングループを取得します。
GetMaterialAnimGroup()296     const AnimGroup* GetMaterialAnimGroup() const { return m_MaterialAnimGroup; }
297 
298     //! @brief マテリアルアニメーショングループのアニメーションバインディング中のインデックスを取得します。
GetMaterialAnimBindingIndex()299     int GetMaterialAnimBindingIndex() const { return m_MaterialAnimBindingIndex; }
300 
301     //! @brief マテリアルアニメーションオブジェクトを取得します。
302     const AnimObject* GetMaterialAnimObject(int objectIndex = 0) const
303     {
304         NW_NULL_ASSERT(m_AnimBinding);
305         return m_AnimBinding->GetAnimObject(m_MaterialAnimBindingIndex, objectIndex);
306     }
307 
308     //! @brief マテリアルアニメーションオブジェクトを取得します。
309     AnimObject* GetMaterialAnimObject(int objectIndex = 0)
310     {
311         NW_NULL_ASSERT(m_AnimBinding);
312         return m_AnimBinding->GetAnimObject(m_MaterialAnimBindingIndex, objectIndex);
313     }
314 
315     //! @brief マテリアルアニメーションオブジェクトを設定します。
316     void SetMaterialAnimObject(AnimObject* animObject, int objectIndex = 0)
317     {
318         NW_NULL_ASSERT(m_AnimBinding);
319         m_AnimBinding->SetAnimObject(m_MaterialAnimBindingIndex, animObject, objectIndex);
320     }
321 
322     //! @brief ビジビリティアニメーショングループを取得します。
GetVisibilityAnimGroup()323     AnimGroup* GetVisibilityAnimGroup() { return m_VisibilityAnimGroup; }
324 
325     //! @brief ビジビリティアニメーショングループを取得します。
GetVisibilityAnimGroup()326     const AnimGroup* GetVisibilityAnimGroup() const { return m_VisibilityAnimGroup; }
327 
328     //! @brief ビジビリティアニメーショングループのアニメーションバインディング中のインデックスを取得します。
GetVisibilityAnimBindingIndex()329     int GetVisibilityAnimBindingIndex() const { return m_VisibilityAnimBindingIndex; }
330 
331     //! @brief ビジビリティアニメーションオブジェクトを取得します。
332     const AnimObject* GetVisibilityAnimObject(int objectIndex = 0) const
333     {
334         NW_NULL_ASSERT(m_AnimBinding);
335         return m_AnimBinding->GetAnimObject(m_VisibilityAnimBindingIndex, objectIndex);
336     }
337 
338     //! @brief ビジビリティアニメーションオブジェクトを取得します。
339     AnimObject* GetVisibilityAnimObject(int objectIndex = 0)
340     {
341         NW_NULL_ASSERT(m_AnimBinding);
342         return m_AnimBinding->GetAnimObject(m_VisibilityAnimBindingIndex, objectIndex);
343     }
344 
345     //! @brief ビジビリティアニメーションオブジェクトを設定します。
346     void SetVisibilityAnimObject(AnimObject* animObject, int objectIndex = 0)
347     {
348         NW_NULL_ASSERT(m_AnimBinding);
349         m_AnimBinding->SetAnimObject(m_VisibilityAnimBindingIndex, animObject, objectIndex);
350     }
351 
352     //@}
353 
354     //----------------------------------------
355     //! @name コールバック
356     //@{
357 
358     //! @brief モデルの描画前に呼び出されるシグナルを取得します。
359     //!
360     //! このシグナルはライブラリからは呼び出されません。
361     //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。
362     //!
363     //! @sa RenderSignal
PreRenderSignal()364     RenderSignal& PreRenderSignal() { return *m_PreRenderSignal; }
365 
366     //! @brief モデルの描画前に呼び出されるシグナルを取得します。
367     //!
368     //! このシグナルはライブラリからは呼び出されません。
369     //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。
370     //!
371     //! @sa RenderSignal
PreRenderSignal()372     const RenderSignal& PreRenderSignal() const { return *m_PreRenderSignal; }
373 
374     //! @brief モデルの描画後に呼び出されるシグナルを取得します。
375     //!
376     //! このシグナルはライブラリからは呼び出されません。
377     //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。
378     //!
379     //! @sa RenderSignal
PostRenderSignal()380     RenderSignal& PostRenderSignal() { return *m_PostRenderSignal; }
381 
382     //! @brief モデルの描画後に呼び出されるシグナルを取得します。
383     //!
384     //! このシグナルはライブラリからは呼び出されません。
385     //! シグナルを有効にするためには、ユーザーが明示的に呼び出す必要があります。
386     //!
387     //! @sa RenderSignal
PostRenderSignal()388     const RenderSignal& PostRenderSignal() const { return *m_PostRenderSignal; }
389 
390 
391     // [非推奨] 互換性のために残してありますが、こちらの定義は用いないでください。
392 
393     //! @details :private
394     typedef gfx::MaterialArray MaterialArray;
395 
396     //@}
397 
398     //----------------------------------------
399     //! @name マテリアル
400     //@{
401 
402     //! @brief マテリアルのリストの範囲を表す型の定義です。
403     typedef std::pair<
404         gfx::MaterialArray::iterator,
405         gfx::MaterialArray::iterator> MaterialRange;
406 
407     //! @brief マテリアルのリストの先頭と末尾を取得します。
GetMaterials()408     MaterialRange GetMaterials()
409     {
410         return std::make_pair(
411             m_Materials.begin(),
412             m_Materials.end());
413     }
414 
415     //! @brief マテリアルの数を取得します。
GetMaterialCount()416     int GetMaterialCount() const { return m_Materials.size(); }
417 
418     //! @brief 指定したインデックス番号のマテリアルを取得します。
GetMaterial(int index)419     Material* GetMaterial(int index)
420     {
421         return m_Materials[index];
422     }
423 
424     //! @brief 指定したインデックス番号のマテリアルを取得します。
GetMaterial(int index)425     const Material* GetMaterial(int index) const
426     {
427         return m_Materials[index];
428     }
429 
430     //! @brief マテリアルアクティベータを取得します。
GetMaterialActivator()431     const IMaterialActivator* GetMaterialActivator() const
432     {
433         return this->m_MaterialActivator.Get();
434     }
435 
436     //! @brief マテリアルアクティベータを取得します。
GetMaterialActivator()437     IMaterialActivator* GetMaterialActivator()
438     {
439         return this->m_MaterialActivator.Get();
440     }
441 
442     //! @brief 所有権の移動を行いマテリアルアクティベータを設定します。
443     //!        モデルクラスが破棄された場合に一緒に破棄されます。
SetMaterialActivator(IMaterialActivator * materialActivator)444     void SetMaterialActivator(IMaterialActivator* materialActivator)
445     {
446         return this->m_MaterialActivator.Reset(materialActivator);
447     }
448 
449     //! @brief 所有権の移動を行わずにマテリアルアクティベータを設定します。
450     //!        ユーザー側でマテリアルアクティベータを管理する場合はこちらで設定してください。
SetSharedMaterialActivator(IMaterialActivator * materialActivator)451     void SetSharedMaterialActivator(IMaterialActivator* materialActivator)
452     {
453         return this->m_MaterialActivator.Reset(materialActivator, false);
454     }
455 
456     //@}
457 
458     //----------------------------------------
459     //! @name バッファオプション
460     //@{
461 
462     //! @brief バッファオプションを確認します。
CheckBufferOption(bit32 bufferOption)463     bool CheckBufferOption(bit32 bufferOption) const
464     {
465         return ut::CheckFlag(this->m_BufferOption, bufferOption);
466     }
467 
468     //! @brief バッファオプションを取得します。
GetBufferOption()469     bit32 GetBufferOption() const
470     {
471         return this->m_BufferOption;
472     }
473 
474     //@}
475 
476     //----------------------------------------
477     //! @name マトリクス
478     //@{
479 
480     //! @brief モデルビューマトリクスを取得します。
ModelViewMatrix()481     math::MTX34& ModelViewMatrix()
482     {
483         return this->m_ModelViewMatrix;
484     }
485 
486     //! @brief モデルビューマトリクスを取得します。
ModelViewMatrix()487     const math::MTX34& ModelViewMatrix() const
488     {
489         return this->m_ModelViewMatrix;
490     }
491 
492     //! @brief 法線マトリクスを取得します。
NormalMatrix()493     math::MTX34& NormalMatrix()
494     {
495         return this->m_NormalMatrix;
496     }
497 
498     //! @brief 法線マトリクスを取得します。
NormalMatrix()499     const math::MTX34& NormalMatrix() const
500     {
501         return this->m_NormalMatrix;
502     }
503 
504     //! @brief モデルビュー行列と法線用行列を更新します。
505     NW_INLINE void UpdateModelViewMatrixAndNormalMatrix(
506         const math::MTX34& viewMatrix, bool isModelCoordinate);
507 
508     //@}
509 
510     //----------------------------------------
511     //! @name レイヤー
512     //@{
513 
514     //! @brief レイヤーIDを取得します。
GetLayerId()515     u8 GetLayerId() const { return m_LayerId; }
516 
517     //! @brief レイヤーIDを設定します。
SetLayerId(u8 layerId)518     void SetLayerId(u8 layerId) { m_LayerId = layerId; }
519 
520      //! @brief メッシュの描画レイヤー値を取得します。
GetRenderLayerId(ResMesh mesh)521     ResMaterial::TranslucencyKind GetRenderLayerId(ResMesh mesh)
522     {
523         NW_ASSERT(mesh.IsValid());
524         Material* material = this->GetMaterial(mesh.GetMaterialIndex());
525 
526         ResMaterial shadingParametersResMaterial = material->GetShaderParameterResMaterial();
527         NW_ASSERT(shadingParametersResMaterial.IsValid());
528 
529         return shadingParametersResMaterial.GetTranslucencyKind();
530     }
531 
532     //@}
533 
534     //----------------------------------------
535     //! @name 描画
536     //@{
537 
538     //! @brief モデルを描画するかどうかのフラグを取得します。
IsVisible()539     bool IsVisible() const { return m_Visible; }
540 
541     //! @brief モデルを描画するかどうかのフラグを設定します。
SetVisible(bool visible)542     void SetVisible(bool visible) { m_Visible = visible; }
543 
544     //! @brief メッシュが描画されるかどうかのフラグを取得します。
545     //!
546     //! メッシュのビジビリティとメッシュノードビジビリティの論理積を返します。
547     //!
548     //! @param[in] mesh 対象のメッシュです。
549     //!
550     //! @return メッシュが描画されるかどうかのフラグを返します。
IsMeshVisible(ResMesh mesh)551     bool IsMeshVisible(ResMesh mesh)
552     {
553         int index = mesh.GetMeshNodeVisibilityIndex();
554         if (index < 0)
555         {
556             return mesh.IsVisible();
557         }
558         else
559         {
560             ResMeshNodeVisibility visibility = this->GetResMeshNodeVisibilities(index);
561             NW_ASSERT(visibility.IsValid());
562             {
563                 return visibility.IsVisible() && mesh.IsVisible();
564             }
565         }
566     }
567 
568     //! @brief 描画ソート用キーのキャッシュを無効化します。
569     //!
570     //! @sa RenderQueue::Reset
571     void InvalidateRenderKeyCache();
572     //@}
573 
574     //----------------------------------------
575     //! @name ユーザーパラメータ
576     //@{
577 
578     //! @brief ユーザーパラメータを取得します。
579     template<typename Type>
GetUserParameter()580     Type GetUserParameter() const
581     {
582         NW_STATIC_ASSERT(sizeof(Type) <= 4);
583         return *reinterpret_cast<const Type*>(&m_UserParameter);
584     }
585 
586     //! @brief ユーザーパラメータを設定します。
587     template<typename Type>
SetUserParameter(Type parameter)588     void SetUserParameter(Type parameter)
589     {
590         NW_STATIC_ASSERT(sizeof(Type) <= 4);
591         m_UserParameter = *reinterpret_cast<u32*>(&parameter);
592     }
593 
594     //@}
595 
596 
597 protected:
598     virtual Result Initialize(os::IAllocator* allocator);
599 
600     //----------------------------------------
601     //! @name コンストラクタ/デストラクタ
602     //@{
603 
604     //! コンストラクタです。
Model(os::IAllocator * allocator,ResTransformNode resource,const Model::Description & description)605     Model(
606         os::IAllocator* allocator,
607         ResTransformNode resource,
608         const Model::Description& description)
609     : TransformNode(
610         allocator,
611         resource,
612         description),
613       m_MaterialAnimGroup(NULL),
614       m_MaterialAnimBindingIndex(0),
615       m_VisibilityAnimGroup(NULL),
616       m_VisibilityAnimBindingIndex(0),
617       m_PreRenderSignal(NULL),
618       m_PostRenderSignal(NULL),
619       m_MeshBuffers(NULL, NULL),
620       m_BufferOption(description.bufferOption),
621       m_ModelViewMatrix(math::MTX34::Identity()),
622       m_NormalMatrix(math::MTX34::Identity()),
623       m_LayerId(0),
624       m_OriginalVisibility(true),
625       m_Visible(true),
626       m_Description(description),
627       m_UserParameter(0),
628       m_SharingMaterial(description.sharedMaterialModel != NULL)
629     {
630         SetVisible(ResStaticCast<ResModel>(resource).IsVisible());
631     }
632 
633     //! デストラクタです。
~Model()634     virtual ~Model()
635     {
636         DestroyResMeshes(&GetAllocator(), m_MeshBuffers);
637         SafeDestroy(this->m_PreRenderSignal);
638         SafeDestroy(this->m_PostRenderSignal);
639 
640         if (!m_SharingMaterial)
641         {
642             SafeDestroyAll(this->m_Materials);
643         }
644 
645         SafeDestroy(this->m_MaterialAnimGroup);
646         SafeDestroy(this->m_VisibilityAnimGroup);
647     }
648 
649     //@}
650 
651     //! @brief   Initialize() の実行に必要なメモリサイズを取得します。
652     //!
653     //! @details :private
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,ResModel resModel,Description description)654     static void GetMemorySizeForInitialize(
655         os::MemorySizeCalculator* pSize,
656         ResModel resModel,
657         Description description)
658     {
659         NW_ASSERT(description.isFixedSizeMemory);
660 
661         os::MemorySizeCalculator& size = *pSize;
662 
663         TransformNode::GetMemorySizeForInitialize(pSize, resModel, description);
664 
665         // Model::CreateResMeshes
666         const s32 meshesCount = resModel.GetMeshesCount();
667         const s32 visibilitiesConut = resModel.GetMeshNodeVisibilitiesCount();
668 
669         size += sizeof(ut::Offset) * meshesCount;
670         size += sizeof(ResMeshData) * meshesCount;
671         size += sizeof(bool) * meshesCount;
672 
673         // Model::CreateResMeshNodeVisibilities
674         size += sizeof(ResMeshNodeVisibilityData) * visibilitiesConut;
675         size += sizeof(bool) * visibilitiesConut;
676 
677         // Model::CreateMaterials
678         if (description.sharedMaterialModel != NULL)
679         {
680             const int materialCount = description.sharedMaterialModel->GetMaterialCount();
681             size += sizeof(Material*) * materialCount;
682         }
683         else
684         {
685             const s32 bufferCount = (description.bufferOption == 0x0) ? 0 : 1;
686             const s32 materialCount = resModel.GetMaterialsCount();
687 
688             size += sizeof(Material*) * materialCount;
689 
690             for (int i=0; i < materialCount ; i++)
691             {
692                 Material::GetMemorySizeInternal(
693                     pSize,
694                     resModel.GetMaterials(i),
695                     bufferCount,
696                     description.bufferOption);
697             }
698         }
699 
700         // Model::CreateCallbacks
701         if (description.maxCallbacks == 0)
702         {
703             RenderSignal::GetMemorySizeForInvalidateSignalInternal(pSize);
704             RenderSignal::GetMemorySizeForInvalidateSignalInternal(pSize);
705         }
706         else
707         {
708             RenderSignal::GetMemorySizeForFixedSizedSignalInternal(pSize, description.maxCallbacks);
709             RenderSignal::GetMemorySizeForFixedSizedSignalInternal(pSize, description.maxCallbacks);
710         }
711 
712         // Model::CreateAnimGroups
713         if (description.isAnimationEnabled)
714         {
715             const int animGroupCount = resModel.GetAnimGroupsCount();
716             for (int animGroupIdx = 0; animGroupIdx < animGroupCount; ++animGroupIdx)
717             {
718                 anim::ResAnimGroup resAnimGroup = resModel.GetAnimGroups(animGroupIdx);
719 
720                 if (
721                     resAnimGroup.GetTargetType() == anim::ResGraphicsAnimGroup::TARGET_TYPE_MATERIAL ||
722                     resAnimGroup.GetTargetType() == anim::ResGraphicsAnimGroup::TARGET_TYPE_VISIBILITY)
723                 {
724                     AnimGroup::Builder()
725                         .ResAnimGroup(resAnimGroup)
726                         .UseOriginalValue(true)
727                         .GetMemorySizeInternal(pSize);
728                 }
729             }
730         }
731 
732         // Model::CreateMaterialActivator
733         if (description.sharedMaterialModel == NULL)
734         {
735             if (description.bufferOption == 0 || description.bufferOption == FLAG_BUFFER_SCENE_ENVIRONMENT)
736             {
737                 SimpleMaterialActivator::GetMemorySizeInternal(pSize);
738             }
739             else
740             {
741                 MaterialActivator::GetMemorySizeInternal(pSize);
742             }
743         }
744     }
745 
746 private:
747 
748     //! マテリアルのメンバへの参照を解決します。
749     void BindMaterialAnim(AnimGroup* animGroup);
750 
751     //! ビジビリティのメンバへの参照を解決します。
752     void BindVisibilityAnim(AnimGroup* animGroup);
753 
754     //! メッシュリソースを生成します。
755     Result CreateResMeshes(os::IAllocator* allocator);
756 
757     //! メッシュリソースを破棄します。
758     void DestroyResMeshes(os::IAllocator* allocator, ResMeshArray resMeshes);
759 
760     //! MeshNodeVisibility リソースを生成します。
761     Result CreateResMeshNodeVisibilities(os::IAllocator* allocator);
762 
763     //! リソースからマテリアルを生成します。
764     Result CreateMaterials(os::IAllocator* allocator);
765 
766     //! アニメーショングループを生成します。
767     Result CreateAnimGroups(os::IAllocator* allocator);
768 
769     //! コールバック関数を生成します。
770     Result CreateCallbacks(os::IAllocator* allocator);
771 
772     //! マテリアルのアクティベータを生成します。
773     Result CreateMaterialActivator(os::IAllocator* allocator);
774 
775     //! アニメーションに登録するモデルデータのポインタを取得します。
776     void* GetAnimTargetObject(const anim::ResAnimGroupMember& anim);
777 
778     //! マテリアルアニメーションで書き換えるメンバへのポインタを取得します。
779     void* GetMaterialAnimTargetPtr(Material* material, const anim::ResAnimGroupMember& anim, bool isOriginalValue);
780 
781     //! アニメーション対象のマテリアルのインデックスを取得します。
782     int GetMaterialIndex(const anim::ResAnimGroupMember& anim) const;
783 
784     AnimGroup* m_MaterialAnimGroup;
785     s32 m_MaterialAnimBindingIndex;
786 
787     AnimGroup* m_VisibilityAnimGroup;
788     s32 m_VisibilityAnimBindingIndex;
789 
790     RenderSignal* m_PreRenderSignal;
791     RenderSignal* m_PostRenderSignal;
792 
793     nw::gfx::MaterialArray m_Materials;
794     ResMeshArray m_MeshBuffers;
795     ut::MoveArray<ResMeshNodeVisibilityData> m_MeshNodeVisibilityBuffers;
796     bit32 m_BufferOption;
797     math::MTX34 m_ModelViewMatrix;
798     math::MTX34 m_NormalMatrix;
799     GfxPtr<IMaterialActivator> m_MaterialActivator;
800 
801     u8 m_LayerId;
802 
803     bool m_OriginalVisibility;
804     bool m_Visible;
805     ut::MoveArray<bool> m_MeshOriginalVisibilities;
806     ut::MoveArray<bool> m_MeshNodeOriginalVisibilities;
807 
808     const Model::Description& m_Description;
809 
810     u32 m_UserParameter;
811     bool m_SharingMaterial;
812 };
813 
814 //----------------------------------------
815 NW_INLINE void
UpdateModelViewMatrixAndNormalMatrix(const math::MTX34 & viewMatrix,bool isModelCoordinate)816 Model::UpdateModelViewMatrixAndNormalMatrix(
817     const math::MTX34& viewMatrix,
818     bool isModelCoordinate)
819 {
820 #if 1 // フラグの判定を行うとより多くのCPU時間を消費する傾向にあるので、判定をせずに全て計算を行うほうを有効にしておきます。
821     // 累積スケールが1でない場合は法線マトリクスの向きを補正します。
822     if (isModelCoordinate)
823     {
824         // ViewMatrix * WorldInverseTranspose * ModelNormalVector
825         math::MTX34 worldInvTranspose;
826         math::MTX34InvTranspose(&worldInvTranspose, &this->WorldMatrix());
827         math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose);
828     }
829     else
830     {
831         if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_SCALE_ONE))
832         {
833             // ViewMatrix * WorldNormalVector
834             math::MTX34Copy(&this->NormalMatrix(), &viewMatrix);
835         }
836         else
837         {
838             // ViewMatrix * WorldInverseTranspose * WorldInverse * WorldNormalVector
839             math::MTX34 worldInv;
840             math::MTX34 worldTranspose;
841             math::MTX34 worldInvTranspose;
842             math::MTX34Inverse(&worldInv, this->WorldMatrix());
843             math::MTX34Transpose(&worldTranspose, &worldInv);
844             math::MTX34Mult(&worldInvTranspose, &worldInv, &worldTranspose);
845             math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose);
846         }
847     }
848 #else
849     // 累積スケールが1でない場合は法線マトリクスの向きを補正します。
850     if (isModelCoordinate)
851     {
852         if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_SCALE_ONE))
853         {
854             // ViewMatrix * WorldMatrix * ModelNormalVector
855             math::MTX34 modelView;
856             math::MTX34Mult(&modelView, &viewMatrix, &this->WorldMatrix());
857             math::MTX34Copy(&this->NormalMatrix(), &modelView);
858         }
859         else if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_UNIFORM_SCALE))
860         {
861             // ViewMatrix * InverseScale * WorldMatrix * ModelNormalVector
862             math::MTX34 scaleMtx;
863             math::MTX34 reScaleMtx;
864             f32 scale = 1.0f / this->WorldTransform().Scale().x;
865             scaleMtx.SetupScale(math::VEC3(scale, scale, scale));
866             math::MTX34Mult(&reScaleMtx, &scaleMtx, &this->WorldMatrix());
867             math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &reScaleMtx);
868         }
869         else
870         {
871             // ViewMatrix * WorldInverseTranspose * ModelNormalVector
872             math::MTX34 worldInvTranspose;
873             math::MTX34InvTranspose(&worldInvTranspose, &this->WorldMatrix());
874             math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose);
875         }
876     }
877     else
878     {
879         if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_SCALE_ONE))
880         {
881             // ViewMatrix * WorldNormalVector
882             math::MTX34Copy(&this->NormalMatrix(), &viewMatrix);
883         }
884         else if (this->WorldTransform().IsEnabledFlags(CalculatedTransform::FLAG_IS_UNIFORM_SCALE))
885         {
886             // ViewMatrix * InverseScale * WorldNormalVector
887             math::MTX34 scaleMtx;
888             f32 scale = 1.0f / this->WorldTransform().Scale().x;
889             scaleMtx.SetupScale(math::VEC3(scale, scale, scale));
890             math::MTX34Mult(&this->NormalMatrix(), &scaleMtx, &viewMatrix);
891         }
892         else
893         {
894             // ViewMatrix * WorldInverseTranspose * WorldInverse * WorldNormalVector
895             math::MTX34 worldInv;
896             math::MTX34 worldTranspose;
897             math::MTX34 worldInvTranspose;
898             math::MTX34Inverse(&worldInv, this->WorldMatrix());
899             math::MTX34Transpose(&worldTranspose, &worldInv);
900             math::MTX34Mult(&worldInvTranspose, &worldInv, &worldTranspose);
901             math::MTX34Mult(&this->NormalMatrix(), &viewMatrix, &worldInvTranspose);
902         }
903 #endif
904 }
905 
906 } // namespace gfx
907 } // namespace nw
908 
909 #endif // NW_GFX_MODEL_H_
910