1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: lyt_Layout.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_Animation.h>
21 #include <nw/lyt/lyt_Bounding.h>
22 #include <nw/lyt/lyt_Common.h>
23 #include <nw/lyt/lyt_DrawInfo.h>
24 #include <nw/lyt/lyt_GraphicsResource.h>
25 #include <nw/lyt/lyt_Group.h>
26 #include <nw/lyt/lyt_Layout.h>
27 #include <nw/lyt/lyt_Material.h>
28 #include <nw/lyt/lyt_Picture.h>
29 #include <nw/lyt/lyt_ResourceAccessor.h>
30 #include <nw/lyt/lyt_Resources.h>
31 #include <nw/lyt/lyt_Stopwatch.h>
32 #include <nw/lyt/lyt_TextBox.h>
33 #include <nw/lyt/lyt_Util.h>
34 #include <nw/lyt/lyt_Window.h>
35
36 #define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
37
38 namespace nw
39 {
40 namespace lyt
41 {
42
43 nw::os::IAllocator* Layout::s_pAllocator = 0;
44 nw::os::IAllocator* Layout::s_pDeviceMemoryAllocator = 0;
45 bool Layout::s_LayoutDrawEnable = false;
46
47 namespace
48 {
49
50 /*---------------------------------------------------------------------------*
51 @brief 再帰的にペインにタグプロセッサ設定します。
52 *---------------------------------------------------------------------------*/
53 void
SetTagProcessorImpl(Pane * pPane,font::TagProcessorBase<wchar_t> * pTagProcessor)54 SetTagProcessorImpl(
55 Pane* pPane,
56 font::TagProcessorBase<wchar_t>* pTagProcessor
57 )
58 {
59 // TextBox ペインか
60 if (TextBox* pTextBox = ut::DynamicCast<TextBox*>(pPane))
61 {
62 pTextBox->SetTagProcessor(pTagProcessor);
63 }
64
65 // 再帰的にセット
66 for (PaneList::Iterator it = pPane->GetChildList().GetBeginIter(); it != pPane->GetChildList().GetEndIter(); ++it)
67 {
68 SetTagProcessorImpl(&(*it), pTagProcessor);
69 }
70 }
71
72 bool
IsIncludeAnimationGroupRef(GroupContainer * pGroupContainer,const AnimationGroupRef * const groupRefs,u16 bindGroupNum,bool bDescendingBind,Pane * pTargetPane)73 IsIncludeAnimationGroupRef(
74 GroupContainer* pGroupContainer,
75 const AnimationGroupRef *const groupRefs,
76 u16 bindGroupNum,
77 bool bDescendingBind,
78 Pane* pTargetPane
79 )
80 {
81 for (u16 grpIdx = 0; grpIdx < bindGroupNum; ++grpIdx)
82 {
83 // 共有対象のペインがバインド指定のグループが持つペインリストに含まれるか調べます。
84 Group *const pGroup = pGroupContainer->FindGroupByName(groupRefs[grpIdx].GetName());
85 PaneLinkList& paneList = pGroup->GetPaneList();
86 for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
87 {
88 if (it->target == pTargetPane)
89 {
90 return true;
91 }
92
93 if (bDescendingBind)
94 {
95 // pTargetPaneの親方向で一致するものが無いか調べる。
96 for (Pane* pParentPane = pTargetPane->GetParent(); pParentPane; pParentPane = pParentPane->GetParent())
97 {
98 if (it->target == pParentPane)
99 {
100 return true;
101 }
102 }
103 }
104 }
105 }
106
107 return false;
108 }
109
110 } // namespace nw::lyt::{no-name}
111
112 void
SetAllocator(nw::os::IAllocator * pAllocator)113 Layout::SetAllocator(nw::os::IAllocator* pAllocator)
114 {
115 s_pAllocator = pAllocator;
116 }
117
118 void
SetDeviceMemoryAllocator(nw::os::IAllocator * pAllocator)119 Layout::SetDeviceMemoryAllocator(nw::os::IAllocator* pAllocator)
120 {
121 s_pDeviceMemoryAllocator = pAllocator;
122 }
123
124 void*
AllocMemory(u32 size,u8 alignment)125 Layout::AllocMemory(u32 size, u8 alignment)
126 {
127 NW_NULL_ASSERT(s_pAllocator);
128
129 void *const pMem = s_pAllocator->Alloc(size, alignment);
130 NW_WARNING(pMem, "can't alloc memory.");
131 return pMem;
132 }
133
134 void*
AllocDeviceMemory(u32 size,u8 alignment)135 Layout::AllocDeviceMemory(u32 size, u8 alignment)
136 {
137 NW_NULL_ASSERT(s_pDeviceMemoryAllocator);
138
139 void *const pMem = s_pDeviceMemoryAllocator->Alloc(size, alignment);
140 NW_WARNING(pMem, "can't alloc memory.");
141 return pMem;
142 }
143
144 void
FreeMemory(void * mem)145 Layout::FreeMemory(void* mem)
146 {
147 NW_NULL_ASSERT(s_pAllocator);
148
149 s_pAllocator->Free(mem);
150 }
151
152 void
FreeDeviceMemory(void * mem)153 Layout::FreeDeviceMemory(void* mem)
154 {
155 NW_NULL_ASSERT(s_pDeviceMemoryAllocator);
156
157 s_pDeviceMemoryAllocator->Free(mem);
158 }
159
Layout()160 Layout::Layout()
161 : m_pRootPane(0),
162 m_pGroupContainer(0),
163 m_LayoutSize(0.f, 0.f)
164 {
165 }
166
~Layout()167 Layout::~Layout()
168 {
169 DeleteObj(m_pGroupContainer);
170
171 if (m_pRootPane && !m_pRootPane->IsUserAllocated())
172 {
173 DeleteObj(m_pRootPane);
174 }
175
176 for (AnimTransformList::Iterator it = m_AnimTransList.GetBeginIter(); it != m_AnimTransList.GetEndIter();)
177 {
178 AnimTransformList::Iterator currIt = it++;
179 m_AnimTransList.Erase(currIt);
180 DeleteObj(&(*currIt));
181 }
182 }
183
184 bool
Build(const void * lytResBuf,ResourceAccessor * pResAcsr)185 Layout::Build(
186 const void* lytResBuf,
187 ResourceAccessor* pResAcsr
188 )
189 {
190 NW_NULL_ASSERT(s_pAllocator);
191 NW_NULL_ASSERT(lytResBuf);
192
193 const ut::BinaryFileHeader *const pFileHead = static_cast<const ut::BinaryFileHeader*>(lytResBuf);
194
195 if (! ut::IsValidBinaryFile(pFileHead, res::FILESIGNATURE_CLYT, res::BinaryFileFormatVersion))
196 {
197 NW_WARNING(false, "not valid layout file.");
198 }
199
200 ResBlockSet resBlockSet = { 0 };
201 resBlockSet.pResAccessor = pResAcsr;
202 Pane* pParentPane = 0;
203 Pane* pLastPane = 0;
204
205 bool bReadRootGroup = false;
206 int groupNestLevel = 0;
207
208 const void* dataPtr = static_cast<const u8*>(lytResBuf) + pFileHead->headerSize;
209 for (int i = 0; i < pFileHead->dataBlocks; ++i)
210 {
211 const ut::BinaryBlockHeader* pDataBlockHead = static_cast<const ut::BinaryBlockHeader*>(dataPtr);
212 ut::SigWord kind = pDataBlockHead->kind;
213 switch (kind)
214 {
215 case res::DATABLOCKKIND_LAYOUT:
216 {
217 const res::Layout* pResLyt = static_cast<const res::Layout*>(dataPtr);
218 this->SetLayoutSize(pResLyt->layoutSize);
219 }
220 break;
221
222 case res::DATABLOCKKIND_TEXTURELIST:
223 resBlockSet.pTextureList = static_cast<const res::TextureList*>(dataPtr);
224 break;
225
226 case res::DATABLOCKKIND_FONTLIST:
227 resBlockSet.pFontList = static_cast<const res::FontList*>(dataPtr);
228 break;
229
230 case res::DATABLOCKKIND_MATERIALLIST:
231 resBlockSet.pMaterialList = static_cast<const res::MaterialList*>(dataPtr);
232 break;
233
234 case res::DATABLOCKKIND_PANE:
235 case res::DATABLOCKKIND_PICTURE:
236 case res::DATABLOCKKIND_TEXTBOX:
237 case res::DATABLOCKKIND_WINDOW:
238 case res::DATABLOCKKIND_BOUNDING:
239 {
240 Pane* pPane = BuildPaneObj(kind, dataPtr, resBlockSet);
241 if (pPane)
242 {
243 // ルートペインがまだ設定されていないときはルートペインに設定
244 if (this->GetRootPane() == 0)
245 {
246 this->SetRootPane(pPane);
247 }
248
249 // 親がいたら親に登録
250 if (pParentPane)
251 {
252 pParentPane->AppendChild(pPane);
253 }
254
255 pLastPane = pPane;
256 }
257 }
258 break;
259
260 case res::DATABLOCKKIND_USERDATALIST:
261 NW_NULL_ASSERT(pLastPane);
262 pLastPane->SetExtUserDataList(reinterpret_cast<const res::ExtUserDataList*>(pDataBlockHead));
263 break;
264
265 case res::DATABLOCKKIND_PANEBEGIN:
266 NW_NULL_ASSERT(pLastPane);
267 pParentPane = pLastPane; // 最後に作成したペインを親とする
268 break;
269 case res::DATABLOCKKIND_PANEEND:
270 pLastPane = pParentPane; // 親ペインを最後に作成したペインとする
271 pParentPane = pLastPane->GetParent();
272 break;
273 case res::DATABLOCKKIND_GROUP:
274 if (! bReadRootGroup) // グループのルートに初めて到達
275 {
276 bReadRootGroup = true;
277 this->SetGroupContainer(NewObj<GroupContainer>());
278 }
279 else
280 {
281 if (this->GetGroupContainer() && groupNestLevel == 1)
282 {
283 if (Group* pGroup = NewObj<Group>(reinterpret_cast<const res::Group*>(pDataBlockHead), this->GetRootPane()))
284 {
285 this->GetGroupContainer()->AppendGroup(pGroup);
286 }
287 }
288 }
289 break;
290 case res::DATABLOCKKIND_GROUPBEGIN:
291 groupNestLevel++;
292 break;
293 case res::DATABLOCKKIND_GROUPEND:
294 groupNestLevel--;
295 break;
296 default:
297 break;
298 }
299
300 dataPtr = static_cast<const u8*>(dataPtr) + pDataBlockHead->size; // 次のブロック位置へ
301 }
302
303 return true;
304 }
305
306 AnimTransform*
CreateAnimTransform()307 Layout::CreateAnimTransform()
308 {
309 NW_NULL_ASSERT(s_pAllocator);
310
311 AnimTransformBasic *const pAnimTrans = NewObj<AnimTransformBasic>();
312 if (pAnimTrans)
313 {
314 this->GetAnimTransformList().PushBack(pAnimTrans);
315 }
316 return pAnimTrans;
317 }
318
319 void
DeleteAnimTransform(AnimTransform * pAnimTransform)320 Layout::DeleteAnimTransform(AnimTransform *pAnimTransform)
321 {
322 NW_NULL_ASSERT(pAnimTransform);
323
324 this->GetAnimTransformList().erase(pAnimTransform);
325 DeleteObj(pAnimTransform);
326 }
327
328 AnimTransform*
CreateAnimTransform(const void * animResBuf,ResourceAccessor * pResAcsr)329 Layout::CreateAnimTransform(
330 const void* animResBuf,
331 ResourceAccessor* pResAcsr
332 )
333 {
334 return CreateAnimTransform(AnimResource(animResBuf), pResAcsr);
335 }
336
337 AnimTransform*
CreateAnimTransform(const AnimResource & animRes,ResourceAccessor * pResAcsr)338 Layout::CreateAnimTransform(
339 const AnimResource& animRes,
340 ResourceAccessor* pResAcsr
341 )
342 {
343 const res::AnimationBlock *const pAnimBlock = animRes.GetResourceBlock();
344 if (! pAnimBlock)
345 {
346 return 0;
347 }
348
349 AnimTransform *const pAnimTrans = CreateAnimTransform();
350 if (pAnimTrans)
351 {
352 pAnimTrans->SetResource(pAnimBlock, pResAcsr);
353 }
354
355 return pAnimTrans;
356 }
357
358 void
BindAnimation(AnimTransform * pAnimTrans)359 Layout::BindAnimation(AnimTransform* pAnimTrans)
360 {
361 if (this->GetRootPane())
362 {
363 this->GetRootPane()->BindAnimation(pAnimTrans, true);
364 }
365 }
366
367 void
UnbindAnimation(AnimTransform * pAnimTrans)368 Layout::UnbindAnimation(AnimTransform* pAnimTrans)
369 {
370 if (this->GetRootPane())
371 {
372 this->GetRootPane()->UnbindAnimation(pAnimTrans, true);
373 }
374 }
375
376 void
UnbindAllAnimation()377 Layout::UnbindAllAnimation()
378 {
379 UnbindAnimation(0);
380 }
381
382 bool
BindAnimationAuto(const AnimResource & animRes,ResourceAccessor * pResAcsr)383 Layout::BindAnimationAuto(
384 const AnimResource& animRes,
385 ResourceAccessor* pResAcsr
386 )
387 {
388 if (! this->GetRootPane())
389 {
390 return false;
391 }
392
393 if (! animRes.GetResourceBlock())
394 {
395 return false;
396 }
397
398 AnimTransform *const pAnimTrans = CreateAnimTransform(); // AnimTransform オブジェクトの作成
399 if (pAnimTrans == NULL)
400 {
401 NW_WARNING(false, "Create AnimTransform failed.");
402 return false;
403 }
404
405 bool bResult = true;
406
407 // 最初に名前によるバインドを一通り行う
408 const u16 bindGroupNum = animRes.GetGroupNum();
409
410 u16 animNum = 0;
411 if (bindGroupNum == 0) // バインドする対象を限定していない
412 {
413 animNum = animRes.GetResourceBlock()->animContNum;
414
415 // バインドするアニメーション数を明示的に指定してリソースをセットします。
416 pAnimTrans->SetResource(animRes.GetResourceBlock(), pResAcsr, animNum);
417
418 const bool bRecursive = true;
419 this->GetRootPane()->BindAnimation(pAnimTrans, bRecursive, true/* bDisable */);
420 }
421 else // グループを指定してのバインド
422 {
423 const AnimationGroupRef *const groupRefs = animRes.GetGroupArray();
424 for (int grpIdx = 0; grpIdx < bindGroupNum; ++grpIdx)
425 {
426 // グループにあるペイン全てで必要になるアニメーションの個数を数えます。
427 Group *const pGroup = this->GetGroupContainer()->FindGroupByName(groupRefs[grpIdx].GetName());
428 if (pGroup == NULL)
429 {
430 NW_WARNING(false, "Group not found: %s", groupRefs[grpIdx].GetName());
431 bResult = false;
432 continue;
433 }
434
435 animNum += animRes.CalcAnimationNum(pGroup, animRes.IsDescendingBind());
436 }
437
438 // バインドするアニメーション数を明示的に指定してリソースをセットします。
439 pAnimTrans->SetResource(animRes.GetResourceBlock(), pResAcsr, animNum);
440
441 for (int grpIdx = 0; grpIdx < bindGroupNum; ++grpIdx)
442 {
443 // グループにあるペイン全てで必要になるアニメーションの個数を数えます。
444 Group *const pGroup = this->GetGroupContainer()->FindGroupByName(groupRefs[grpIdx].GetName());
445 if (pGroup == NULL)
446 {
447 continue;
448 }
449
450 // アニメーションをバインドします。
451 nw::lyt::BindAnimation(pGroup, pAnimTrans, animRes.IsDescendingBind(), true/* bDisable */);
452 }
453 }
454
455 const u16 animShareInfoNum = animRes.GetAnimationShareInfoNum();
456 if (animShareInfoNum > 0) // アニメーション共有によるバインド
457 {
458 const AnimationShareInfo *const animShareInfoAry = animRes.GetAnimationShareInfoArray();
459 NW_NULL_ASSERT(animShareInfoAry);
460
461 for (int i = 0; i < animShareInfoNum; ++i)
462 {
463 Pane *const pSrcPane = this->GetRootPane()->FindPaneByName(animShareInfoAry[i].GetSrcPaneName());
464 if (pSrcPane == NULL)
465 {
466 NW_WARNING(false, "Source pane of animation-share is not found: %s", animShareInfoAry[i].GetSrcPaneName());
467 bResult = false;
468 continue;
469 }
470
471 internal::AnimPaneTree animPaneTree(pSrcPane, animRes);
472 if (! animPaneTree.IsEnabled()) // 共有元ペインにアニメーションが無い?
473 {
474 continue;
475 }
476
477 Group *const pGroup = this->GetGroupContainer()->FindGroupByName(animShareInfoAry[i].GetTargetGroupName());
478 if (pGroup == NULL)
479 {
480 NW_WARNING(false, "Target group of animation-share is not found: %s", animShareInfoAry[i].GetTargetGroupName());
481 bResult = false;
482 continue;
483 }
484
485 PaneLinkList& paneList = pGroup->GetPaneList();
486 u32 animIdx = 0;
487 for (PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it, ++animIdx)
488 {
489 if (it->target != pSrcPane)
490 {
491 if (bindGroupNum > 0) // バインド対象の指定があり
492 {
493 // 関連グループに含まれてない場合は共有しない
494 const bool bInclude = IsIncludeAnimationGroupRef(
495 this->GetGroupContainer(),
496 animRes.GetGroupArray(),
497 bindGroupNum,
498 animRes.IsDescendingBind(),
499 it->target);
500
501 if (! bInclude)
502 {
503 continue;
504 }
505 }
506
507 // srcPaneNameと異なるペインに対してアニメーションをバインド
508 animPaneTree.Bind(this, it->target, pResAcsr);
509 }
510 }
511 }
512 }
513
514 return bResult;
515 }
516
517 void
SetAnimationEnable(AnimTransform * pAnimTrans,bool bEnable)518 Layout::SetAnimationEnable(
519 AnimTransform* pAnimTrans,
520 bool bEnable
521 )
522 {
523 if (this->GetRootPane())
524 {
525 this->GetRootPane()->SetAnimationEnable(pAnimTrans, bEnable, true);
526 }
527 }
528
529 void
CalculateMtx(const DrawInfo & drawInfo)530 Layout::CalculateMtx(const DrawInfo& drawInfo)
531 {
532 NW_LYT_STOPWATCH_MEASURE(-610, "nw::lyt::Layout::CalculateMtx");
533
534 if (! this->GetRootPane())
535 {
536 return;
537 }
538
539 this->GetRootPane()->CalculateMtx(drawInfo);
540 }
541
542 #ifdef NW_LYT_DMPGL_ENABLED
543 void
Draw(const DrawInfo & drawInfo)544 Layout::Draw(const DrawInfo& drawInfo)
545 {
546 NW_LYT_STOPWATCH_MEASURE(-630, "nw::lyt::Layout::Draw");
547
548 if (! this->GetRootPane())
549 {
550 return;
551 }
552
553 GraphicsResource* graphicsResource = drawInfo.GetGraphicsResource();
554 if (graphicsResource == NULL)
555 {
556 NW_WARNING(false, "GraphicsResource is not set.");
557 return;
558 }
559
560 graphicsResource->ResetGlState();
561 graphicsResource->ResetGlProgramState();
562
563 graphicsResource->SetProjectionMtx(drawInfo.GetProjectionMtx());
564
565 drawInfo.SetLayout(this);
566
567 this->GetRootPane()->Draw(drawInfo);
568
569 internal::FinalizeGraphics();
570
571 drawInfo.SetLayout(0);
572 }
573 #endif
574
575 void
Animate(u32 option)576 Layout::Animate(u32 option)
577 {
578 NW_LYT_STOPWATCH_MEASURE(-620, "nw::lyt::Layout::Animate");
579
580 if (! this->GetRootPane())
581 {
582 return;
583 }
584
585 this->GetRootPane()->Animate(option);
586 }
587
588 const ut::Rect
GetLayoutRect() const589 Layout::GetLayoutRect() const
590 {
591 return ut::Rect(- m_LayoutSize.width / 2, m_LayoutSize.height / 2, m_LayoutSize.width / 2, - m_LayoutSize.height / 2);
592 }
593
594 void
SetTagProcessor(font::TagProcessorBase<wchar_t> * pTagProcessor)595 Layout::SetTagProcessor(font::TagProcessorBase<wchar_t>* pTagProcessor)
596 {
597 SetTagProcessorImpl(this->GetRootPane(), pTagProcessor);
598 }
599
600 Pane*
BuildPaneObj(s32 kind,const void * dataPtr,const ResBlockSet & resBlockSet)601 Layout::BuildPaneObj(
602 s32 kind,
603 const void* dataPtr,
604 const ResBlockSet& resBlockSet
605 )
606 {
607 switch (kind)
608 {
609 case res::DATABLOCKKIND_PANE:
610 {
611 const res::Pane* pResPane = static_cast<const res::Pane*>(dataPtr);
612 return NewObj<Pane>(pResPane);
613 }
614 case res::DATABLOCKKIND_PICTURE:
615 {
616 const res::Picture* pResPic = static_cast<const res::Picture*>(dataPtr);
617 return NewObj<Picture>(pResPic, resBlockSet);
618 }
619 case res::DATABLOCKKIND_TEXTBOX:
620 {
621 const res::TextBox* pBlock = static_cast<const res::TextBox*>(dataPtr);
622 return NewObj<TextBox>(pBlock, resBlockSet);
623 }
624 case res::DATABLOCKKIND_WINDOW:
625 {
626 const res::Window* pBlock = static_cast<const res::Window*>(dataPtr);
627 return NewObj<Window>(pBlock, resBlockSet);
628 }
629 case res::DATABLOCKKIND_BOUNDING:
630 {
631 const res::Bounding* pResBounding = static_cast<const res::Bounding*>(dataPtr);
632 return NewObj<Bounding>(pResBounding, resBlockSet);
633 }
634 default:
635 NW_ASSERTMSG(false, "unknown data type");
636 break;
637 }
638
639 return 0;
640 }
641
642 } // namespace nw::lyt
643 } // namespace nw
644