1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_AnimEvaluator.cpp
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 #include "precompiled.h"
19 
20 #include <nw/gfx/gfx_AnimEvaluator.h>
21 
22 namespace nw
23 {
24 namespace gfx
25 {
26 
27 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimEvaluator    , BaseAnimEvaluator);
28 
29 //----------------------------------------------------------
30 int
GetCacheBufferSizeNeeded() const31 AnimEvaluator::GetCacheBufferSizeNeeded() const
32 {
33     return GetCacheBufferSizeNeeded(m_AnimData);
34 }
35 
36 //----------------------------------------------------------
37 int
GetCacheBufferSizeNeeded(const anim::ResAnim & animData)38 AnimEvaluator::GetCacheBufferSizeNeeded(const anim::ResAnim& animData)
39 {
40     const int headBytes = anim::AnimResult().GetOffsetToValueBuffer();
41     int size = 0;
42 
43     const int memberAnimCount = animData.GetMemberAnimSetCount();
44     for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx)
45     {
46         const anim::ResMemberAnim memberAnim = animData.GetMemberAnimSet(animIdx);
47         const int primBytes = memberAnim.GetPrimitiveSize();
48         size += ut::RoundUp(headBytes + primBytes, sizeof(bit32));
49     }
50     return size;
51 }
52 
53 //----------------------------------------------------------
54 void
SetCacheBufferPointers()55 AnimEvaluator::SetCacheBufferPointers()
56 {
57     const int headBytes = anim::AnimResult().GetOffsetToValueBuffer();
58     u8* cachePtr = reinterpret_cast<u8*>(m_CacheBuf);
59     const int memberAnimCount = m_AnimData.GetMemberAnimSetCount();
60     for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx)
61     {
62         m_CachePtrs[animIdx] = reinterpret_cast<anim::AnimResult*>(cachePtr);
63         const anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
64         const int primBytes = memberAnim.GetPrimitiveSize();
65         cachePtr += ut::RoundUp(headBytes + primBytes, sizeof(bit32));
66     }
67 }
68 
69 //----------------------------------------------------------
AnimEvaluator(os::IAllocator * allocator)70 AnimEvaluator::AnimEvaluator(
71     os::IAllocator* allocator)
72 : BaseAnimEvaluator(allocator, ANIMTYPE_SIMPLE),
73   m_CacheBuf(NULL),
74   m_SharedCache(NULL)
75 {
76 }
77 
78 //----------------------------------------------------------
79 void
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)80 AnimEvaluator::GetMemorySizeForInitialize(
81     os::MemorySizeCalculator* pSize,
82     const nw::anim::ResAnim& animData,
83     const int maxMembers,
84     const int maxAnimMembers,
85     bool allocCache)
86 {
87     os::MemorySizeCalculator& size = *pSize;
88 
89     BaseAnimEvaluator::GetMemorySizeForInitialize(pSize, maxMembers, maxAnimMembers);
90     size += sizeof(anim::AnimResult*) * maxAnimMembers;
91 
92     if (allocCache)
93     {
94         size += AnimEvaluator::GetCacheBufferSizeNeeded(animData);
95     }
96 }
97 
98 //----------------------------------------------------------
Initialize(const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)99 Result AnimEvaluator::Initialize(
100     const nw::anim::ResAnim& animData,
101     const int maxMembers,
102     const int maxAnimMembers,
103     bool allocCache)
104 {
105     // 親クラスの初期化を通す
106     Result result = BaseAnimEvaluator::Initialize(animData, maxMembers, maxAnimMembers);
107     NW_ENSURE_AND_RETURN(result);
108 
109     void* memory = GetAllocator().Alloc(sizeof(anim::AnimResult*) * maxAnimMembers);
110     if (memory == NULL)
111     {
112         result |= Result::MASK_FAIL_BIT;
113     }
114     NW_ENSURE_AND_RETURN(result);
115 
116     m_CachePtrs = ut::MoveArray<anim::AnimResult*>(memory, maxAnimMembers, &GetAllocator());
117     m_CachePtrs.Resize(animData.GetMemberAnimSetCount());
118 
119     if (allocCache)
120     {
121         // サイズ0でのAllocを回避する
122         // CreateEmpty~Anim()などを使用した場合に起こりうる
123         if (animData.GetMemberAnimSetCount() != 0)
124         {
125             m_CacheBuf = GetAllocator().Alloc(GetCacheBufferSizeNeeded());
126             if (m_CacheBuf == NULL)
127             {
128                 result |= Result::MASK_FAIL_BIT;
129             }
130             NW_ENSURE_AND_RETURN(result);
131 
132             SetCacheBufferPointers();
133         }
134     }
135 
136     return result;
137 }
138 
139 //----------------------------------------------------------
140 Result
ForceBindMaterialAnim(AnimGroup * animGroup,const char * materialName)141 AnimEvaluator::ForceBindMaterialAnim(AnimGroup* animGroup, const char* materialName)
142 {
143     NW_NULL_ASSERT(materialName);
144 
145     NW_FAILSAFE_IF (std::strcmp(m_AnimData.GetTargetAnimGroupName(), "MaterialAnimation") != 0)
146     {
147         return Result(BIND_RESULT_IRRELEVANT_ANIM_TYPE | Result::MASK_FAIL_BIT);
148     }
149     return TryBindTemplate(animGroup, ReplaceMaterialNameIndexGetterFunctor(materialName));
150 }
151 
152 //----------------------------------------------------------
153 const anim::AnimResult*
GetResult(void * target,int memberIdx) const154 AnimEvaluator::GetResult(
155     void* target,
156     int memberIdx
157 ) const
158 {
159     //-----------------------------------------------------------------
160     // メンバに関連付けられたアニメーションが存在しない場合は
161     // target を変更せずに NULL を返す
162     if (!HasMemberAnim(memberIdx))
163     {
164         return NULL;
165     }
166 
167     //-----------------------------------------------------------------
168     const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
169     const int animIdx = m_BindIndexTable[memberIdx];
170     if (m_CacheBuf != NULL && !m_IsCacheDirty)
171     {
172         //-----------------------------------------------------------------
173         // キャッシュがあればキャッシュの値を返す
174         if (blendOp != NULL)
175         {
176             return m_CachePtrs[animIdx];
177         }
178         else
179         {
180             anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
181             memberAnim.ApplyCacheForType(target, m_CachePtrs[animIdx]);
182             // ブレンドオペレーションがない場合、返り値は使用されないが
183             // ブレンダに評価したことを伝えるために target を返す
184             return reinterpret_cast<anim::AnimResult*>(target);
185         }
186     }
187     else
188     {
189         //-----------------------------------------------------------------
190         // アニメーションカーブを評価して対象に書き込む
191         anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
192         const void* originalValue = m_AnimGroup->HasOriginalValue()
193             ? m_AnimGroup->GetOriginalValue(memberIdx)
194             : NULL;
195 
196         if (blendOp != NULL)
197         {
198             anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
199             bit32 flags = memberAnim.EvaluateResultForType(
200                 result->GetValueBuffer(), result->GetFlags(),
201                 m_AnimFrameController.GetFrame(), originalValue);
202             result->SetFlags(flags);
203             return result;
204         }
205         else
206         {
207             memberAnim.EvaluateResultForType(
208                 target, 0, m_AnimFrameController.GetFrame(),
209                 originalValue);
210 
211             // ブレンドオペレーションがない場合、返り値は使用されないが
212             // ブレンダに評価したことを伝えるために target を返す
213             return reinterpret_cast<anim::AnimResult*>(target);
214         }
215     }
216 }
217 
218 //----------------------------------------------------------
219 void
UpdateCacheNonVirtual()220 AnimEvaluator::UpdateCacheNonVirtual()
221 {
222     if (m_IsCacheDirty)
223     {
224         if (m_CacheBuf != NULL && m_IsCacheDirty)
225         {
226             UpdateCacheImpl();
227         }
228         else if (m_UseSharedCache && m_SharedCache != NULL)
229         {
230             // 共有キャッシュのDirtyフラグは、
231             // 現在のところアニメを変更したときに手動でtrueを立てるときしか使用しない
232             if (m_SharedCache->IsDirty() ||
233                 GetFrame() != m_SharedCache->GetFrame() ||
234                 GetStepFrame() != m_SharedCache->GetStepFrame())
235             {
236                 UpdateCacheImpl();
237 
238                 // 共有キャッシュの情報更新
239                 m_SharedCache->SetFrame(GetFrame());
240                 m_SharedCache->SetStepFrame(GetStepFrame());
241                 m_SharedCache->SetDirtyFlag(false);
242             }
243         }
244     }
245 
246     m_IsCacheDirty = false;
247 }
248 
249 void
UpdateCacheImpl()250 AnimEvaluator::UpdateCacheImpl()
251 {
252     int animCount = m_AnimData.GetMemberAnimSetCount();
253     for (int animIdx = 0; animIdx < animCount; ++animIdx)
254     {
255         anim::AnimResult* result = m_CachePtrs[animIdx];
256         result->ResetFlags();
257 
258         // バインドされたメンバーがモデルに存在しない場合もあるのでチェック
259         const int memberIdx = m_ReverseBindIndexTable[animIdx];
260         if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
261         {
262             continue;
263         }
264 
265         this->GetResult(result, memberIdx);
266     }
267 }
268 
269 } // namespace gfx
270 } // namespace nw
271