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