1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_AnimObject.cpp
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: 28041 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <nw/gfx/gfx_TransformAnim.h>
19
20 namespace {
21 // HACK
22 using namespace nw::gfx;
23 using namespace nw::anim;
24
ClearMaterialHash(ResAnimGroupMember member)25 void ClearMaterialHash(ResAnimGroupMember member)
26 {
27 ResMaterial material(reinterpret_cast<void*>(member.GetResMaterialPtr()));
28
29 switch(member.GetObjectType())
30 {
31 case ResAnimGroupMember::OBJECT_TYPE_MATERIAL_COLOR:
32 material.SetMaterialColorHash(0x0);
33 break;
34
35 case ResAnimGroupMember::OBJECT_TYPE_TEXTURE_SAMPLER:
36 material.SetTextureMappersHash(0x0);
37 material.SetTextureSamplersHash(0x0);
38 break;
39
40 case ResAnimGroupMember::OBJECT_TYPE_TEXTURE_MAPPER:
41 // TODO: サンプラーが変化しない場合はHashの再計算が可能
42 material.SetTextureMappersHash(0x0);
43 break;
44
45 case ResAnimGroupMember::OBJECT_TYPE_BLEND_OPERATION:
46 material.SetFragmentOperationHash(0x0);
47 break;
48
49 case ResAnimGroupMember::OBJECT_TYPE_TEXTURE_COORDINATOR:
50 material.SetTextureCoordinatorsHash(0x0);
51 break;
52 }
53 }
54 }
55
56 namespace nw
57 {
58 namespace gfx
59 {
60
61 NW_UT_RUNTIME_TYPEINFO_ROOT_DEFINITION(AnimObject);
62 NW_UT_RUNTIME_TYPEINFO_DEFINITION(BaseAnimEvaluator, AnimObject);
63 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimEvaluator , BaseAnimEvaluator);
64 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimBlender , AnimObject);
65 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimInterpolator , AnimBlender);
66 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimAdder , AnimBlender);
67 NW_UT_RUNTIME_TYPEINFO_DEFINITION(AnimOverrider , AnimBlender);
68
69 //! 汎用アニメーション評価で使用する定数です。
70 const int BaseAnimEvaluator::NotFoundIndex = -1;
71
72 namespace {
73
74 /*!--------------------------------------------------------------------------*
75 @brief タイプに対応するアニメーションのブレンドオペレーションを取得します。
76 *---------------------------------------------------------------------------*/
77 anim::AnimBlendOp*
GetAnimBlendOpByType(int blendOpType)78 GetAnimBlendOpByType(int blendOpType)
79 {
80 static anim::AnimBlendOpBool blendOpBool;
81 static anim::AnimBlendOpInt blendOpInt;
82 static anim::AnimBlendOpFloat blendOpFloat;
83 static anim::AnimBlendOpVector2 blendOpVector2;
84 static anim::AnimBlendOpVector3 blendOpVector3;
85 static anim::AnimBlendOpRgbaColor blendOpRgbaColor;
86 static anim::AnimBlendOpTexture blendOpTexture;
87
88 static TransformAnimBlendOpStandard blendOpTransform;
89 static TransformAnimBlendOpAccScale blendOpTransformAccScale;
90 static TransformAnimBlendOpQuat blendOpTransformQuat;
91 static TransformAnimBlendOpAccScaleQuat blendOpTransformAccScaleQuat;
92
93 switch (blendOpType)
94 {
95 case anim::ResAnimGroup::BLENDOP_BOOL:
96 return &blendOpBool;
97 case anim::ResAnimGroup::BLENDOP_INT:
98 return &blendOpInt;
99 case anim::ResAnimGroup::BLENDOP_FLOAT:
100 return &blendOpFloat;
101 case anim::ResAnimGroup::BLENDOP_VECTOR2:
102 return &blendOpVector2;
103 case anim::ResAnimGroup::BLENDOP_VECTOR3:
104 return &blendOpVector3;
105 case anim::ResAnimGroup::BLENDOP_RGBA_COLOR:
106 return &blendOpRgbaColor;
107 case anim::ResAnimGroup::BLENDOP_TEXTURE:
108 return &blendOpTexture;
109
110 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM:
111 return &blendOpTransform;
112 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM_ACCURATE_SCALE:
113 return &blendOpTransformAccScale;
114 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM_QUAT:
115 return &blendOpTransformQuat;
116 case anim::ResAnimGroup::BLENDOP_CALCULATED_TRANSFORM_ACCURATE_SCALE_QUAT:
117 return &blendOpTransformAccScaleQuat;
118
119 default:
120 return NULL;
121 }
122 }
123
124 } // namespace
125
126 //----------------------------------------------------------
AnimGroup(anim::ResAnimGroup resAnimGroup,SceneNode * sceneNode,os::IAllocator * allocator)127 AnimGroup::AnimGroup(
128 anim::ResAnimGroup resAnimGroup,
129 SceneNode* sceneNode,
130 os::IAllocator* allocator)
131 : GfxObject(allocator),
132 m_ResAnimGroup(resAnimGroup),
133 m_SceneNode(sceneNode),
134 m_PreEvaluateCallback(NULL),
135 m_FullBakedAnimEnabled(false)
136 {
137 }
138
139 //----------------------------------------------------------
140 void
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,const anim::ResAnimGroup resAnimGroup,bool useOriginalValue)141 AnimGroup::GetMemorySizeForInitialize(
142 os::MemorySizeCalculator* pSize,
143 const anim::ResAnimGroup resAnimGroup,
144 bool useOriginalValue)
145 {
146 const int blendOpCount = resAnimGroup.GetBlendOperationsCount();
147 const int memberCount = resAnimGroup.GetMemberInfoSetCount();
148
149 os::MemorySizeCalculator& size = *pSize;
150
151 size += sizeof(anim::AnimBlendOp*) * blendOpCount;
152 size += sizeof(int) * memberCount;
153 size += sizeof(void*) * memberCount;
154 size += sizeof(void*) * memberCount;
155
156 if (useOriginalValue)
157 {
158 size += sizeof(void*) * memberCount;
159 }
160 }
161
162 //----------------------------------------------------------
Initialize(bool useOriginalValue)163 Result AnimGroup::Initialize(bool useOriginalValue)
164 {
165 Result result = INITIALIZE_RESULT_OK;
166
167 {
168 const int blendOpCount = m_ResAnimGroup.GetBlendOperationsCount();
169 NW_ASSERT(blendOpCount > 0);
170
171 void* memory = GetAllocator().Alloc(sizeof(anim::AnimBlendOp*) * blendOpCount);
172
173 if (memory == NULL)
174 {
175 result |= Result::MASK_FAIL_BIT;
176 }
177 NW_ENSURE_AND_RETURN(result);
178
179 m_BlendOperations = ut::MoveArray<anim::AnimBlendOp*>(memory, blendOpCount, &GetAllocator());
180 for (int blendOpIdx = 0; blendOpIdx < blendOpCount; ++blendOpIdx)
181 {
182 const int blendOpType = m_ResAnimGroup.GetBlendOperations(blendOpIdx);
183 m_BlendOperations.PushBackFast(GetAnimBlendOpByType(blendOpType));
184 }
185 }
186
187 const int memberCount = GetMemberCount();
188 NW_ASSERT(memberCount > 0);
189
190 {
191 void* memory = GetAllocator().Alloc(sizeof(int) * memberCount);
192 if (memory == NULL)
193 {
194 result |= Result::MASK_FAIL_BIT;
195 }
196 NW_ENSURE_AND_RETURN(result);
197
198 m_TargetObjectIndicies = ut::MoveArray<int>(memory, memberCount, &GetAllocator());
199 m_TargetObjectIndicies.Resize(memberCount);
200 }
201
202 {
203 void* memory = GetAllocator().Alloc(sizeof(void*) * memberCount);
204 if (memory == NULL)
205 {
206 result |= Result::MASK_FAIL_BIT;
207 }
208 NW_ENSURE_AND_RETURN(result);
209
210 m_TargetObjects = ut::MoveArray<void*>(memory, memberCount, &GetAllocator());
211 m_TargetObjects.Resize(memberCount);
212 }
213
214 {
215 void* memory = GetAllocator().Alloc(sizeof(void*) * memberCount);
216 if (memory == NULL)
217 {
218 result |= Result::MASK_FAIL_BIT;
219 }
220 NW_ENSURE_AND_RETURN(result);
221
222 m_TargetPtrs = ut::MoveArray<void*>(memory, memberCount, &GetAllocator());
223 m_TargetPtrs.Resize(memberCount);
224 }
225
226 if (useOriginalValue)
227 {
228 void* memory = GetAllocator().Alloc(sizeof(void*) * memberCount);
229 if (memory == NULL)
230 {
231 result |= Result::MASK_FAIL_BIT;
232 }
233 NW_ENSURE_AND_RETURN(result);
234
235 m_OriginalValues = ut::MoveArray<const void*>(memory, memberCount, &GetAllocator());
236 m_OriginalValues.Resize(memberCount);
237 }
238
239 return result;
240 }
241
242 //----------------------------------------------------------
243 void
Reset()244 AnimGroup::Reset()
245 {
246 if (!this->HasOriginalValue())
247 {
248 return;
249 }
250
251 for ( int memberIdx = 0 ; memberIdx < this->GetMemberCount() ; ++memberIdx )
252 {
253 const ResAnimGroupMember resAnimGroupMember = this->GetResAnimGroupMember(memberIdx);
254 resAnimGroupMember.SetValueForType(
255 this->GetTargetObject(memberIdx),
256 this->GetOriginalValue(memberIdx));
257 }
258 }
259
260 //----------------------------------------------------------
261 Result
TryBind(AnimGroup * animGroup)262 BaseAnimEvaluator::TryBind(AnimGroup* animGroup)
263 {
264 NW_NULL_ASSERT(animGroup);
265 NW_ASSERT(std::strcmp(m_AnimData.GetTargetAnimGroupName(), animGroup->GetName()) == 0);
266 NW_ASSERT(m_AnimGroup == NULL);
267
268 const int memberCount = animGroup->GetMemberCount();
269 bool resultResize = m_BindIndexTable.Resize(memberCount);
270 NW_ASSERTMSG(resultResize,
271 "Member count exceeded upper limit. Increase AnimEvaluator::Builder::MaxMembers.");
272
273 const int animMemberCount = m_AnimData.GetMemberAnimSetCount();
274 bool resultReverseResize = m_ReverseBindIndexTable.Resize(animMemberCount);
275 NW_ASSERTMSG(resultReverseResize,
276 "Animation member count exceeded upper limit. Increase AnimEvaluator::Builder::MaxAnimMembers.");
277
278 NW_ASSERTMSG(animGroup->GetFullBakedAnimEnabled() == m_AnimData.IsFullBakedAnim(),
279 "To use full baked animation, call SkeletalModel::SetFullBakedAnimEnabled(true) before Bind.");
280
281 int boundAnimCount = 0;
282 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
283 {
284 // 見つからなかったときのインデックスで埋める
285 m_BindIndexTable[memberIdx] = NotFoundIndex;
286 }
287
288 for (int animIdx = 0; animIdx < animMemberCount; ++animIdx)
289 {
290 anim::ResMemberAnim member = m_AnimData.GetMemberAnimSet(animIdx);
291 const int bindTargetIdx = animGroup->GetResAnimGroupMemberIndex(member.GetPath());
292
293 // 辞書引きで見つからなかったときは、モデルに対象が存在しない
294 if (bindTargetIdx == -1)
295 {
296 m_ReverseBindIndexTable[animIdx] = NotFoundIndex;
297 continue;
298 }
299
300 m_BindIndexTable[bindTargetIdx] = animIdx;
301 m_ReverseBindIndexTable[animIdx] = bindTargetIdx;
302 ++boundAnimCount;
303
304 //HACK
305 anim::ResAnimGroupMember resAnimGroupMember =
306 animGroup->GetResAnimGroupMember(bindTargetIdx);
307 ClearMaterialHash(resAnimGroupMember);
308 }
309
310 m_AnimGroup = animGroup;
311
312 // すべてのメンバアニメーションがバインドされました。
313 if (boundAnimCount == m_AnimData.GetMemberAnimSetCount())
314 {
315 return Result(BIND_RESULT_OK);
316 }
317
318 // バインドされたメンバアニメーションが無かったので失敗とします。
319 if (boundAnimCount == 0)
320 {
321 return Result(BIND_RESULT_NO_MEMBER_BOUND | Result::MASK_FAIL_BIT);
322 }
323
324 // 上のどちらでもない場合は、バインドには成功したが
325 // すべてのメンバアニメがバインドされなかったことを通知します。
326 return Result(BIND_RESULT_NOT_ALL_ANIM_MEMBER_BOUND);
327 }
328
329 //----------------------------------------------------------
330 void
ResetMember(int memberIdx)331 BaseAnimEvaluator::ResetMember(int memberIdx)
332 {
333 NW_NULL_ASSERT(m_AnimGroup);
334
335 if (!m_AnimGroup->HasOriginalValue())
336 {
337 return;
338 }
339
340 anim::ResGraphicsAnimGroup data = m_AnimGroup->GetResGraphicsAnimGroup();
341 NW_ASSERT(data.IsValid());
342
343 const ResAnimGroupMember resAnimGroupMember = m_AnimGroup->GetResAnimGroupMember(memberIdx);
344 resAnimGroupMember.SetValueForType(
345 m_AnimGroup->GetTargetObject(memberIdx),
346 m_AnimGroup->GetOriginalValue(memberIdx));
347
348 m_IsCacheDirty = true;
349 }
350
351 //----------------------------------------------------------
352 int
GetCacheBufferSizeNeeded() const353 AnimEvaluator::GetCacheBufferSizeNeeded() const
354 {
355 return GetCacheBufferSizeNeeded(m_AnimData);
356 }
357
358 //----------------------------------------------------------
359 int
GetCacheBufferSizeNeeded(const anim::ResAnim & animData)360 AnimEvaluator::GetCacheBufferSizeNeeded(const anim::ResAnim& animData)
361 {
362 const int headBytes = anim::AnimResult().GetOffsetToValueBuffer();
363 int size = 0;
364
365 const int memberAnimCount = animData.GetMemberAnimSetCount();
366 for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx)
367 {
368 const anim::ResMemberAnim memberAnim = animData.GetMemberAnimSet(animIdx);
369 const int primBytes = memberAnim.GetPrimitiveSize();
370 size += ut::RoundUp(headBytes + primBytes, sizeof(bit32));
371 }
372 return size;
373 }
374
375 //----------------------------------------------------------
376 void
SetCacheBufferPointers()377 AnimEvaluator::SetCacheBufferPointers()
378 {
379 const int headBytes = anim::AnimResult().GetOffsetToValueBuffer();
380 u8* cachePtr = reinterpret_cast<u8*>(m_CacheBuf);
381 const int memberAnimCount = m_AnimData.GetMemberAnimSetCount();
382 for (int animIdx = 0; animIdx < memberAnimCount; ++animIdx)
383 {
384 m_CachePtrs[animIdx] = reinterpret_cast<anim::AnimResult*>(cachePtr);
385 const anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
386 const int primBytes = memberAnim.GetPrimitiveSize();
387 cachePtr += ut::RoundUp(headBytes + primBytes, sizeof(bit32));
388 }
389 }
390
391 //----------------------------------------------------------
AnimEvaluator(os::IAllocator * allocator)392 AnimEvaluator::AnimEvaluator(
393 os::IAllocator* allocator)
394 : BaseAnimEvaluator(allocator, ANIMTYPE_SIMPLE),
395 m_CacheBuf(NULL)
396 {
397 }
398
399 //----------------------------------------------------------
400 void
GetMemorySizeForInitialize(os::MemorySizeCalculator * pSize,const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)401 AnimEvaluator::GetMemorySizeForInitialize(
402 os::MemorySizeCalculator* pSize,
403 const nw::anim::ResAnim& animData,
404 const int maxMembers,
405 const int maxAnimMembers,
406 bool allocCache)
407 {
408 os::MemorySizeCalculator& size = *pSize;
409
410 BaseAnimEvaluator::GetMemorySizeForInitialize(pSize, maxMembers, maxAnimMembers);
411 size += sizeof(anim::AnimResult*) * maxAnimMembers;
412
413 if (allocCache)
414 {
415 size += AnimEvaluator::GetCacheBufferSizeNeeded(animData);
416 }
417 }
418
419 //----------------------------------------------------------
Initialize(const nw::anim::ResAnim & animData,const int maxMembers,const int maxAnimMembers,bool allocCache)420 Result AnimEvaluator::Initialize(
421 const nw::anim::ResAnim& animData,
422 const int maxMembers,
423 const int maxAnimMembers,
424 bool allocCache)
425 {
426 // 親クラスの初期化を通す
427 Result result = BaseAnimEvaluator::Initialize(animData, maxMembers, maxAnimMembers);
428 NW_ENSURE_AND_RETURN(result);
429
430 void* memory = GetAllocator().Alloc(sizeof(anim::AnimResult*) * maxAnimMembers);
431 if (memory == NULL)
432 {
433 result |= Result::MASK_FAIL_BIT;
434 }
435 NW_ENSURE_AND_RETURN(result);
436
437 m_CachePtrs = ut::MoveArray<anim::AnimResult*>(memory, maxAnimMembers, &GetAllocator());
438 m_CachePtrs.Resize(animData.GetMemberAnimSetCount());
439
440 if (allocCache)
441 {
442 // サイズ0でのAllocを回避する
443 // CreateEmpty~Anim()などを使用した場合に起こりうる
444 if (animData.GetMemberAnimSetCount() != 0)
445 {
446 m_CacheBuf = GetAllocator().Alloc(GetCacheBufferSizeNeeded());
447 if (m_CacheBuf == NULL)
448 {
449 result |= Result::MASK_FAIL_BIT;
450 }
451 NW_ENSURE_AND_RETURN(result);
452
453 SetCacheBufferPointers();
454 }
455 }
456
457 return result;
458 }
459
460 //----------------------------------------------------------
461 const anim::AnimResult*
GetResult(void * target,int memberIdx) const462 AnimEvaluator::GetResult(
463 void* target,
464 int memberIdx
465 ) const
466 {
467 //-----------------------------------------------------------------
468 // メンバに関連付けられたアニメーションが存在しない場合は
469 // target を変更せずに NULL を返す
470 if (!HasMemberAnim(memberIdx))
471 {
472 return NULL;
473 }
474
475 //-----------------------------------------------------------------
476 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
477 const int animIdx = m_BindIndexTable[memberIdx];
478 if (m_CacheBuf != NULL && !m_IsCacheDirty)
479 {
480 //-----------------------------------------------------------------
481 // キャッシュがあればキャッシュの値を返す
482 if (blendOp != NULL)
483 {
484 return m_CachePtrs[animIdx];
485 }
486 else
487 {
488 anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
489 memberAnim.ApplyCacheForType(target, m_CachePtrs[animIdx]);
490 // ブレンドオペレーションがない場合、返り値は使用されないが
491 // ブレンダに評価したことを伝えるために target を返す
492 return reinterpret_cast<anim::AnimResult*>(target);
493 }
494 }
495 else
496 {
497 //-----------------------------------------------------------------
498 // アニメーションカーブを評価して対象に書き込む
499 anim::ResMemberAnim memberAnim = m_AnimData.GetMemberAnimSet(animIdx);
500 const void* originalValue = m_AnimGroup->HasOriginalValue()
501 ? m_AnimGroup->GetOriginalValue(memberIdx)
502 : NULL;
503
504 if (blendOp != NULL)
505 {
506 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
507 bit32 flags = memberAnim.EvaluateResultForType(
508 result->GetValueBuffer(), result->GetFlags(),
509 m_AnimFrameController.GetFrame(), originalValue);
510 result->SetFlags(flags);
511 return result;
512 }
513 else
514 {
515 memberAnim.EvaluateResultForType(
516 target, 0, m_AnimFrameController.GetFrame(),
517 originalValue);
518
519 // ブレンドオペレーションがない場合、返り値は使用されないが
520 // ブレンダに評価したことを伝えるために target を返す
521 return reinterpret_cast<anim::AnimResult*>(target);
522 }
523 }
524 }
525
526 //----------------------------------------------------------
527 void
UpdateCacheNonVirtual()528 AnimEvaluator::UpdateCacheNonVirtual()
529 {
530 if (m_CacheBuf != NULL && m_IsCacheDirty)
531 {
532 int animCount = m_AnimData.GetMemberAnimSetCount();
533 for (int animIdx = 0; animIdx < animCount; ++animIdx)
534 {
535 anim::AnimResult* result = m_CachePtrs[animIdx];
536 result->ResetFlags();
537
538 // バインドされたメンバーがモデルに存在しない場合もあるのでチェック
539 const int memberIdx = m_ReverseBindIndexTable[animIdx];
540 if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
541 {
542 continue;
543 }
544
545 this->GetResult(result, memberIdx);
546 }
547 m_IsCacheDirty = false;
548 }
549 }
550
551 //----------------------------------------------------------
552 const anim::AnimResult*
GetResult(void * target,int memberIdx) const553 AnimInterpolator::GetResult(
554 void* target,
555 int memberIdx
556 ) const
557 {
558 //----------------------------------------------------------
559 // ブレンドオペレーションがない場合および
560 // ブレンドオペレーションにブレンド処理がない場合は上書き処理
561 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
562 if (blendOp == NULL || !blendOp->HasBlend())
563 {
564 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
565 {
566 if (m_AnimObjects[animIdx] == NULL)
567 {
568 continue;
569 }
570 const anim::AnimResult* childResult =
571 m_AnimObjects[animIdx]->GetResult(target, memberIdx);
572 if (childResult != NULL)
573 {
574 return childResult;
575 }
576 }
577 return NULL;
578 }
579
580 if (m_IsOldMethod)
581 {
582 // TODO: こちらのブロックを整理。
583
584 //----------------------------------------------------------
585 // 有効な子アニメーションの重みの合計を求める
586 float weightSum = 0.0f;
587 const AnimObject* lastAnimObj = NULL;
588 int validAnimCount = 0;
589 for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
590 {
591 if (m_AnimObjects[animIdx] == NULL)
592 {
593 continue;
594 }
595 const float weight = m_Weights[animIdx];
596 if (!AnimWeightNearlyEqualZero(weight))
597 {
598 if (m_AnimObjects[animIdx]->HasMemberAnim(memberIdx))
599 {
600 weightSum += weight;
601 lastAnimObj = m_AnimObjects[animIdx];
602 ++validAnimCount;
603 }
604 }
605 }
606
607 if (validAnimCount == 0)
608 {
609 // 有効な子アニメーションが存在しない場合は
610 // target を変更せずに NULL を返す
611 return NULL;
612 }
613 else if (validAnimCount == 1)
614 {
615 // 有効な子アニメーションが 1 つだけの場合は
616 // そのアニメーションの結果を返す
617 return lastAnimObj->GetResult(target, memberIdx);
618 }
619
620 // 重みの合計が 1.0 でない場合は正規化スケールを計算
621 const float weightNormalizeScale = GetAnimWeightNormalizeScale(weightSum);
622
623 //----------------------------------------------------------
624 // 補間は操作空間があればそこで行われるべきなので
625 // target の CONVERTED フラグを退避してからオンに
626 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
627 const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
628 result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
629
630 //----------------------------------------------------------
631 // すべての子アニメーションについてループ
632 anim::AnimResult workResult;
633 bool written = false;
634 float compWeights[anim::AnimResult::MAX_COMPONENTS];
635 //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
636 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
637 {
638 if (m_AnimObjects[animIdx] == NULL)
639 {
640 continue;
641 }
642 const float childWeight = m_Weights[animIdx] * weightNormalizeScale;
643 if (!AnimWeightNearlyEqualZero(childWeight))
644 {
645 // 退避した CONVERTED フラグを work に反映
646 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
647 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
648 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
649
650 // 評価
651 const anim::AnimResult* childResult =
652 m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
653 if (childResult != NULL)
654 {
655 written = true;
656 if (!blendOp->Blend(result, compWeights, childResult, &childWeight))
657 {
658 break;
659 }
660 }
661 }
662 }
663
664 //----------------------------------------------------------
665 // target の CONVERTED フラグを復元
666 if (!convertedBak)
667 {
668 result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
669 }
670
671 if (!written) // 有効な子アニメーションなし
672 {
673 return NULL;
674 }
675
676 //----------------------------------------------------------
677 // ブレンド後の処理があれば実行
678 if (!convertedBak && blendOp->HasPostBlend())
679 {
680 blendOp->PostBlend(result, compWeights);
681 }
682 return result;
683 }
684 else
685 {
686 bool isValidAnim = false;
687 for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
688 {
689 if (m_AnimObjects[animIdx] && m_AnimObjects[animIdx]->HasMemberAnim(memberIdx))
690 {
691 isValidAnim = true;
692 break;
693 }
694 }
695
696 // 有効な子アニメーションが存在しない場合は
697 // target を変更せずに NULL を返す
698 if (!isValidAnim)
699 {
700 return NULL;
701 }
702
703 // アニメーション重みの正規化を必要なら行います。
704 if (m_IsWeightDirty && m_IsWeightNormalizationEnabled)
705 {
706 NormalizeWeight();
707 }
708
709 //----------------------------------------------------------
710 // 補間は操作空間があればそこで行われるべきなので
711 // target の CONVERTED フラグを退避してからオンに
712 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
713 const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
714 result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
715
716 //----------------------------------------------------------
717 // すべての子アニメーションについてループ
718 anim::AnimResult workResult;
719 float compWeights[anim::AnimResult::MAX_COMPONENTS];
720 //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
721 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
722 {
723 const float childWeight = m_NormalizedWeights[animIdx];
724 if (!AnimWeightNearlyEqualZero(childWeight))
725 {
726 // 退避した CONVERTED フラグを work に反映
727 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
728 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
729 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
730
731 // 評価
732 const anim::AnimResult* childResult = NULL;
733 if (m_AnimObjects[animIdx] != NULL)
734 {
735 childResult = m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
736 }
737
738 if (childResult == NULL)
739 {
740 NW_ASSERT(GetAnimGroup()->HasOriginalValue());
741 blendOp->ConvertToAnimResult(
742 &workResult,
743 GetAnimGroup()->GetOriginalValue(memberIdx));
744 childResult = &workResult;
745
746 NW_NULL_ASSERT(childResult);
747 }
748
749 if (!blendOp->Blend(result, compWeights, childResult, &childWeight))
750 {
751 break;
752 }
753
754 }
755 }
756
757 //----------------------------------------------------------
758 // target の CONVERTED フラグを復元
759 if (!convertedBak)
760 {
761 result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
762 }
763
764 //----------------------------------------------------------
765 // ブレンド後の処理があれば実行
766 if (!convertedBak && blendOp->HasPostBlend())
767 {
768 blendOp->PostBlend(result, compWeights);
769 }
770 return result;
771 }
772 }
773
774 //----------------------------------------------------------
775 const anim::AnimResult*
GetResult(void * target,int memberIdx) const776 AnimAdder::GetResult(
777 void* target,
778 int memberIdx
779 ) const
780 {
781 //----------------------------------------------------------
782 // ブレンドオペレーションがない場合および
783 // ブレンドオペレーションにブレンド処理がない場合は上書き処理
784 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
785 if (blendOp == NULL || !blendOp->HasBlend())
786 {
787 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
788 {
789 if (m_AnimObjects[animIdx] == NULL)
790 {
791 continue;
792 }
793 const anim::AnimResult* childResult =
794 m_AnimObjects[animIdx]->GetResult(target, memberIdx);
795 if (childResult != NULL)
796 {
797 return childResult;
798 }
799 }
800 return NULL;
801 }
802
803 //----------------------------------------------------------
804 // 補間は操作空間があればそこで行われるべきなので
805 // target の CONVERTED フラグを退避してからオンに
806 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
807 const bool convertedBak = result->IsEnabledFlags(anim::AnimResult::FLAG_CONVERTED);
808 result->EnableFlags(anim::AnimResult::FLAG_CONVERTED, true);
809
810 //----------------------------------------------------------
811 // すべての子アニメーションについてループ
812 anim::AnimResult workResult;
813 bool written = false;
814 //for (int animIdx = 0; animIdx < m_AnimObjects.Size(); ++animIdx)
815 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
816 {
817 if (m_AnimObjects[animIdx] == NULL)
818 {
819 continue;
820 }
821 const float childWeight = m_Weights[animIdx];
822 if (!AnimWeightNearlyEqualZero(childWeight))
823 {
824 // 退避した CONVERTED フラグを work に反映
825 // 子が CONVERTED を扱う Blender であれば CONVERTED なままの結果が返ってくることを期待
826 // 子が Evaluator の場合はフラグがオフで返ってくるが blendOp 内で変換されるので問題ない
827 workResult.EnableFlags(anim::AnimResult::FLAG_CONVERTED, convertedBak);
828
829 // 評価
830 const anim::AnimResult* childResult =
831 m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
832 if (childResult != NULL)
833 {
834 written = true;
835 if (!blendOp->Blend(result, NULL, childResult, &childWeight))
836 {
837 break;
838 }
839 }
840 }
841 }
842
843 //----------------------------------------------------------
844 // target の CONVERTED フラグを復元
845 if (!convertedBak)
846 {
847 result->DisableFlags(anim::AnimResult::FLAG_CONVERTED);
848 }
849
850 if (!written) // 有効な子アニメーションなし
851 {
852 return NULL;
853 }
854
855 //----------------------------------------------------------
856 // ブレンド後の処理があれば実行
857 if (!convertedBak && blendOp->HasPostBlend())
858 {
859 blendOp->PostBlend(result, NULL);
860 }
861 return result;
862 }
863
864 //----------------------------------------------------------
865 const anim::AnimResult*
GetResult(void * target,int memberIdx) const866 AnimOverrider::GetResult(
867 void* target,
868 int memberIdx
869 ) const
870 {
871 //----------------------------------------------------------
872 // ブレンドオペレーションがない場合および
873 // ブレンドオペレーションにブレンド処理がない場合は上書き処理
874 const anim::AnimBlendOp* blendOp = m_AnimGroup->GetBlendOperation(memberIdx);
875 if (blendOp == NULL || !blendOp->HasBlend())
876 {
877 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
878 {
879 if (m_AnimObjects[animIdx] == NULL)
880 {
881 continue;
882 }
883 const anim::AnimResult* childResult =
884 m_AnimObjects[animIdx]->GetResult(target, memberIdx);
885 if (childResult != NULL)
886 {
887 return childResult;
888 }
889 }
890 return NULL;
891 }
892
893 //----------------------------------------------------------
894 // すべての子アニメーションについてループ
895 anim::AnimResult* result = reinterpret_cast<anim::AnimResult*>(target);
896 anim::AnimResult workResult;
897 bool written = false;
898 for (int animIdx = m_AnimObjects.Size() - 1; animIdx >= 0; --animIdx)
899 {
900 if (m_AnimObjects[animIdx] == NULL)
901 {
902 continue;
903 }
904 const anim::AnimResult* childResult =
905 m_AnimObjects[animIdx]->GetResult(&workResult, memberIdx);
906 if (childResult != NULL)
907 {
908 written = true;
909 if (blendOp->Override(result, childResult)) // 全成分を上書きしたら true が返る
910 {
911 return result;
912 }
913 }
914 }
915
916 if (!written) // 有効な子アニメーションなし
917 {
918 return NULL;
919 }
920
921 return result;
922 }
923
924 //----------------------------------------------------------
925 void
Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing)926 AnimBinding::Evaluate(anim::ResGraphicsAnimGroup::EvaluationTiming timing)
927 {
928 for (int animGroupIdx = 0; animGroupIdx < m_AnimGroups.Size(); ++animGroupIdx)
929 {
930 AnimGroup* animGroup = m_AnimGroups[animGroupIdx];
931
932 // アニメーションの有無と評価タイミングをチェック
933 if (animGroup == NULL || animGroup->GetResGraphicsAnimGroup().GetEvaluationTiming() != timing)
934 {
935 continue;
936 }
937
938 for (int animObjectIdx = 0; animObjectIdx < m_AnimObjectCountPerGroup; ++animObjectIdx)
939 {
940 const int index = animGroupIdx * m_AnimObjectCountPerGroup + animObjectIdx;
941 AnimObject* animObj = m_AnimObjects[index];
942 if (animObj == NULL)
943 {
944 continue;
945 }
946
947 // 高速化のため、ブレンダの有無・Transformかどうかで分岐
948 switch (animObj->GetAnimType())
949 {
950 case AnimObject::ANIMTYPE_SIMPLE:
951 static_cast<AnimEvaluator*>(animObj)->UpdateCacheNonVirtual();
952 EvaluateSimple(animGroup, static_cast<AnimEvaluator*>(animObj));
953 break;
954 case AnimObject::ANIMTYPE_TRANSFORM_SIMPLE:
955 static_cast<TransformAnimEvaluator*>(animObj)->UpdateCacheNonVirtual();
956 EvaluateTransformSimple(animGroup, static_cast<TransformAnimEvaluator*>(animObj));
957 break;
958 default:
959 // アニメーション評価結果の内部キャッシュが古ければ更新
960 animObj->UpdateCache();
961 EvaluateBlender(animGroup, animObj);
962 }
963 }
964 }
965 }
966
967 //----------------------------------------------------------
EvaluateSimple(AnimGroup * animGroup,AnimEvaluator * evaluator)968 void AnimBinding::EvaluateSimple(AnimGroup* animGroup, AnimEvaluator* evaluator)
969 {
970 NW_ASSERT(!(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM));
971
972 // 汎用アニメーションを評価
973 int lastTargetObjIdx = -1;
974 bool targetObjSkipFlag = false;
975 int animCount = evaluator->GetAnimData().GetMemberAnimSetCount();
976 for (int animIdx = 0; animIdx < animCount; ++animIdx)
977 {
978 int memberIdx = evaluator->ReverseBindIndexTable()[animIdx];
979 if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
980 {
981 continue;
982 }
983 EvaluateMember(animGroup, memberIdx, evaluator, lastTargetObjIdx, targetObjSkipFlag);
984 }
985 }
986
987 //----------------------------------------------------------
EvaluateTransformSimple(AnimGroup * animGroup,TransformAnimEvaluator * evaluator)988 void AnimBinding::EvaluateTransformSimple(AnimGroup* animGroup, TransformAnimEvaluator* evaluator)
989 {
990 NW_ASSERT(animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM);
991
992 // トランスフォームアニメーションを評価
993 int animCount = evaluator->GetAnimData().GetMemberAnimSetCount();
994 for (int animIdx = 0; animIdx < animCount; ++animIdx)
995 {
996 int memberIdx = evaluator->ReverseBindIndexTable()[animIdx];
997 if (memberIdx == BaseAnimEvaluator::NotFoundIndex)
998 {
999 continue;
1000 }
1001 EvaluateTransformMemberFast(animGroup, memberIdx, evaluator);
1002 }
1003 }
1004
1005 //----------------------------------------------------------
EvaluateBlender(AnimGroup * animGroup,AnimObject * animObj)1006 void AnimBinding::EvaluateBlender(AnimGroup* animGroup, AnimObject* animObj)
1007 {
1008 if (animGroup->GetResAnimGroup().GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM)
1009 {
1010 // トランスフォームアニメーションを評価
1011 int memberCount = animGroup->GetMemberCount();
1012 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1013 {
1014 EvaluateTransformMember(animGroup, memberIdx, animObj);
1015 }
1016 }
1017 else
1018 {
1019 // 汎用アニメーションを評価
1020 int lastTargetObjIdx = -1;
1021 bool targetObjSkipFlag = false;
1022 int memberCount = animGroup->GetMemberCount();
1023 for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
1024 {
1025 EvaluateMember(animGroup, memberIdx, animObj, lastTargetObjIdx, targetObjSkipFlag);
1026 }
1027 }
1028 }
1029
1030 //----------------------------------------------------------
EvaluateTransformMember(AnimGroup * animGroup,int memberIdx,AnimObject * animObj)1031 void AnimBinding::EvaluateTransformMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj)
1032 {
1033 AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
1034
1035 // 評価前コールバックの呼び出し
1036 if (preEvaluateCallback != NULL)
1037 {
1038 const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
1039 if (!preEvaluateCallback(animGroup, targetObjIdx))
1040 {
1041 return;
1042 }
1043 }
1044
1045 // 評価
1046 CalculatedTransform* target = static_cast<CalculatedTransform*>(animGroup->GetTargetPtr(memberIdx));
1047 animObj->GetResult(target, memberIdx);
1048
1049 // Setter経由で設定する必要はないので、Setterは呼び出さない
1050 // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する
1051 }
1052
1053 //----------------------------------------------------------
EvaluateTransformMemberFast(AnimGroup * animGroup,int memberIdx,TransformAnimEvaluator * evaluator)1054 void AnimBinding::EvaluateTransformMemberFast(AnimGroup* animGroup, int memberIdx, TransformAnimEvaluator* evaluator)
1055 {
1056 AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
1057
1058 // 評価前コールバックの呼び出し
1059 if (preEvaluateCallback != NULL)
1060 {
1061 const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
1062 if (!preEvaluateCallback(animGroup, targetObjIdx))
1063 {
1064 return;
1065 }
1066 }
1067
1068 // 評価
1069 CalculatedTransform* target = static_cast<CalculatedTransform*>(animGroup->GetTargetPtr(memberIdx));
1070 evaluator->GetResultFast(target, memberIdx);
1071
1072 // Setter経由で設定する必要はないので、Setterは呼び出さない
1073 // Setter内部で回転行列の生成を行うので、呼び出すとパフォーマンスにも大きく影響する
1074 }
1075
1076 //----------------------------------------------------------
EvaluateMember(AnimGroup * animGroup,int memberIdx,AnimObject * animObj,int & lastTargetObjIdx,bool & targetObjSkipFlag)1077 void AnimBinding::EvaluateMember(AnimGroup* animGroup, int memberIdx, AnimObject* animObj, int& lastTargetObjIdx, bool& targetObjSkipFlag)
1078 {
1079 AnimGroup::PreEvaluateCallback preEvaluateCallback = animGroup->GetPreEvaluateCallback();
1080
1081 // 評価前コールバックの呼び出し
1082 if (preEvaluateCallback != NULL)
1083 {
1084 const int targetObjIdx = animGroup->GetTargetObjectIndex(memberIdx);
1085 if (targetObjIdx != lastTargetObjIdx)
1086 {
1087 // 高速化のため前回と対象オブジェクトが異なる場合だけ評価前コールバックを呼ぶ
1088 targetObjSkipFlag = !preEvaluateCallback(animGroup, targetObjIdx);
1089 lastTargetObjIdx = targetObjIdx;
1090 }
1091 if (targetObjSkipFlag)
1092 {
1093 return;
1094 }
1095 }
1096
1097 // 評価
1098 anim::ResAnimGroupMember member = animGroup->GetResAnimGroupMember(memberIdx);
1099 void* target = NULL;
1100 ut::Offset texturePatternTarget;
1101
1102 if (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TEXTURE_MAPPER &&
1103 member.GetMemberType() == anim::ResTextureMapperMember::MEMBER_TYPE_TEXTURE)
1104 {
1105 // テクスチャパターンアニメーションは、targetを上書きせずにSetterのみ呼び出す
1106 //
1107 // マテリアルのバッファが有効な場合は、targetは動的に確保されたReferenceTextureを指す
1108 // それを上書きすると、解放時にアロケータで確保されていないポインタを解放しようとしてクラッシュする
1109 target = &texturePatternTarget;
1110 }
1111 else
1112 {
1113 target = animGroup->GetTargetPtr(memberIdx);
1114 }
1115
1116 const anim::AnimBlendOp* blendOp = animGroup->GetBlendOperation(memberIdx);
1117 const anim::AnimResult* resultPtr = NULL;
1118 if (blendOp != NULL)
1119 {
1120 // ブレンドオペレーションがある場合は
1121 // AnimResult オブジェクト経由でターゲットに書き込む
1122 anim::AnimResult result;
1123 resultPtr = animObj->GetResult(&result, memberIdx);
1124 if (resultPtr != NULL)
1125 {
1126 blendOp->Apply(target, resultPtr); // VALID フラグがオンの成分のみ書き込み
1127 }
1128 }
1129 else
1130 {
1131 // ブレンドオペレーションがない場合はターゲットを直接上書き
1132 resultPtr = animObj->GetResult(target, memberIdx);
1133 }
1134
1135 // transformのメンバの場合は、setterを呼びださない。
1136 bool isTransformMember = (
1137 (member.GetObjectType() == anim::ResAnimGroupMember::OBJECT_TYPE_TRANSFORM) &&
1138 (member.GetMemberType() == anim::ResTransformMember::MEMBER_TYPE_TRANSFORM)
1139 );
1140
1141 if (!isTransformMember && resultPtr)
1142 {
1143 // メモリ書き込み以外の処理が必要なメンバのためにSetterを呼び出す
1144 // (コマンドキャッシュの更新などが行われる)
1145 //
1146 // Setterがtargetも書き換えるので2回書き込んでいる。
1147 // 1回にしたいが、VALIDフラグがオフの成分があるとtargetの値の取得が必要。
1148 // するとバッファの確保 -> Get -> Apply -> Setとなり、かえって遅くなりそう。
1149 void* object = animGroup->GetTargetObject(memberIdx);
1150 member.SetValueForType(object, target);
1151 }
1152 }
1153
1154 } // namespace gfx
1155 } // namespace nw
1156