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