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