1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     lyt_Animation.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: 19854 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/lyt/lyt_Common.h>
19 #include <nw/lyt/lyt_Pane.h>
20 #include <nw/lyt/lyt_Group.h>
21 #include <nw/lyt/lyt_Material.h>
22 #include <nw/lyt/lyt_Animation.h>
23 #include <nw/lyt/lyt_Layout.h>
24 #include <nw/lyt/lyt_ResourceAccessor.h>
25 #include <nw/lyt/lyt_Util.h>
26 
27 const f32 R_SAME_TOLERANCE = 1.0e-5F;
28 const f32 R_FRAME_TOLERANCE = 0.001F;
29 
30 namespace nw
31 {
32 namespace lyt
33 {
34 namespace
35 {
36 
37 /*---------------------------------------------------------------------------*
38   @brief f32 型の値を許容値付きで比較します。
39 
40   @param a 比較する値です。
41   @param b 比較する値です。
42   @param tolerance 許容値です。
43 
44   @return 2つの値の差の絶対値が許容値未満なら true を返します。
45  *---------------------------------------------------------------------------*/
46 inline bool
RIsSame(const f32 a,const f32 b,const f32 tolerance=R_SAME_TOLERANCE)47 RIsSame(
48     const f32 a,
49     const f32 b,
50     const f32 tolerance = R_SAME_TOLERANCE
51 )
52 {
53     f32 c = a - b;
54     return (-tolerance < c && c < tolerance);
55 }
56 
57 /*---------------------------------------------------------------------------*
58   @brief ステップ形式カーブの特定フレームでの値を取得します。
59 
60   @param frame 値を取得するフレームです。
61   @param keyArray ステップ形式キーの配列です。
62   @param keySize キー数です。
63 
64   @return 値です。
65  *---------------------------------------------------------------------------*/
66 u16
GetStepCurveValue(f32 frame,const res::StepKey * keyArray,u32 keySize)67 GetStepCurveValue(
68     f32 frame,
69     const res::StepKey* keyArray,
70     u32 keySize
71 )
72 {
73     NW_ASSERT(keySize > 0);
74 
75     if (keySize == 1 || frame <= keyArray[0].frame)
76     {
77         return keyArray[0].value;
78     }
79     else if (frame >= keyArray[keySize - 1].frame)
80     {
81         return keyArray[keySize - 1].value;
82     }
83 
84     int ikeyL = 0;
85     int ikeyR = (int)keySize - 1;
86     while (ikeyL != ikeyR - 1 && ikeyL != ikeyR)
87     {
88         int ikeyCenter = (ikeyL + ikeyR) / 2;
89         const res::StepKey& centerKey = keyArray[ikeyCenter];
90         if (frame < centerKey.frame)
91         {
92             ikeyR = ikeyCenter;
93         }
94         else
95         {
96             ikeyL = ikeyCenter;
97         }
98     }
99 
100     if (RIsSame(frame, keyArray[ikeyR].frame, R_FRAME_TOLERANCE))
101     {
102         return keyArray[ikeyR].value;
103     }
104     else
105     {
106         return keyArray[ikeyL].value;
107     }
108 }
109 
110 /*---------------------------------------------------------------------------*
111   @brief エルミート形式カーブの特定フレームでの値を取得します。
112 
113   @param frame 値を取得するフレームです。
114   @param keyArray エルミート形式キーの配列です。
115   @param keySize キー数です。
116 
117   @return 値です。
118  *---------------------------------------------------------------------------*/
119 f32
GetHermiteCurveValue(f32 frame,const res::HermiteKey * keyArray,u32 keySize)120 GetHermiteCurveValue(
121     f32 frame,
122     const res::HermiteKey*  keyArray,
123     u32 keySize
124 )
125 {
126     NW_ASSERT(keySize > 0);
127 
128     // outside of curve
129     if (keySize == 1 || frame <= keyArray[0].frame)
130     {
131         return keyArray[0].value;
132     }
133     else if (frame >= keyArray[keySize - 1].frame)
134     {
135         return keyArray[keySize - 1].value;
136     }
137 
138     // find 2 keys
139     u32 ikeyL = 0;
140     u32 ikeyR = keySize - 1;
141     while (ikeyL != ikeyR - 1 && ikeyL != ikeyR)
142     {
143         int ikeyCenter = (ikeyL + ikeyR) / 2;
144         if (frame <= keyArray[ikeyCenter].frame)
145         {
146             ikeyR = ikeyCenter;
147         }
148         else
149         {
150             ikeyL = ikeyCenter;
151         }
152     }
153 
154     // calculate hermite interpolation
155     const res::HermiteKey& key0 = keyArray[ikeyL];
156     const res::HermiteKey& key1 = keyArray[ikeyR];
157     if (RIsSame(frame, key1.frame, R_FRAME_TOLERANCE))
158     {
159         if (ikeyR < keySize - 1 &&
160             key1.frame == keyArray[ikeyR + 1].frame)
161         {
162             // 同一フレームに値の異なるキーがある場合
163             return keyArray[ikeyR + 1].value;
164         }
165         else
166         {
167             return key1.value;
168         }
169     }
170     f32 t1 = frame - key0.frame;
171     f32 t2 = 1.0F / (key1.frame - key0.frame);
172     f32 v0 = key0.value;
173     f32 v1 = key1.value;
174     f32 s0 = key0.slope;
175     f32 s1 = key1.slope;
176 
177     f32 t1t1t2 = t1 * t1 * t2;
178     f32 t1t1t2t2 = t1t1t2 * t2;
179     f32 t1t1t1t2t2 = t1 * t1t1t2t2;
180     f32 t1t1t1t2t2t2 = t1t1t1t2t2 * t2;
181 
182     return v0 * (2.0F * t1t1t1t2t2t2 - 3.0F * t1t1t2t2 + 1.0F)
183         + v1 * (-2.0F * t1t1t1t2t2t2 + 3.0F * t1t1t2t2)
184         + s0 * (t1t1t1t2t2 - 2.0F * t1t1t2 + t1)
185         + s1 * (t1t1t1t2t2 - t1t1t2);
186 }
187 
188 void
AnimatePaneSRT(Pane * pPane,const res::AnimationInfo * pAnimInfo,const u32 * animTargetOffsets,f32 frame)189 AnimatePaneSRT(
190     Pane* pPane,
191     const res::AnimationInfo* pAnimInfo,
192     const u32* animTargetOffsets,
193     f32 frame
194 )
195 {
196     for (int i = 0; i < pAnimInfo->num; ++i)
197     {
198         const res::AnimationTarget* pAnimTarget = internal::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
199 
200         NW_ASSERT(pAnimTarget->target < ANIMTARGET_PANE_MAX);
201         NW_ASSERT(pAnimTarget->curveType == ANIMCURVE_HERMITE);   // 現時点ではHERMITEのみ
202 
203         const res::HermiteKey* keys = internal::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
204         pPane->SetSRTElement(pAnimTarget->target, GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum));
205     }
206 }
207 
208 void
AnimateVisibility(Pane * pPane,const res::AnimationInfo * pAnimInfo,const u32 * animTargetOffsets,f32 frame)209 AnimateVisibility(
210     Pane* pPane,
211     const res::AnimationInfo* pAnimInfo,
212     const u32* animTargetOffsets,
213     f32 frame
214 )
215 {
216     for (int i = 0; i < pAnimInfo->num; ++i)
217     {
218         const res::AnimationTarget* pAnimTarget = internal::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
219 
220         NW_ASSERT(pAnimTarget->target < ANIMTARGET_PANE_MAX);
221         NW_ASSERT(pAnimTarget->curveType == ANIMCURVE_STEP);
222 
223         const res::StepKey* keys = internal::ConvertOffsToPtr<res::StepKey>(pAnimTarget, pAnimTarget->keysOffset);
224         pPane->SetVisible(0 != GetStepCurveValue(frame, keys, pAnimTarget->keyNum));
225     }
226 }
227 
228 void
AnimateVertexColor(Pane * pPane,const res::AnimationInfo * pAnimInfo,const u32 * animTargetOffsets,f32 frame)229 AnimateVertexColor(
230     Pane* pPane,
231     const res::AnimationInfo* pAnimInfo,
232     const u32* animTargetOffsets,
233     f32 frame
234 )
235 {
236     for (int i = 0; i < pAnimInfo->num; ++i)
237     {
238         const res::AnimationTarget* pAnimTarget = internal::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
239 
240         NW_ASSERT(pAnimTarget->target < ANIMTARGET_PANE_COLOR_MAX);
241         NW_ASSERT(pAnimTarget->curveType == ANIMCURVE_HERMITE);   // 現時点ではHERMITEのみ
242 
243         const res::HermiteKey* keys = internal::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
244         f32 value = GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum);
245         value += 0.5f;
246         u8 u8Val = static_cast<u8>(value);
247         pPane->SetColorElement(pAnimTarget->target, u8Val);
248     }
249 }
250 
251 void
AnimateMaterialColor(Material * pMaterial,const res::AnimationInfo * pAnimInfo,const u32 * animTargetOffsets,f32 frame)252 AnimateMaterialColor(
253     Material* pMaterial,
254     const res::AnimationInfo* pAnimInfo,
255     const u32* animTargetOffsets,
256     f32 frame
257 )
258 {
259     for (int i = 0; i < pAnimInfo->num; ++i)
260     {
261         const res::AnimationTarget* pAnimTarget = internal::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
262         NW_ASSERT(pAnimTarget->target < ANIMTARGET_MATCOLOR_MAX);
263         NW_ASSERT(pAnimTarget->curveType == ANIMCURVE_HERMITE);   // 現時点ではHERMITEのみ
264 
265         const res::HermiteKey* keys = internal::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
266         f32 value = GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum);
267         value += 0.5f;
268         u8 val = static_cast<u8>(ut::Min(ut::Max(value, 0.f), 255.f));
269         pMaterial->SetColorElement(pAnimTarget->target, val);
270     }
271 }
272 
273 void
AnimateTextureSRT(Material * pMaterial,const res::AnimationInfo * pAnimInfo,const u32 * animTargetOffsets,f32 frame)274 AnimateTextureSRT(
275     Material* pMaterial,
276     const res::AnimationInfo* pAnimInfo,
277     const u32* animTargetOffsets,
278     f32 frame
279 )
280 {
281     for (int i = 0; i < pAnimInfo->num; ++i)
282     {
283         const res::AnimationTarget* pAnimTarget = internal::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
284         NW_ASSERT(pAnimTarget->id < TexMapMax);
285         if (pAnimTarget->id < pMaterial->GetTexSRTCap())
286         {
287             NW_ASSERT(pAnimTarget->target < ANIMTARGET_TEXSRT_MAX);
288             NW_ASSERT(pAnimTarget->curveType == ANIMCURVE_HERMITE);   // 現時点ではHERMITEのみ
289 
290             const res::HermiteKey* keys = internal::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
291             pMaterial->SetTexSRTElement(pAnimTarget->id, pAnimTarget->target, GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum));
292         }
293     }
294 }
295 
296 void
AnimateTexturePattern(Material * pMaterial,const res::AnimationInfo * pAnimInfo,const u32 * animTargetOffsets,f32 frame,const TextureInfo * texInfos)297 AnimateTexturePattern(
298     Material* pMaterial,
299     const res::AnimationInfo* pAnimInfo,
300     const u32* animTargetOffsets,
301     f32 frame,
302     const TextureInfo* texInfos
303 )
304 {
305     for (int j = 0; j < pAnimInfo->num; ++j)
306     {
307         const res::AnimationTarget* pAnimTarget = internal::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[j]);
308 
309         if (pAnimTarget->id < pMaterial->GetTexMapNum())
310         {
311             NW_ASSERT(pAnimTarget->curveType == ANIMCURVE_STEP);              // 現時点ではSTEPのみ
312             NW_ASSERT(pAnimTarget->target == ANIMTARGET_TEXPATTURN_IMAGE);    // 現状ではimageのみ
313 
314             const res::StepKey* keys = internal::ConvertOffsToPtr<res::StepKey>(pAnimTarget, pAnimTarget->keysOffset);
315             const u16 fileIdx = GetStepCurveValue(frame, keys, pAnimTarget->keyNum);
316 
317             if (texInfos[fileIdx].IsValid())
318             {
319                 pMaterial->SetTexMap(pAnimTarget->id, texInfos[fileIdx]);
320             }
321         }
322     }
323 }
324 
325 inline bool
IsBindAnimation(Pane * pPane,AnimTransform * pAnimTrans)326 IsBindAnimation(
327     Pane* pPane,
328     AnimTransform* pAnimTrans
329 )
330 {
331 #if defined(NW_RELEASE)
332 
333     NW_UNUSED_VARIABLE(pPane)
334     NW_UNUSED_VARIABLE(pAnimTrans)
335 
336 #else
337 
338     if (pPane->FindAnimationLinkSelf(pAnimTrans))
339     {
340         NW_WARNING(false, "already bind animation.");
341         return true;
342     }
343 
344 #endif  // #if !defined(NW_RELEASE)
345 
346     return false;
347 }
348 
349 inline bool
IsBindAnimation(Material * pMaterial,AnimTransform * pAnimTrans)350 IsBindAnimation(
351     Material* pMaterial,
352     AnimTransform* pAnimTrans
353 )
354 {
355 #if defined(NW_RELEASE)
356 
357     NW_UNUSED_VARIABLE(pMaterial)
358     NW_UNUSED_VARIABLE(pAnimTrans)
359 
360 #else
361 
362     if (pMaterial->FindAnimationLink(pAnimTrans))
363     {
364         NW_WARNING(false, "already bind animation.");
365         return true;
366     }
367 
368 #endif  // #if !defined(NW_RELEASE)
369 
370     return false;
371 }
372 
373 } // namespace nw::lyt::{no-name}
374 
AnimTransform()375 AnimTransform::AnimTransform()
376 : m_pRes(0),
377   m_Frame(0)
378 {
379 }
380 
~AnimTransform()381 AnimTransform::~AnimTransform()
382 {
383 }
384 
385 u16
GetFrameSize() const386 AnimTransform::GetFrameSize() const
387 {
388     return m_pRes->frameSize;
389 }
390 
391 bool
IsLoopData() const392 AnimTransform::IsLoopData() const
393 {
394     return m_pRes->loop != 0;
395 }
396 
AnimTransformBasic()397 AnimTransformBasic::AnimTransformBasic()
398 : m_pTexAry(0),
399   m_pAnimLinkAry(0),
400   m_AnimLinkNum(0)
401 {
402 }
403 
~AnimTransformBasic()404 AnimTransformBasic::~AnimTransformBasic()
405 {
406     Layout::DeleteArray(m_pAnimLinkAry, m_AnimLinkNum);
407     Layout::DeletePrimArray(m_pTexAry);
408 }
409 
410 void
SetResource(const res::AnimationBlock * pRes,ResourceAccessor * pResAccessor)411 AnimTransformBasic::SetResource(
412     const res::AnimationBlock* pRes,
413     ResourceAccessor* pResAccessor
414 )
415 {
416     NW_NULL_ASSERT(pRes);
417     SetResource(pRes, pResAccessor, pRes->animContNum);
418 }
419 
420 void
SetResource(const res::AnimationBlock * pRes,ResourceAccessor * pResAccessor,u16 animNum)421 AnimTransformBasic::SetResource(
422     const res::AnimationBlock*  pRes,
423     ResourceAccessor* pResAccessor,
424     u16 animNum
425 )
426 {
427     NW_ASSERT(m_pTexAry == 0);
428     NW_ASSERT(m_pAnimLinkAry == 0);
429     NW_NULL_ASSERT(pRes);
430 
431     this->SetAnimResource(pRes);
432     m_pTexAry = 0;
433 
434      if (pRes->fileNum > 0)
435     {
436         NW_NULL_ASSERT(pResAccessor);
437 
438         m_pTexAry = Layout::NewArray<TextureInfo>(pRes->fileNum);
439         if (m_pTexAry)
440         {
441             const u32* fileNameOffsets = internal::ConvertOffsToPtr<u32>(pRes, sizeof(*pRes));
442 
443             for (int i = 0; i < pRes->fileNum; ++i)
444             {
445                 const char *const fileName = internal::GetStrTableStr(fileNameOffsets, i);
446 
447                 // テクスチャオブジェクトをロードする。
448                 m_pTexAry[i] = pResAccessor->GetTexture(fileName);
449             }
450         }
451     }
452 
453     m_pAnimLinkAry = Layout::NewArray<AnimationLink>(animNum);
454     if (m_pAnimLinkAry)
455     {
456         m_AnimLinkNum = animNum;
457     }
458 }
459 
460 void
Bind(Pane * pPane,bool bRecursive,bool bDisable)461 AnimTransformBasic::Bind(
462     Pane* pPane,
463     bool bRecursive,
464     bool bDisable
465 )
466 {
467     NW_NULL_ASSERT(pPane);
468 
469     AnimationLink* pCrAnimLink = 0;
470     const res::AnimationBlock* pRes = this->GetAnimResource();
471 
472     const u32 *const animContOffsets = internal::ConvertOffsToPtr<u32>(pRes, pRes->animContOffsetsOffset);
473     for (u16 i = 0; i < pRes->animContNum; ++i)
474     {
475         const res::AnimationContent& animCont = *internal::ConvertOffsToPtr<res::AnimationContent>(pRes, animContOffsets[i]);
476         if (animCont.type == ANIMCONTENTTYPE_PANE)
477         {
478             if (Pane *const pFindPane = pPane->FindPaneByName(animCont.name, bRecursive))
479             {
480                 if (! IsBindAnimation(pFindPane, this))
481                 {
482                     pCrAnimLink = Bind(pFindPane, pCrAnimLink, i, bDisable);
483                     if (! pCrAnimLink)
484                     {
485                         break;
486                     }
487                 }
488             }
489         }
490         else
491         {
492             if (Material *const pFindMat = pPane->FindMaterialByName(animCont.name, bRecursive))
493             {
494                 if (! IsBindAnimation(pFindMat, this))
495                 {
496                     pCrAnimLink = Bind(pFindMat, pCrAnimLink, i, bDisable);
497                     if (! pCrAnimLink)
498                     {
499                         break;
500                     }
501                 }
502             }
503         }
504     }
505 }
506 
507 void
Bind(Material * pMaterial,bool bDisable)508 AnimTransformBasic::Bind(
509     Material* pMaterial,
510     bool bDisable
511 )
512 {
513     NW_NULL_ASSERT(pMaterial);
514 
515     AnimationLink* pCrAnimLink = 0;
516     const res::AnimationBlock* pRes = this->GetAnimResource();
517 
518     const u32 *const animContOffsets = internal::ConvertOffsToPtr<u32>(pRes, pRes->animContOffsetsOffset);
519     for (u16 i = 0; i < pRes->animContNum; ++i)
520     {
521         const res::AnimationContent& animCont = *internal::ConvertOffsToPtr<res::AnimationContent>(pRes, animContOffsets[i]);
522         if (animCont.type == ANIMCONTENTTYPE_MATERIAL)
523         {
524             if (internal::EqualsMaterialName(pMaterial->GetName(), animCont.name))
525             {
526                 if (! IsBindAnimation(pMaterial, this))
527                 {
528                     pCrAnimLink = Bind(pMaterial, pCrAnimLink, i, bDisable);
529                     if (! pCrAnimLink)
530                     {
531                         break;
532                     }
533                 }
534             }
535         }
536     }
537 }
538 
539 template<typename T>
540 AnimationLink*
Bind(T * pTarget,AnimationLink * pAnimLink,u16 idx,bool bDisable)541 AnimTransformBasic::Bind(
542     T* pTarget,
543     AnimationLink* pAnimLink,
544     u16 idx,
545     bool bDisable
546 )
547 {
548     NW_NULL_ASSERT(pTarget);
549 
550     pAnimLink = FindUnbindLink(pAnimLink);
551     if (! pAnimLink)
552     {
553         NW_WARNING(false, "all AnimationLink used.");
554         return 0;
555     }
556 
557     pAnimLink->Set(this, idx, bDisable);
558     pTarget->AddAnimationLink(pAnimLink);
559 
560     return ++pAnimLink;
561 }
562 
563 void
Animate(u32 idx,Pane * pPane)564 AnimTransformBasic::Animate(u32 idx, Pane* pPane)
565 {
566     NW_NULL_ASSERT(pPane);
567 
568     const res::AnimationBlock* pRes = this->GetAnimResource();
569 
570     u32 animContOffsets = internal::ConvertOffsToPtr<u32>(pRes, pRes->animContOffsetsOffset)[idx];
571     const res::AnimationContent* pAnimCont = internal::ConvertOffsToPtr<res::AnimationContent>(pRes, animContOffsets);
572 
573     const u32* animInfoOffsets = internal::ConvertOffsToPtr<u32>(pAnimCont, sizeof(*pAnimCont));
574     for (int i = 0; i < pAnimCont->num; ++i)
575     {
576         const res::AnimationInfo* pAnimInfo = internal::ConvertOffsToPtr<res::AnimationInfo>(pAnimCont, animInfoOffsets[i]);
577         const u32* animTargetOffsets = internal::ConvertOffsToPtr<u32>(pAnimInfo, sizeof(*pAnimInfo));
578 
579         switch (pAnimInfo->kind)
580         {
581         case res::ANIMATIONTYPE_PANESRT:
582             AnimatePaneSRT(pPane, pAnimInfo, animTargetOffsets, this->GetFrame());
583             break;
584         case res::ANIMATIONTYPE_VISIBILITY:
585             AnimateVisibility(pPane, pAnimInfo, animTargetOffsets, this->GetFrame());
586             break;
587         case res::ANIMATIONTYPE_VTXCOLOR:
588             AnimateVertexColor(pPane, pAnimInfo, animTargetOffsets, this->GetFrame());
589             break;
590         }
591     }
592 }
593 
594 void
Animate(u32 idx,Material * pMaterial)595 AnimTransformBasic::Animate(u32 idx, Material* pMaterial)
596 {
597     NW_NULL_ASSERT(pMaterial);
598 
599     const res::AnimationBlock* pRes = this->GetAnimResource();
600     if (pRes == NULL)
601     {
602         NW_WARNING(false, "Animation resource is not set.");
603         return;
604     }
605 
606     u32 animContOffsets = internal::ConvertOffsToPtr<u32>(pRes, pRes->animContOffsetsOffset)[idx];
607     const res::AnimationContent* pAnimCont = internal::ConvertOffsToPtr<res::AnimationContent>(pRes, animContOffsets);
608 
609     const u32* animInfoOffsets = internal::ConvertOffsToPtr<u32>(pAnimCont, sizeof(*pAnimCont));
610     for (int i = 0; i < pAnimCont->num; ++i)
611     {
612         const res::AnimationInfo* pAnimInfo = internal::ConvertOffsToPtr<res::AnimationInfo>(pAnimCont, animInfoOffsets[i]);
613         const u32* animTargetOffsets = internal::ConvertOffsToPtr<u32>(pAnimInfo, sizeof(*pAnimInfo));
614 
615         switch (pAnimInfo->kind)
616         {
617         case res::ANIMATIONTYPE_MATCOLOR:
618             AnimateMaterialColor(pMaterial, pAnimInfo, animTargetOffsets, this->GetFrame());
619             break;
620         case res::ANIMATIONTYPE_TEXSRT:
621             AnimateTextureSRT(pMaterial, pAnimInfo, animTargetOffsets, this->GetFrame());
622             break;
623         case res::ANIMATIONTYPE_TEXPATTERN:
624             if (m_pTexAry)
625             {
626                 AnimateTexturePattern(pMaterial, pAnimInfo, animTargetOffsets, this->GetFrame(), m_pTexAry);
627             }
628             break;
629         }
630     }
631 }
632 
633 AnimationLink*
FindUnbindLink(AnimationLink * pLink) const634 AnimTransformBasic::FindUnbindLink(AnimationLink* pLink) const
635 {
636     if (pLink == 0)
637     {
638         if (m_pAnimLinkAry == 0)
639         {
640             NW_WARNING(false, "Animation resource is not set.");
641             return 0;
642         }
643         pLink = m_pAnimLinkAry;
644     }
645 
646     while (pLink < m_pAnimLinkAry + m_AnimLinkNum)
647     {
648         if (pLink->GetAnimTransform() == 0)
649         {
650             return pLink;
651         }
652 
653         ++pLink;
654     }
655 
656     return 0;
657 }
658 
AnimResource()659 AnimResource::AnimResource()
660 {
661     Init();
662 }
663 
664 bool
CheckResource() const665 AnimResource::CheckResource() const
666 {
667     if (!m_pResBlock)
668     {
669         NW_WARNING(false, "Animation resource is not set.");
670         return false;
671     }
672     return true;
673 }
674 
675 void
Set(const void * anmResBuf)676 AnimResource::Set(const void* anmResBuf)
677 {
678     NW_NULL_ASSERT(anmResBuf);
679 
680     Init();
681 
682     const ut::BinaryFileHeader *const pFileHeader = static_cast<const ut::BinaryFileHeader*>(anmResBuf);
683 
684     if (!ut::IsValidBinaryFile(pFileHeader, res::FILESIGNATURE_CLAN, res::BinaryFileFormatVersion))
685     {
686         NW_WARNING(false, "not valid layout animation file.");
687         return;
688     }
689 
690     m_pFileHeader = pFileHeader;
691 
692     const ut::BinaryBlockHeader* pDataBlockHead = internal::ConvertOffsToPtr<ut::BinaryBlockHeader>(m_pFileHeader, m_pFileHeader->headerSize);
693     for (int i = 0; i < m_pFileHeader->dataBlocks; ++i)
694     {
695         ut::SigWord kind = pDataBlockHead->kind;
696         switch (kind)
697         {
698         case res::DATABLOCKKIND_PANEANIMTAG:
699             m_pTagBlock = reinterpret_cast<const res::AnimationTagBlock*>(pDataBlockHead);
700             break;
701 
702         case res::DATABLOCKKIND_PANEANIMSHARE:
703             m_pShareBlock = reinterpret_cast<const res::AnimationShareBlock*>(pDataBlockHead);
704             break;
705 
706         case res::DATABLOCKKIND_PANEANIMINFO:
707             m_pResBlock = reinterpret_cast<const res::AnimationBlock*>(pDataBlockHead);
708             break;
709         }
710 
711         // 次のブロック位置へ
712         pDataBlockHead = internal::ConvertOffsToPtr<ut::BinaryBlockHeader>(pDataBlockHead, pDataBlockHead->size);
713     }
714 
715     NW_WARNING(m_pResBlock != NULL, "Animation resource is empty.");
716 }
717 
718 void
Init()719 AnimResource::Init()
720 {
721     m_pFileHeader = 0;
722     m_pResBlock = 0;
723     m_pTagBlock = 0;
724     m_pShareBlock = 0;
725 }
726 
727 u16
GetTagOrder() const728 AnimResource::GetTagOrder() const
729 {
730     if (! m_pTagBlock)
731     {
732         return u16(-1);
733     }
734 
735     return m_pTagBlock->tagOrder;
736 }
737 
738 const char*
GetTagName() const739 AnimResource::GetTagName() const
740 {
741     if (! m_pTagBlock)
742     {
743         return 0;
744     }
745 
746     return internal::ConvertOffsToPtr<const char>(m_pTagBlock, m_pTagBlock->nameOffset);
747 }
748 
749 u16
GetGroupNum() const750 AnimResource::GetGroupNum() const
751 {
752     if (! m_pTagBlock)
753     {
754         return 0;
755     }
756 
757     return m_pTagBlock->groupNum;
758 }
759 
760 const AnimationGroupRef*
GetGroupArray() const761 AnimResource::GetGroupArray() const
762 {
763     if (! m_pTagBlock)
764     {
765         return 0;
766     }
767 
768     const AnimationGroupRef *const groups = internal::ConvertOffsToPtr<const AnimationGroupRef>(m_pTagBlock, m_pTagBlock->groupsOffset);
769 
770     return groups;
771 
772 }
773 
774 bool
IsDescendingBind() const775 AnimResource::IsDescendingBind() const
776 {
777     if (! m_pTagBlock)
778     {
779         return false;
780     }
781 
782     return internal::TestBit(m_pTagBlock->flag, ANIMTAGFLAG_DESCENDINGBIND);
783 }
784 
785 u16
GetAnimationShareInfoNum() const786 AnimResource::GetAnimationShareInfoNum() const
787 {
788     if (! m_pShareBlock)
789     {
790         return 0;
791     }
792 
793     return m_pShareBlock->shareNum;
794 }
795 
796 const AnimationShareInfo*
GetAnimationShareInfoArray() const797 AnimResource::GetAnimationShareInfoArray() const
798 {
799     if (! m_pShareBlock)
800     {
801         return 0;
802     }
803 
804     return internal::ConvertOffsToPtr<const AnimationShareInfo>(m_pShareBlock, m_pShareBlock->animShareInfoOffset);
805 }
806 
807 u16
CalcAnimationNum(Pane * pPane,bool bRecursive) const808 AnimResource::CalcAnimationNum(
809     Pane* pPane,
810     bool bRecursive
811 ) const
812 {
813     if (! CheckResource())
814     {
815         return 0;
816     }
817 
818     u16 linkNum = 0;
819 
820     const u32 *const animContOffsets = internal::ConvertOffsToPtr<u32>(m_pResBlock, m_pResBlock->animContOffsetsOffset);
821     for (u16 i = 0; i < m_pResBlock->animContNum; ++i)
822     {
823         const res::AnimationContent& animCont = *internal::ConvertOffsToPtr<res::AnimationContent>(m_pResBlock, animContOffsets[i]);
824         if (animCont.type == ANIMCONTENTTYPE_PANE)
825         {
826             if (Pane *const pFindPane = pPane->FindPaneByName(animCont.name, bRecursive))
827             {
828                 ++linkNum;
829             }
830         }
831         else
832         {
833             if (Material *const pFindMat = pPane->FindMaterialByName(animCont.name, bRecursive))
834             {
835                 ++linkNum;
836             }
837         }
838     }
839 
840     return linkNum;
841 }
842 
843 u16
CalcAnimationNum(Material * pMaterial) const844 AnimResource::CalcAnimationNum(Material* pMaterial) const
845 {
846     if (! CheckResource())
847     {
848         return 0;
849     }
850 
851     u16 linkNum = 0;
852 
853     const u32 *const animContOffsets = internal::ConvertOffsToPtr<u32>(m_pResBlock, m_pResBlock->animContOffsetsOffset);
854     for (u16 i = 0; i < m_pResBlock->animContNum; ++i)
855     {
856         const res::AnimationContent& animCont = *internal::ConvertOffsToPtr<res::AnimationContent>(m_pResBlock, animContOffsets[i]);
857         if (animCont.type == ANIMCONTENTTYPE_MATERIAL)
858         {
859             if (internal::EqualsMaterialName(pMaterial->GetName(), animCont.name))
860             {
861                 ++linkNum;
862                 break;  // 同じ名前の res::AnimationContent が複数存在することはないため、
863                 // 見つかったらすぐに抜ける。
864             }
865         }
866     }
867 
868     return linkNum;
869 }
870 
871 u16
CalcAnimationNum(Group * pGroup,bool bRecursive) const872 AnimResource::CalcAnimationNum(
873     Group* pGroup,
874     bool bRecursive
875 ) const
876 {
877     NW_NULL_ASSERT(pGroup);
878 
879     u16 linkNum = 0;
880 
881     PaneLinkList& paneList = pGroup->GetPaneList();
882     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
883     {
884         linkNum += CalcAnimationNum(it->target, bRecursive);
885     }
886 
887     return linkNum;
888 }
889 
890 namespace internal
891 {
892 
AnimPaneTree()893 AnimPaneTree::AnimPaneTree()
894 {
895     Init();
896 }
897 
AnimPaneTree(Pane * pTargetPane,const AnimResource & animRes)898 AnimPaneTree::AnimPaneTree(
899     Pane* pTargetPane,
900     const AnimResource& animRes)
901 {
902     Init();
903     Set(pTargetPane, animRes);
904 }
905 
906 u16
FindAnimContent(const res::AnimationBlock * pAnimBlock,const char * animContName,u8 animContType)907 AnimPaneTree::FindAnimContent(
908     const res::AnimationBlock* pAnimBlock,
909     const char* animContName,
910     u8 animContType
911 )
912 {
913     NW_NULL_ASSERT(pAnimBlock);
914 
915     const u32 *const animContOffsets = ConvertOffsToPtr<u32>(pAnimBlock, pAnimBlock->animContOffsetsOffset);
916     for (u16 i = 0; i < pAnimBlock->animContNum; ++i)
917     {
918         const res::AnimationContent *const pAnimCont = ConvertOffsToPtr<res::AnimationContent>(pAnimBlock, animContOffsets[i]);
919         if (pAnimCont->type == animContType &&
920             internal::EqualsMaterialName(pAnimCont->name, animContName))
921         {
922             return i;
923         }
924     }
925 
926     return NOBIND;
927 }
928 
929 void
Init()930 AnimPaneTree::Init()
931 {
932     m_LinkNum = 0;
933 
934     m_AnimPaneIdx = 0;
935     m_AnimMatCnt = 0;
936     for (u8 i = 0; i < MATERIAL_NUM_MAX; ++i)
937     {
938         m_AnimMatIdxs[i] = 0;
939     }
940 }
941 
942 void
Set(Pane * pTargetPane,const AnimResource & animRes)943 AnimPaneTree::Set(
944     Pane* pTargetPane,
945     const AnimResource& animRes
946 )
947 {
948     NW_NULL_ASSERT(pTargetPane);
949 
950     u16 linkNum = 0;
951     const res::AnimationBlock* pAnimBlock = animRes.GetResourceBlock();
952 
953     const u16 animContIdx = FindAnimContent(pAnimBlock, pTargetPane->GetName(), ANIMCONTENTTYPE_PANE);
954     if (animContIdx != NOBIND)
955     {
956         ++linkNum;
957     }
958 
959     // マテリアルの処理
960     const u8 animMatCnt = pTargetPane->GetMaterialNum();
961     NW_ASSERT(animMatCnt <= MATERIAL_NUM_MAX);
962     u16 animMatIdxs[MATERIAL_NUM_MAX];
963 
964     for (u8 i = 0; i < animMatCnt; ++i)
965     {
966         animMatIdxs[i] = FindAnimContent(pAnimBlock, pTargetPane->GetMaterial(i)->GetName(), ANIMCONTENTTYPE_MATERIAL);
967         if (animMatIdxs[i] != NOBIND)
968         {
969             ++linkNum;
970         }
971     }
972 
973     // アニメーション対象がひとつも無い
974     if (linkNum == 0)
975     {
976         return;
977     }
978 
979     m_AnimRes = animRes;
980     m_AnimPaneIdx = animContIdx;
981     m_AnimMatCnt = animMatCnt;
982     for (u8 i = 0; i < animMatCnt; ++i)
983     {
984         m_AnimMatIdxs[i] = animMatIdxs[i];
985     }
986     m_LinkNum = linkNum;
987 }
988 
989 AnimTransform*
Bind(Layout * pLayout,Pane * pTargetPane,ResourceAccessor * pResAccessor) const990 AnimPaneTree::Bind(
991     Layout* pLayout,
992     Pane* pTargetPane,
993     ResourceAccessor* pResAccessor
994 ) const
995 {
996     NW_NULL_ASSERT(pLayout);
997     NW_NULL_ASSERT(pTargetPane);
998 
999     AnimTransformBasic *const pAnimTrans = static_cast<AnimTransformBasic*>(pLayout->CreateAnimTransform());
1000     pAnimTrans->SetResource(m_AnimRes.GetResourceBlock(), pResAccessor, m_LinkNum);
1001 
1002     AnimationLink* pCrAnimLink = 0;
1003 
1004     // ペインのアニメのバインド
1005     if (m_AnimPaneIdx != NOBIND)
1006     {
1007         pCrAnimLink = pAnimTrans->Bind(pTargetPane, pCrAnimLink, m_AnimPaneIdx, true/*bDisable*/);
1008     }
1009 
1010     // マテリアルアニメのバインド
1011     // ※マテリアルの個数が共有元ペインと等しいとは限りません。
1012     const u32 animMatMax = ut::Min(m_AnimMatCnt, pTargetPane->GetMaterialNum());
1013     for (u32 i = 0; i < animMatMax; ++i)
1014     {
1015         if (m_AnimMatIdxs[i] != NOBIND)
1016         {
1017             Material *const pMaterial = pTargetPane->GetMaterial(i);
1018             NW_NULL_ASSERT(pMaterial);
1019             pCrAnimLink = pAnimTrans->Bind(pMaterial, pCrAnimLink, m_AnimMatIdxs[i], true/*bDisable*/);
1020         }
1021     }
1022 
1023     return pAnimTrans;
1024 }
1025 
1026 AnimationLink*
FindAnimationLink(AnimationList * pAnimList,AnimTransform * pAnimTrans)1027 FindAnimationLink(
1028     AnimationList* pAnimList,
1029     AnimTransform* pAnimTrans
1030 )
1031 {
1032     NW_NULL_ASSERT(pAnimList);
1033     NW_NULL_ASSERT(pAnimTrans);
1034 
1035     for (AnimationList::Iterator it = pAnimList->GetBeginIter(); it != pAnimList->GetEndIter(); ++it)
1036     {
1037         if (pAnimTrans == it->GetAnimTransform())
1038         {
1039             return &(*it);
1040         }
1041     }
1042 
1043     return 0;
1044 }
1045 
1046 AnimationLink*
FindAnimationLink(AnimationList * pAnimList,const AnimResource & animRes)1047 FindAnimationLink(
1048     AnimationList* pAnimList,
1049     const AnimResource& animRes
1050 )
1051 {
1052     NW_NULL_ASSERT(pAnimList);
1053 
1054     for (AnimationList::Iterator it = pAnimList->GetBeginIter(); it != pAnimList->GetEndIter(); ++it)
1055     {
1056         if (animRes.GetResourceBlock() == it->GetAnimTransform()->GetAnimResource())
1057         {
1058             return &(*it);
1059         }
1060     }
1061 
1062     return 0;
1063 }
1064 
1065 void
UnbindAnimationLink(AnimationList * pAnimList,AnimTransform * pAnimTrans)1066 UnbindAnimationLink(
1067     AnimationList* pAnimList,
1068     AnimTransform* pAnimTrans
1069 )
1070 {
1071     NW_NULL_ASSERT(pAnimList);
1072 
1073     for (AnimationList::Iterator it = pAnimList->GetBeginIter(); it != pAnimList->GetEndIter();)
1074     {
1075         AnimationList::Iterator currIt = it++;
1076         if (! pAnimTrans || currIt->GetAnimTransform() == pAnimTrans)
1077         {
1078             pAnimList->Erase(currIt);
1079             currIt->Reset();
1080         }
1081     }
1082 }
1083 
1084 } // namespace nw::lyt::internal
1085 } // namespace nw::lyt
1086 } // namespace nw
1087