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