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: 26791 $
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 void
Animate(u32 idx,Pane * pPane)540 AnimTransformBasic::Animate(u32 idx, Pane* pPane)
541 {
542     NW_NULL_ASSERT(pPane);
543 
544     const res::AnimationBlock* pRes = this->GetAnimResource();
545 
546     u32 animContOffsets = internal::ConvertOffsToPtr<u32>(pRes, pRes->animContOffsetsOffset)[idx];
547     const res::AnimationContent* pAnimCont = internal::ConvertOffsToPtr<res::AnimationContent>(pRes, animContOffsets);
548 
549     const u32* animInfoOffsets = internal::ConvertOffsToPtr<u32>(pAnimCont, sizeof(*pAnimCont));
550     for (int i = 0; i < pAnimCont->num; ++i)
551     {
552         const res::AnimationInfo* pAnimInfo = internal::ConvertOffsToPtr<res::AnimationInfo>(pAnimCont, animInfoOffsets[i]);
553         const u32* animTargetOffsets = internal::ConvertOffsToPtr<u32>(pAnimInfo, sizeof(*pAnimInfo));
554 
555         switch (pAnimInfo->kind)
556         {
557         case res::ANIMATIONTYPE_PANESRT:
558             AnimatePaneSRT(pPane, pAnimInfo, animTargetOffsets, this->GetFrame());
559             break;
560         case res::ANIMATIONTYPE_VISIBILITY:
561             AnimateVisibility(pPane, pAnimInfo, animTargetOffsets, this->GetFrame());
562             break;
563         case res::ANIMATIONTYPE_VTXCOLOR:
564             AnimateVertexColor(pPane, pAnimInfo, animTargetOffsets, this->GetFrame());
565             break;
566         }
567     }
568 }
569 
570 void
Animate(u32 idx,Material * pMaterial)571 AnimTransformBasic::Animate(u32 idx, Material* pMaterial)
572 {
573     NW_NULL_ASSERT(pMaterial);
574 
575     const res::AnimationBlock* pRes = this->GetAnimResource();
576     if (pRes == NULL)
577     {
578         NW_WARNING(false, "Animation resource is not set.");
579         return;
580     }
581 
582     u32 animContOffsets = internal::ConvertOffsToPtr<u32>(pRes, pRes->animContOffsetsOffset)[idx];
583     const res::AnimationContent* pAnimCont = internal::ConvertOffsToPtr<res::AnimationContent>(pRes, animContOffsets);
584 
585     const u32* animInfoOffsets = internal::ConvertOffsToPtr<u32>(pAnimCont, sizeof(*pAnimCont));
586     for (int i = 0; i < pAnimCont->num; ++i)
587     {
588         const res::AnimationInfo* pAnimInfo = internal::ConvertOffsToPtr<res::AnimationInfo>(pAnimCont, animInfoOffsets[i]);
589         const u32* animTargetOffsets = internal::ConvertOffsToPtr<u32>(pAnimInfo, sizeof(*pAnimInfo));
590 
591         switch (pAnimInfo->kind)
592         {
593         case res::ANIMATIONTYPE_MATCOLOR:
594             AnimateMaterialColor(pMaterial, pAnimInfo, animTargetOffsets, this->GetFrame());
595             break;
596         case res::ANIMATIONTYPE_TEXSRT:
597             AnimateTextureSRT(pMaterial, pAnimInfo, animTargetOffsets, this->GetFrame());
598             break;
599         case res::ANIMATIONTYPE_TEXPATTERN:
600             if (m_pTexAry)
601             {
602                 AnimateTexturePattern(pMaterial, pAnimInfo, animTargetOffsets, this->GetFrame(), m_pTexAry);
603             }
604             break;
605         }
606     }
607 }
608 
609 AnimationLink*
FindUnbindLink(AnimationLink * pLink) const610 AnimTransformBasic::FindUnbindLink(AnimationLink* pLink) const
611 {
612     if (pLink == 0)
613     {
614         if (m_pAnimLinkAry == 0)
615         {
616             NW_WARNING(false, "Animation resource is not set.");
617             return 0;
618         }
619         pLink = m_pAnimLinkAry;
620     }
621 
622     while (pLink < m_pAnimLinkAry + m_AnimLinkNum)
623     {
624         if (pLink->GetAnimTransform() == 0)
625         {
626             return pLink;
627         }
628 
629         ++pLink;
630     }
631 
632     return 0;
633 }
634 
AnimResource()635 AnimResource::AnimResource()
636 {
637     Init();
638 }
639 
640 bool
CheckResource() const641 AnimResource::CheckResource() const
642 {
643     if (!m_pResBlock)
644     {
645         NW_WARNING(false, "Animation resource is not set.");
646         return false;
647     }
648     return true;
649 }
650 
651 void
Set(const void * anmResBuf)652 AnimResource::Set(const void* anmResBuf)
653 {
654     NW_NULL_ASSERT(anmResBuf);
655 
656     Init();
657 
658     const ut::BinaryFileHeader *const pFileHeader = static_cast<const ut::BinaryFileHeader*>(anmResBuf);
659 
660     if (!ut::IsValidBinaryFile(pFileHeader, res::FILESIGNATURE_CLAN, res::BinaryFileFormatVersion))
661     {
662         NW_WARNING(false, "not valid layout animation file.");
663         return;
664     }
665 
666     m_pFileHeader = pFileHeader;
667 
668     const ut::BinaryBlockHeader* pDataBlockHead = internal::ConvertOffsToPtr<ut::BinaryBlockHeader>(m_pFileHeader, m_pFileHeader->headerSize);
669     for (int i = 0; i < m_pFileHeader->dataBlocks; ++i)
670     {
671         ut::SigWord kind = pDataBlockHead->kind;
672         switch (kind)
673         {
674         case res::DATABLOCKKIND_PANEANIMTAG:
675             m_pTagBlock = reinterpret_cast<const res::AnimationTagBlock*>(pDataBlockHead);
676             break;
677 
678         case res::DATABLOCKKIND_PANEANIMSHARE:
679             m_pShareBlock = reinterpret_cast<const res::AnimationShareBlock*>(pDataBlockHead);
680             break;
681 
682         case res::DATABLOCKKIND_PANEANIMINFO:
683             m_pResBlock = reinterpret_cast<const res::AnimationBlock*>(pDataBlockHead);
684             break;
685         }
686 
687         // 次のブロック位置へ
688         pDataBlockHead = internal::ConvertOffsToPtr<ut::BinaryBlockHeader>(pDataBlockHead, pDataBlockHead->size);
689     }
690 
691     NW_WARNING(m_pResBlock != NULL, "Animation resource is empty.");
692 }
693 
694 void
Init()695 AnimResource::Init()
696 {
697     m_pFileHeader = 0;
698     m_pResBlock = 0;
699     m_pTagBlock = 0;
700     m_pShareBlock = 0;
701 }
702 
703 u16
GetTagOrder() const704 AnimResource::GetTagOrder() const
705 {
706     if (! m_pTagBlock)
707     {
708         return u16(-1);
709     }
710 
711     return m_pTagBlock->tagOrder;
712 }
713 
714 const char*
GetTagName() const715 AnimResource::GetTagName() const
716 {
717     if (! m_pTagBlock)
718     {
719         return 0;
720     }
721 
722     return internal::ConvertOffsToPtr<const char>(m_pTagBlock, m_pTagBlock->nameOffset);
723 }
724 
725 u16
GetGroupNum() const726 AnimResource::GetGroupNum() const
727 {
728     if (! m_pTagBlock)
729     {
730         return 0;
731     }
732 
733     return m_pTagBlock->groupNum;
734 }
735 
736 const AnimationGroupRef*
GetGroupArray() const737 AnimResource::GetGroupArray() const
738 {
739     if (! m_pTagBlock)
740     {
741         return 0;
742     }
743 
744     const AnimationGroupRef *const groups = internal::ConvertOffsToPtr<const AnimationGroupRef>(m_pTagBlock, m_pTagBlock->groupsOffset);
745 
746     return groups;
747 
748 }
749 
750 bool
IsDescendingBind() const751 AnimResource::IsDescendingBind() const
752 {
753     if (! m_pTagBlock)
754     {
755         return false;
756     }
757 
758     return internal::TestBit(m_pTagBlock->flag, ANIMTAGFLAG_DESCENDINGBIND);
759 }
760 
761 u16
GetAnimationShareInfoNum() const762 AnimResource::GetAnimationShareInfoNum() const
763 {
764     if (! m_pShareBlock)
765     {
766         return 0;
767     }
768 
769     return m_pShareBlock->shareNum;
770 }
771 
772 const AnimationShareInfo*
GetAnimationShareInfoArray() const773 AnimResource::GetAnimationShareInfoArray() const
774 {
775     if (! m_pShareBlock)
776     {
777         return 0;
778     }
779 
780     return internal::ConvertOffsToPtr<const AnimationShareInfo>(m_pShareBlock, m_pShareBlock->animShareInfoOffset);
781 }
782 
783 u16
CalcAnimationNum(Pane * pPane,bool bRecursive) const784 AnimResource::CalcAnimationNum(
785     Pane* pPane,
786     bool bRecursive
787 ) const
788 {
789     if (! CheckResource())
790     {
791         return 0;
792     }
793 
794     u16 linkNum = 0;
795 
796     const u32 *const animContOffsets = internal::ConvertOffsToPtr<u32>(m_pResBlock, m_pResBlock->animContOffsetsOffset);
797     for (u16 i = 0; i < m_pResBlock->animContNum; ++i)
798     {
799         const res::AnimationContent& animCont = *internal::ConvertOffsToPtr<res::AnimationContent>(m_pResBlock, animContOffsets[i]);
800         if (animCont.type == ANIMCONTENTTYPE_PANE)
801         {
802             if (Pane *const pFindPane = pPane->FindPaneByName(animCont.name, bRecursive))
803             {
804                 ++linkNum;
805             }
806         }
807         else
808         {
809             if (Material *const pFindMat = pPane->FindMaterialByName(animCont.name, bRecursive))
810             {
811                 ++linkNum;
812             }
813         }
814     }
815 
816     return linkNum;
817 }
818 
819 u16
CalcAnimationNum(Material * pMaterial) const820 AnimResource::CalcAnimationNum(Material* pMaterial) const
821 {
822     if (! CheckResource())
823     {
824         return 0;
825     }
826 
827     u16 linkNum = 0;
828 
829     const u32 *const animContOffsets = internal::ConvertOffsToPtr<u32>(m_pResBlock, m_pResBlock->animContOffsetsOffset);
830     for (u16 i = 0; i < m_pResBlock->animContNum; ++i)
831     {
832         const res::AnimationContent& animCont = *internal::ConvertOffsToPtr<res::AnimationContent>(m_pResBlock, animContOffsets[i]);
833         if (animCont.type == ANIMCONTENTTYPE_MATERIAL)
834         {
835             if (internal::EqualsMaterialName(pMaterial->GetName(), animCont.name))
836             {
837                 ++linkNum;
838                 break;  // 同じ名前の res::AnimationContent が複数存在することはないため、
839                 // 見つかったらすぐに抜ける。
840             }
841         }
842     }
843 
844     return linkNum;
845 }
846 
847 u16
CalcAnimationNum(Group * pGroup,bool bRecursive) const848 AnimResource::CalcAnimationNum(
849     Group* pGroup,
850     bool bRecursive
851 ) const
852 {
853     NW_NULL_ASSERT(pGroup);
854 
855     u16 linkNum = 0;
856 
857     PaneLinkList& paneList = pGroup->GetPaneList();
858     for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
859     {
860         linkNum += CalcAnimationNum(it->target, bRecursive);
861     }
862 
863     return linkNum;
864 }
865 
866 namespace internal
867 {
868 
AnimPaneTree()869 AnimPaneTree::AnimPaneTree()
870 {
871     Init();
872 }
873 
AnimPaneTree(Pane * pTargetPane,const AnimResource & animRes)874 AnimPaneTree::AnimPaneTree(
875     Pane* pTargetPane,
876     const AnimResource& animRes)
877 {
878     Init();
879     Set(pTargetPane, animRes);
880 }
881 
882 u16
FindAnimContent(const res::AnimationBlock * pAnimBlock,const char * animContName,u8 animContType)883 AnimPaneTree::FindAnimContent(
884     const res::AnimationBlock* pAnimBlock,
885     const char* animContName,
886     u8 animContType
887 )
888 {
889     NW_NULL_ASSERT(pAnimBlock);
890 
891     const u32 *const animContOffsets = ConvertOffsToPtr<u32>(pAnimBlock, pAnimBlock->animContOffsetsOffset);
892     for (u16 i = 0; i < pAnimBlock->animContNum; ++i)
893     {
894         const res::AnimationContent *const pAnimCont = ConvertOffsToPtr<res::AnimationContent>(pAnimBlock, animContOffsets[i]);
895         if (pAnimCont->type == animContType &&
896             internal::EqualsMaterialName(pAnimCont->name, animContName))
897         {
898             return i;
899         }
900     }
901 
902     return NOBIND;
903 }
904 
905 void
Init()906 AnimPaneTree::Init()
907 {
908     m_LinkNum = 0;
909 
910     m_AnimPaneIdx = 0;
911     m_AnimMatCnt = 0;
912     for (u8 i = 0; i < MATERIAL_NUM_MAX; ++i)
913     {
914         m_AnimMatIdxs[i] = 0;
915     }
916 }
917 
918 void
Set(Pane * pTargetPane,const AnimResource & animRes)919 AnimPaneTree::Set(
920     Pane* pTargetPane,
921     const AnimResource& animRes
922 )
923 {
924     NW_NULL_ASSERT(pTargetPane);
925 
926     u16 linkNum = 0;
927     const res::AnimationBlock* pAnimBlock = animRes.GetResourceBlock();
928 
929     const u16 animContIdx = FindAnimContent(pAnimBlock, pTargetPane->GetName(), ANIMCONTENTTYPE_PANE);
930     if (animContIdx != NOBIND)
931     {
932         ++linkNum;
933     }
934 
935     // マテリアルの処理
936     const u8 animMatCnt = pTargetPane->GetMaterialNum();
937     NW_ASSERT(animMatCnt <= MATERIAL_NUM_MAX);
938     u16 animMatIdxs[MATERIAL_NUM_MAX];
939 
940     for (u8 i = 0; i < animMatCnt; ++i)
941     {
942         animMatIdxs[i] = FindAnimContent(pAnimBlock, pTargetPane->GetMaterial(i)->GetName(), ANIMCONTENTTYPE_MATERIAL);
943         if (animMatIdxs[i] != NOBIND)
944         {
945             ++linkNum;
946         }
947     }
948 
949     // アニメーション対象がひとつも無い
950     if (linkNum == 0)
951     {
952         return;
953     }
954 
955     m_AnimRes = animRes;
956     m_AnimPaneIdx = animContIdx;
957     m_AnimMatCnt = animMatCnt;
958     for (u8 i = 0; i < animMatCnt; ++i)
959     {
960         m_AnimMatIdxs[i] = animMatIdxs[i];
961     }
962     m_LinkNum = linkNum;
963 }
964 
965 AnimTransform*
Bind(Layout * pLayout,Pane * pTargetPane,ResourceAccessor * pResAccessor) const966 AnimPaneTree::Bind(
967     Layout* pLayout,
968     Pane* pTargetPane,
969     ResourceAccessor* pResAccessor
970 ) const
971 {
972     NW_NULL_ASSERT(pLayout);
973     NW_NULL_ASSERT(pTargetPane);
974 
975     AnimTransformBasic *const pAnimTrans = static_cast<AnimTransformBasic*>(pLayout->CreateAnimTransform());
976     pAnimTrans->SetResource(m_AnimRes.GetResourceBlock(), pResAccessor, m_LinkNum);
977 
978     AnimationLink* pCrAnimLink = 0;
979 
980     // ペインのアニメのバインド
981     if (m_AnimPaneIdx != NOBIND)
982     {
983         pCrAnimLink = pAnimTrans->Bind(pTargetPane, pCrAnimLink, m_AnimPaneIdx, true/*bDisable*/);
984     }
985 
986     // マテリアルアニメのバインド
987     // ※マテリアルの個数が共有元ペインと等しいとは限りません。
988     const u32 animMatMax = ut::Min(m_AnimMatCnt, pTargetPane->GetMaterialNum());
989     for (u32 i = 0; i < animMatMax; ++i)
990     {
991         if (m_AnimMatIdxs[i] != NOBIND)
992         {
993             Material *const pMaterial = pTargetPane->GetMaterial(i);
994             NW_NULL_ASSERT(pMaterial);
995             pCrAnimLink = pAnimTrans->Bind(pMaterial, pCrAnimLink, m_AnimMatIdxs[i], true/*bDisable*/);
996         }
997     }
998 
999     return pAnimTrans;
1000 }
1001 
1002 AnimationLink*
FindAnimationLink(AnimationList * pAnimList,AnimTransform * pAnimTrans)1003 FindAnimationLink(
1004     AnimationList* pAnimList,
1005     AnimTransform* pAnimTrans
1006 )
1007 {
1008     NW_NULL_ASSERT(pAnimList);
1009     NW_NULL_ASSERT(pAnimTrans);
1010 
1011     for (AnimationList::Iterator it = pAnimList->GetBeginIter(); it != pAnimList->GetEndIter(); ++it)
1012     {
1013         if (pAnimTrans == it->GetAnimTransform())
1014         {
1015             return &(*it);
1016         }
1017     }
1018 
1019     return 0;
1020 }
1021 
1022 AnimationLink*
FindAnimationLink(AnimationList * pAnimList,const AnimResource & animRes)1023 FindAnimationLink(
1024     AnimationList* pAnimList,
1025     const AnimResource& animRes
1026 )
1027 {
1028     NW_NULL_ASSERT(pAnimList);
1029 
1030     for (AnimationList::Iterator it = pAnimList->GetBeginIter(); it != pAnimList->GetEndIter(); ++it)
1031     {
1032         if (animRes.GetResourceBlock() == it->GetAnimTransform()->GetAnimResource())
1033         {
1034             return &(*it);
1035         }
1036     }
1037 
1038     return 0;
1039 }
1040 
1041 void
UnbindAnimationLink(AnimationList * pAnimList,AnimTransform * pAnimTrans)1042 UnbindAnimationLink(
1043     AnimationList* pAnimList,
1044     AnimTransform* pAnimTrans
1045 )
1046 {
1047     NW_NULL_ASSERT(pAnimList);
1048 
1049     for (AnimationList::Iterator it = pAnimList->GetBeginIter(); it != pAnimList->GetEndIter();)
1050     {
1051         AnimationList::Iterator currIt = it++;
1052         if (! pAnimTrans || currIt->GetAnimTransform() == pAnimTrans)
1053         {
1054             pAnimList->Erase(currIt);
1055             currIt->Reset();
1056         }
1057     }
1058 }
1059 
1060 } // namespace nw::lyt::internal
1061 } // namespace nw::lyt
1062 } // namespace nw
1063