1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     main.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 //------------------------------------------------------------------
19 // デモ: tagGroupBind
20 //
21 // 概要
22 //   アニメーション区間タグで設定されているグループごとに、
23 //   アニメーションを独立して制御するデモです。
24 //
25 //   アニメーション区間タグは、選択状態(select)と非選択状態(unselect)の
26 //   2つがあり、それぞれにグループ group_1, group_2 を指定しています。
27 //   2つのグループそれぞれにアニメーションの状態を管理するため、
28 //   AnimTransform を 4つ作成し、選択状態によって有効/無効を切り替えています。
29 //
30 // 操作
31 //   十字ボタンの操作でクロスラインが移動します。
32 //   クロスラインのクロスしている部分をペインに移動させると、
33 //   そのペインのアニメーションが変化します。
34 //
35 //------------------------------------------------------------------
36 
37 #include <nw/lyt.h>
38 #include <nw/demo.h>
39 
40 namespace
41 {
42 
43 typedef nw::ut::MoveArray<u8> File;
44 
45 /*---------------------------------------------------------------------------*
46   @brief 描画の初期設定を行います。
47 
48   @param width  画面の幅。
49   @param height  画面の高さ。
50  *---------------------------------------------------------------------------*/
51 void
InitDraw(int width,int height)52 InitDraw(int width, int height)
53 {
54     // カラーバッファ情報
55     // LCDの向きに合わせて、幅と高さを入れ替えています。
56     const nw::font::ColorBufferInfo colBufInfo =
57     {
58         height, width, PICA_DATA_DEPTH24_STENCIL8_EXT
59     };
60 
61     const u32 commands[] =
62     {
63         // ビューポートの設定
64         NW_FONT_CMD_SET_VIEWPORT(0, 0, colBufInfo.width, colBufInfo.height),
65 
66         // シザー処理を無効
67         NW_FONT_CMD_SET_DISABLE_SCISSOR(colBufInfo),
68 
69         // wバッファの無効化
70         // デプスレンジの設定
71         // ポリゴンオフセットの無効化
72         NW_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET(
73             0.0f,           // wScale : 0.0 でWバッファが無効
74             0.0f,           // depth range near
75             1.0f,           // depth range far
76             0,              // polygon offset units : 0.0 で ポリゴンオフセットが無効
77             colBufInfo),
78     };
79 
80     nngxAdd3DCommand(commands, sizeof(commands), true);
81 
82     static const u32 constCommands[] =
83     {
84         // カリングを無効
85         NW_FONT_CMD_SET_CULL_FACE(NW_FONT_CMD_CULL_FACE_DISABLE),
86 
87         // ステンシルテストを無効
88         NW_FONT_CMD_SET_DISABLE_STENCIL_TEST(),
89 
90         // デプステストを無効
91         // カラーバッファの全ての成分を書き込み可
92         NW_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK(
93             false,  // isDepthTestEnabled
94             0,      // depthFunc
95             true,   // depthMask
96             true,   // red
97             true,   // green
98             true,   // blue
99             true),  // alpha
100 
101         // アーリーデプステストを無効
102         NW_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST(false),
103 
104         // フレームバッファアクセス制御
105         NW_FONT_CMD_SET_FBACCESS(
106             true,   // colorRead
107             true,   // colorWrite
108             false,  // depthRead
109             false,  // depthWrite
110             false,  // stencilRead
111             false), // stencilWrite
112     };
113 
114     nngxAdd3DCommand(constCommands, sizeof(constCommands), true);
115 }
116 
117 /*---------------------------------------------------------------------------*
118   @brief アニメーションのセットアップを行います。
119 
120   @details
121   アニメーション区間タグで指定されているグループごとに
122   AnimTransform オブジェクトを作成し、バインドします。
123 
124   無駄な AnimationLink の確保を避けるため、あらかじめバインドに必要な
125   アニメーションの数を調べてからAnimTransform を構築しています。
126 
127   @param pLayout  レイアウトです。
128   @param animRes  アニメーションリソースです。
129   @param groupRef  アニメーション区間タグのグループ情報です。
130   @param pResAccessor リソースアクセサです。
131 
132   @return  作成した AnimTransform オブジェクトへのポインタを返します。
133  *---------------------------------------------------------------------------*/
134 nw::lyt::AnimTransform*
SetupAnimTransform(nw::lyt::Layout * pLayout,const nw::lyt::AnimResource & animRes,const nw::lyt::AnimationGroupRef & groupRef,nw::lyt::ResourceAccessor * pResAccessor)135 SetupAnimTransform(
136     nw::lyt::Layout*                  pLayout,
137     const nw::lyt::AnimResource&      animRes,
138     const nw::lyt::AnimationGroupRef& groupRef,
139     nw::lyt::ResourceAccessor*        pResAccessor
140 )
141 {
142     // グループにあるペイン全てで必要になるアニメーションの個数を数えます。
143     nw::lyt::Group *const pGroup = pLayout->GetGroupContainer()->FindGroupByName(groupRef.GetName());
144     NW_NULL_ASSERT(pGroup);
145 
146     const u16 animNum = animRes.CalcAnimationNum(pGroup, animRes.IsDescendingBind());
147 
148     // nw::lyt::AnimTransform オブジェクトを作成し、
149     // バインドするアニメーション数を明示的に指定してリソースをセットします。
150     nw::lyt::AnimTransform *const pAnimTrans = pLayout->CreateAnimTransform();
151     NW_NULL_ASSERT(pAnimTrans);
152 
153     pAnimTrans->SetResource(animRes.GetResourceBlock(), pResAccessor, animNum);
154 
155     // アニメーションをバインドします。
156     BindAnimation(pGroup, pAnimTrans, animRes.IsDescendingBind());
157 
158     return pAnimTrans;
159 }
160 
161 /*---------------------------------------------------------------------------*
162   @brief モデルビュー行列と射影行列を設定します。
163 
164   @param drawInfo 描画情報です。
165   @param layout レイアウトです。
166  *---------------------------------------------------------------------------*/
167 void
SetupCamera(nw::lyt::DrawInfo & drawInfo,const nw::lyt::Layout & layout)168 SetupCamera(nw::lyt::DrawInfo& drawInfo, const nw::lyt::Layout& layout)
169 {
170     nw::ut::Rect layoutRect = layout.GetLayoutRect();
171 
172     f32 znear = 0.f;
173     f32 zfar = 500.f;
174 
175     // 射影行列を正射影に設定
176     // (Layoutデータは横向きなので向きを変換する)
177     nw::math::MTX44 projMtx;
178     nw::math::MTX44Ortho(
179         &projMtx,
180         layoutRect.bottom,  // left
181         layoutRect.top,     // right
182         -layoutRect.right,  // bottom
183         -layoutRect.left,   // top
184         znear,
185         zfar);
186     drawInfo.SetProjectionMtx(projMtx);
187 
188     // モデルビュー行列を設定
189     // (Layoutデータは横向きなので画面の上方向はレイアウトの-X方向)
190     nw::math::VEC3 pos(0, 0, 1);
191     nw::math::VEC3 up(-1, 0, 0);
192     nw::math::VEC3 target(0, 0, 0);
193 
194     nw::math::MTX34 viewMtx;
195     nw::math::MTX34LookAt(&viewMtx, &pos, &up, &target);
196     drawInfo.SetViewMtx(viewMtx);
197 }
198 
199 /*---------------------------------------------------------------------------*
200   @brief カーソルの位置をレイアウトの座標系で取得します。
201 
202   @param pLayout  レイアウトです。
203 
204   @return カーソル位置を返します。
205  *---------------------------------------------------------------------------*/
206 const nw::math::VEC2
GetCursorPosition(nw::lyt::Layout * pLayout)207 GetCursorPosition(nw::lyt::Layout* pLayout)
208 {
209     const nw::ut::Rect& layoutRect = pLayout->GetLayoutRect();
210     const nw::math::VEC2 center(
211         (layoutRect.left  + layoutRect.right ) / 2,
212         (layoutRect.top   + layoutRect.bottom) / 2
213         );
214 
215     nw::math::VEC2 curPos;
216 
217     // カーソルの座標系をレイアウトの座標系に変換します。
218     const nw::ut::Rect cursorRect(-0.5, 0.5, 0.5, -0.5); // LTRB
219     nw::demo::Pad& pad = *nw::demo::PadFactory::GetPad();
220     const nw::math::VEC2 stick = pad.GetAnalogStick();
221     curPos.x = center.x + stick.x / (cursorRect.right - cursorRect.left  ) * (layoutRect.right - layoutRect.left  );
222     curPos.y = center.y + stick.y / (cursorRect.top   - cursorRect.bottom) * (layoutRect.top   - layoutRect.bottom);
223     // NW_LOG("curPos %f, %f\n", curPos.x, curPos.y);
224     return curPos;
225 }
226 
227 /*---------------------------------------------------------------------------*
228   @brief カーソルの位置をレイアウトに反映します。
229 
230   @param pLayout レイアウトです。
231   @param curPos レイアウトの座標系におけるカーソルの位置です。
232  *---------------------------------------------------------------------------*/
233 void
ApplyCursorPosition(nw::lyt::Layout * pLayout,const nw::math::VEC2 & curPos)234 ApplyCursorPosition(nw::lyt::Layout* pLayout, const nw::math::VEC2& curPos)
235 {
236     nw::lyt::Pane* pCrossBar = pLayout->GetRootPane()->FindPaneByName("CrossBar", true);
237     if (pCrossBar)
238     {
239         pCrossBar->SetTranslate(curPos);
240     }
241 }
242 
243 /*---------------------------------------------------------------------------*
244   @brief 指定されたペインおよびその子孫となるペインの中で、
245          Bounding ペインを探します。
246 
247   @param pPane  探索の起点となるペインです。
248 
249   @return 見つかった場合は、そのペインのポインタを返します。
250           見つからなかった場合は、NULLを返します。
251  *---------------------------------------------------------------------------*/
252 nw::lyt::Bounding*
FindBoundingPane(nw::lyt::Pane * pPane)253 FindBoundingPane(nw::lyt::Pane* pPane)
254 {
255     // Bound ペインか
256     nw::lyt::Bounding* pBounding = NULL;
257     if ((pBounding = nw::ut::DynamicCast<nw::lyt::Bounding*>(pPane)) != NULL)
258     {
259         return pBounding;
260     }
261     else
262     {
263         // 子供のチェック
264         for (nw::lyt::PaneList::Iterator it = pPane->GetChildList().GetBeginIter(); it != pPane->GetChildList().GetEndIter(); ++it)
265         {
266             if ((pBounding = FindBoundingPane(&(*it))) != NULL)
267             {
268                 return pBounding;
269             }
270         }
271     }
272 
273     return 0;
274 }
275 
276 /*---------------------------------------------------------------------------*
277   @brief 指定されたグループに含まれるペインの子孫の中ある Bounding ペインが
278          指定された点を含むかどうかをチェックします。
279          (ペインがXおよびY軸周りで回転している場合は考慮していません。)
280 
281   @param pGroup  探すグループです。
282   @param pos     探す点です。
283 
284   @return 含む場合は真を返します。
285  *---------------------------------------------------------------------------*/
286 bool
TestHit(nw::lyt::Group * pGroup,const nw::math::VEC2 & pos)287 TestHit(
288     nw::lyt::Group*           pGroup,
289     const nw::math::VEC2&     pos
290 )
291 {
292     nw::lyt::PaneLinkList& paneList = pGroup->GetPaneList();
293     for (nw::lyt::PaneLinkList::Iterator it = paneList.GetBeginIter(); it != paneList.GetEndIter(); ++it)
294     {
295         nw::lyt::Bounding *const pBounding = FindBoundingPane(it->target);
296         NW_NULL_ASSERT(pBounding);
297 
298         if (nw::lyt::IsContain(pBounding, pos))
299         {
300             return true;
301         }
302     }
303 
304     return false;
305 }
306 
307 /*---------------------------------------------------------------------------*
308   @brief アニメーションのフレームを更新します。
309 
310   @details
311   アニメーションデータがループするアニメーションであること仮定しています。
312 
313   @param pAnimTrans  フレーム値の更新対象です。
314  *---------------------------------------------------------------------------*/
315 void
UpdateAnimationFrame(nw::lyt::AnimTransform * pAnimTrans)316 UpdateAnimationFrame(nw::lyt::AnimTransform* pAnimTrans)
317 {
318     f32 animFrame = pAnimTrans->GetFrame() + 1.0f;
319     if (animFrame >= pAnimTrans->GetFrameSize())
320     {
321         animFrame -= pAnimTrans->GetFrameSize();
322     }
323     pAnimTrans->SetFrame(animFrame);
324 }
325 
326 }   // namespace
327 
328 /*---------------------------------------------------------------------------*
329   @brief サンプルのメイン関数です。
330  *---------------------------------------------------------------------------*/
331 void
nnMain()332 nnMain()
333 {
334     nw::demo::SimpleApp& demoApp = nw::demo::SimpleApp::GetInstance();
335     demoApp.Initialize();
336 
337     nw::lyt::Initialize(&demoApp.GetAllocator(), &demoApp.GetDeviceAllocator());
338 
339     nw::lyt::Layout *const pLayout = new nw::lyt::Layout();
340 
341     // レイアウトのバイナリリソース(アーカイブ)を読み込み。
342     File fileLayout = nw::demo::Utility::LoadFile(
343         &demoApp.GetDeviceAllocator(), NW_DEMO_FILE_PATH(L"layout.arc"), 128);
344 
345     if (fileLayout.empty())
346     {
347         NW_FATAL_ERROR("can not open layout archive.\n");
348     }
349 
350     // バイナリリソースのルートディレクトリを指定してリソースアクセサを生成。
351     nw::lyt::ArcResourceAccessor* pResAccessor = new nw::lyt::ArcResourceAccessor;
352     if (!pResAccessor->Attach(fileLayout.begin(), "."))
353     {
354         NW_FATAL_ERROR("can not attach layout archive.\n");
355     }
356 
357     // レイアウトリソースの読み込み
358     {
359         const void* lytRes = pResAccessor->GetResource(0, "tagGroupBind.bclyt");
360         NW_NULL_ASSERT(lytRes);
361         pLayout->Build(lytRes, pResAccessor);
362     }
363 
364     enum
365     {
366         ANIMTYPE_UNSELECT,
367         ANIMTYPE_SELECT,
368 
369         ANIMTYPE_MAX
370     };
371 
372     // アニメーションファイル
373     const char *const brlanFileNames[ANIMTYPE_MAX] =
374     {
375         "tagGroupBind_unselect.bclan",
376         "tagGroupBind_select.bclan",
377     };
378 
379     nw::lyt::AnimResource animRess[ANIMTYPE_MAX];
380 
381     // アニメーションリソースの取得します。
382     // 同時に、brlanファイル内のグループの総数を求めます。
383     int animTransNum = 0;
384     for (int i = 0; i < ANIMTYPE_MAX; ++i)
385     {
386         const void* lpaRes = pResAccessor->GetResource(0, brlanFileNames[i]);
387         NW_NULL_ASSERT(lpaRes);
388         animRess[i].Set(lpaRes);
389 
390         NW_ASSERT(animRess[i].GetGroupNum() > 0);
391         animTransNum += animRess[i].GetGroupNum();
392     }
393 
394     // グループ毎に nw::lyt::AnimTransform を構築するため、
395     // グループの総数分 nw::lyt::AnimTransform ポインタのメモリを確保します。
396     nw::lyt::AnimTransform* *const animTranss = new nw::lyt::AnimTransform* [animTransNum];
397 
398     // アニメーションのバインドを行います。
399     {
400         int animTransIdx = 0;
401         for (int anmIdx = 0; anmIdx < ANIMTYPE_MAX; ++anmIdx)
402         {
403             const nw::lyt::AnimationGroupRef *const groupRefs = animRess[anmIdx].GetGroupArray();
404 
405             for (int grpIdx = 0; grpIdx < animRess[anmIdx].GetGroupNum(); ++grpIdx)
406             {
407                 animTranss[animTransIdx++] = SetupAnimTransform(pLayout, animRess[anmIdx], groupRefs[grpIdx], pResAccessor);
408             }
409         }
410     }
411 
412     nw::lyt::GraphicsResource graphicsResource;
413     // グローバルなリソースファイルを読み込みます。
414     {
415         graphicsResource.StartSetup();
416         const wchar_t* resourcePath = 0;
417         for (int i = 0;
418              (resourcePath = graphicsResource.GetResourcePath(i)) != NULL;
419              ++i)
420         {
421             File file = nw::demo::Utility::LoadFile(&demoApp.GetAllocator(), resourcePath);
422 
423             if (file.empty())
424             {
425                 NW_FATAL_ERROR("can not read lyt resource file.");
426             }
427 
428             graphicsResource.SetResource(i, file.begin(), file.size(), false);
429         }
430 
431         graphicsResource.FinishSetup();
432     }
433 
434     nw::lyt::DrawInfo drawInfo;
435     drawInfo.SetGraphicsResource(&graphicsResource);
436     nw::math::VEC2 curPos(0.f, 0.f);
437 
438     nw::lyt::Drawer drawer;
439     drawer.Initialize(graphicsResource);
440 
441     const nw::ut::FloatColor clearColor(0.3f, 0.3f, 0.3f, 1.0f);
442     const f32 clearDepth = 0.0f;
443 
444     bool loop = true;
445     while (loop)
446     {
447         nw::demo::PadFactory::GetPad()->Update();
448 
449         demoApp.SetRenderingTarget(demoApp.DISPLAY0);
450         {
451             demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth);
452 
453             InitDraw(demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT);
454 
455             SetupCamera(drawInfo, *pLayout);
456 
457             curPos = GetCursorPosition(pLayout);
458             ApplyCursorPosition(pLayout, curPos);
459 
460             pLayout->Animate();
461             pLayout->CalculateMtx(drawInfo);
462 
463             drawer.DrawBegin(drawInfo);
464             drawer.Draw(pLayout, drawInfo);
465             drawer.DrawEnd(drawInfo);
466 
467             // カーソル位置をレイアウト座標系からビュー座標系に変換します。
468             {
469                 nw::math::VEC3 tmp(curPos.x, curPos.y, 0.0f);
470                 nw::math::VEC3Transform(&tmp, &drawInfo.GetViewMtx(), &tmp);
471                 curPos = nw::math::VEC2(tmp.x, tmp.y);
472             }
473 
474             // nw::lyt::Layout::CalculateMtx() を呼び出した後の行列を利用してヒットチェックを行います。
475             // グループ単位でペインのヒットチェックを行い、アニメーションの有効/無効を切り替えます。
476             int animTransIdx = 0;
477             for (int anmIdx = 0; anmIdx < ANIMTYPE_MAX; ++anmIdx)
478             {
479                 const nw::lyt::AnimationGroupRef *const groupRefs = animRess[anmIdx].GetGroupArray();
480 
481                 for (int grpIdx = 0; grpIdx < animRess[anmIdx].GetGroupNum(); ++grpIdx)
482                 {
483                     nw::lyt::Group *const pGroup = pLayout->GetGroupContainer()->FindGroupByName(groupRefs[grpIdx].GetName());
484 
485                     const bool bSelect = TestHit(pGroup, curPos);
486                     const bool bEnable = anmIdx == ANIMTYPE_UNSELECT ? ! bSelect: bSelect;
487 
488                     // アニメーションの有効/無効を切り替えます。
489                     nw::lyt::SetAnimationEnable(pGroup, animTranss[animTransIdx], bEnable, animRess[anmIdx].IsDescendingBind());
490 
491                     // アニメーションが有効な場合、フレームを更新しておきます。
492                     if (bEnable)
493                     {
494                         UpdateAnimationFrame(animTranss[animTransIdx]);
495                     }
496                     ++animTransIdx;
497                 }
498             }
499         }
500 
501         demoApp.SetRenderingTarget(demoApp.DISPLAY1);
502         {
503             demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth);
504         }
505 
506         demoApp.SwapBuffer(demoApp.DISPLAY_BOTH);
507     }
508 
509     delete [] animTranss;
510 
511     delete pLayout;
512 
513     delete pResAccessor;
514 }
515 
516