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