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