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