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 // デモ: orthoStereo
18 //
19 // 概要
20 // レイアウトを正射影で立体視するサンプルです。
21 //
22 //------------------------------------------------------------------
23
24 #include <nn/os.h>
25 #include <nn/fs.h>
26
27 #include <nw/types.h>
28 #include <nw/sdk.h>
29 #include <nw/demo.h>
30 #include <nw/dev.h>
31 #include <nw/gfx.h>
32 #include <nw/lyt.h>
33 #include <nw/ut.h>
34
35 namespace
36 {
37
38 nw::demo::RenderSystem* s_pRenderSystem = NULL;
39 nw::gfx::IRenderTarget* s_pRenderTarget = NULL;
40 nw::gfx::IRenderTarget* s_pRenderTargetLower = NULL;
41
42 //----------------------------------------
43 // メモリ関係
44
45 // デバイスメモリを確保するためのアロケータです。
46 nw::demo::DemoAllocator s_DeviceAllocator;
47
48 //----------------------------------------
49 typedef nw::ut::MoveArray<u8> File;
50
51 nn::ulcd::CTR::StereoCamera s_StereoCamera;
52
53 f32 s_DepthLevel = 10.0f; // LCD 上に配置したい場所(基準面)までのカメラからの距離
54 f32 s_StereoFactor = 1.0f; // 立体具合の調整係数(0で視差が無くなり、1で標準となります。)
55
56 /*---------------------------------------------------------------------------*
57 @brief グラフィックス関連の初期化を行います。
58 *---------------------------------------------------------------------------*/
59 void
InitializeGraphics()60 InitializeGraphics()
61 {
62 nw::demo::RenderSystem::Description renderDesc;
63
64 nw::demo::DisplayBufferSwapper::Description& upperScreenDesc =
65 renderDesc.upperScreenDescription;
66
67 nw::demo::DisplayBufferSwapper::Description& lowerScreenDesc =
68 renderDesc.lowerScreenDescription;
69
70 renderDesc.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO;
71
72 s_pRenderSystem = nw::demo::RenderSystem::Create(
73 &s_DeviceAllocator,
74 renderDesc);
75
76 NW_ASSERT(s_pRenderSystem != NULL);
77
78 s_pRenderTarget = nw::gfx::IRenderTarget::Builder()
79 .BufferSize(upperScreenDesc.height, upperScreenDesc.width)
80 .ColorFormat(renderDesc.renderColorFormat)
81 .Create(&s_DeviceAllocator);
82
83 NW_ASSERT(s_pRenderTarget != NULL);
84
85 s_pRenderTargetLower = nw::gfx::IRenderTarget::Builder()
86 .BufferSize(lowerScreenDesc.height, lowerScreenDesc.width)
87 .ColorFormat(renderDesc.renderColorFormat)
88 .Create(&s_DeviceAllocator);
89
90 NW_ASSERT(s_pRenderTargetLower != NULL);
91
92 NW_GL_ASSERT();
93 }
94
95 //---------------------------------------------------------------------------
96 //! @brief グラフィックス関連の後始末を行います。
97 //---------------------------------------------------------------------------
98 void
TerminateGraphics()99 TerminateGraphics()
100 {
101 nw::gfx::SafeDestroy(s_pRenderSystem);
102 nw::gfx::SafeDestroy(s_pRenderTarget);
103 nw::gfx::SafeDestroy(s_pRenderTargetLower);
104 }
105
106 /*---------------------------------------------------------------------------*
107 @brief 描画の初期設定を行います。
108
109 @param width 画面の幅。
110 @param height 画面の高さ。
111 *---------------------------------------------------------------------------*/
112 void
InitDraw(int width,int height)113 InitDraw(int width, int height)
114 {
115 // カラーバッファ情報
116 // LCDの向きに合わせて、幅と高さを入れ替えています。
117 const nw::font::ColorBufferInfo colBufInfo =
118 {
119 height, width, PICA_DATA_DEPTH24_STENCIL8_EXT
120 };
121
122 const u32 commands[] =
123 {
124 // ビューポートの設定
125 NW_FONT_CMD_SET_VIEWPORT(0, 0, colBufInfo.width, colBufInfo.height),
126
127 // シザー処理を無効
128 NW_FONT_CMD_SET_DISABLE_SCISSOR(colBufInfo),
129
130 // wバッファの無効化
131 // デプスレンジの設定
132 // ポリゴンオフセットの無効化
133 NW_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET(
134 0.0f, // wScale : 0.0 でWバッファが無効
135 0.0f, // depth range near
136 1.0f, // depth range far
137 0, // polygon offset units : 0.0 で ポリゴンオフセットが無効
138 colBufInfo),
139 };
140
141 nngxAdd3DCommand(commands, sizeof(commands), true);
142
143 static const u32 constCommands[] =
144 {
145 // カリングを無効
146 NW_FONT_CMD_SET_CULL_FACE(NW_FONT_CMD_CULL_FACE_DISABLE),
147
148 // ステンシルテストを無効
149 NW_FONT_CMD_SET_DISABLE_STENCIL_TEST(),
150
151 // デプステストを無効
152 // カラーバッファの全ての成分を書き込み可
153 NW_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK(
154 false, // isDepthTestEnabled
155 0, // depthFunc
156 true, // depthMask
157 true, // red
158 true, // green
159 true, // blue
160 true), // alpha
161
162 // アーリーデプステストを無効
163 NW_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST(false),
164
165 // フレームバッファアクセス制御
166 NW_FONT_CMD_SET_FBACCESS(
167 true, // colorRead
168 true, // colorWrite
169 false, // depthRead
170 false, // depthWrite
171 false, // stencilRead
172 false), // stencilWrite
173 };
174
175 nngxAdd3DCommand(constCommands, sizeof(constCommands), true);
176 }
177
178 //---------------------------------------------------------------------------
179 //! @brief モデルビュー行列と射影行列を設定します。
180 //!
181 //! @param[in] drawInfo 描画情報です。
182 //! @param[in] layout レイアウトです。
183 //!
184 //! @return 視差の半分の値を返します(液晶のドット単位)。
185 //---------------------------------------------------------------------------
186 void
SetupCamera(nw::lyt::DrawInfo & drawInfo,const nw::lyt::Layout & layout)187 SetupCamera(
188 nw::lyt::DrawInfo& drawInfo,
189 const nw::lyt::Layout& layout
190 )
191 {
192 nw::ut::Rect layoutRect = layout.GetLayoutRect();
193
194 f32 znear = 0.f;
195 f32 zfar = 500.f;
196
197 // 射影行列を正射影に設定
198 // (Layoutデータは横向きなので向きを変換する)
199 nw::math::MTX44 projMtx;
200 nw::math::MTX44OrthoPivot(
201 &projMtx,
202 layoutRect.left, // left
203 layoutRect.right, // right
204 layoutRect.bottom, // bottom
205 layoutRect.top, // top
206 znear,
207 zfar,
208 nw::math::PIVOT_UPSIDE_TO_TOP);
209 drawInfo.SetProjectionMtx(projMtx);
210
211 // モデルビュー行列を設定
212 nw::math::VEC3 pos(0, 0, s_DepthLevel);
213 nw::math::VEC3 up(0, 1, 0);
214 nw::math::VEC3 target(0, 0, 0);
215
216 nw::math::MTX34 viewMtx;
217 nw::math::MTX34LookAt(&viewMtx, &pos, &up, &target);
218 drawInfo.SetViewMtx(viewMtx);
219 }
220
221 //---------------------------------------------------------------------------
222 //! @brief 視差の半分の値を液晶のドット単位で求めます。
223 //!
224 //! @param[in] drawInfo 描画情報です。
225 //!
226 //! @return 視差の半分の値を返します(液晶のドット単位)。
227 //---------------------------------------------------------------------------
228 f32
CalcParallaxDot(nw::lyt::DrawInfo & drawInfo)229 CalcParallaxDot(nw::lyt::DrawInfo& drawInfo)
230 {
231 // 左右の視差に対応した絵を描画するための射影行列、ビュー行列を計算する
232 nn::math::MTX34 view = drawInfo.GetViewMtx();
233 s_StereoCamera.SetBaseCamera(&view);
234
235 nn::math::MTX44 projL, projR;
236 nn::math::MTX34 viewL, viewR;
237 s_StereoCamera.CalculateMatrices(
238 &projL,
239 &viewL,
240 &projR,
241 &viewR,
242 s_DepthLevel,
243 s_StereoFactor,
244 nn::math::PIVOT_UPSIDE_TO_TOP);
245
246 // 視差の半分の値を液晶のドット単位で求める。
247 f32 wkParallax = s_StereoCamera.GetCoefficientForParallax();
248 return wkParallax * nw::demo::SimpleApp::DISPLAY0_WIDTH;
249 }
250
251 //---------------------------------------------------------------------------
252 //! @brief コマンドリストを作成します。
253 //!
254 //! @param[in] bufSize 3Dコマンドバッファのサイズです。
255 //! @param[in] requestCount コマンドリクエストの個数です。
256 //!
257 //! @return コマンドリストIDを返します。
258 //---------------------------------------------------------------------------
259 GLuint
CrateCmdList(GLsizei bufSize,GLsizei requestCount)260 CrateCmdList(
261 GLsizei bufSize,
262 GLsizei requestCount
263 )
264 {
265 // カレントを退避
266 GLuint crntCmdListId;
267 nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, reinterpret_cast<GLint*>(&crntCmdListId));
268
269 // 生成
270 GLuint lytCmdListId;
271 nngxGenCmdlists(1, &lytCmdListId);
272 nngxBindCmdlist(lytCmdListId);
273 nngxCmdlistStorage(bufSize, requestCount);
274
275 // カレントを復帰
276 nngxBindCmdlist(crntCmdListId);
277
278 return lytCmdListId;
279 }
280
281 //---------------------------------------------------------------------------
282 //! @brief コマンドリストの保存を開始します。
283 //!
284 //! @param[in] cmdListId 保存するコマンドリストのID。
285 //!
286 //! @return 現在のコマンドリストIDを返します。
287 //---------------------------------------------------------------------------
288 GLuint
StartCmdListSave(GLuint cmdListId)289 StartCmdListSave(GLuint cmdListId)
290 {
291 // カレントを退避
292 GLuint crntCmdListId;
293 nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, reinterpret_cast<GLint*>(&crntCmdListId));
294
295 nngxBindCmdlist(cmdListId); // バインド
296 nngxClearCmdlist(); // クリア
297 nngxStartCmdlistSave(); // セーブ開始
298
299 return crntCmdListId;
300 }
301
302 //---------------------------------------------------------------------------
303 //! @brief 保存したコマンドリストの情報を保存する構造体。
304 //---------------------------------------------------------------------------
305 struct CmdListInfo
306 {
307 GLuint bufferOffset;
308 GLsizei bufferSize;
309 GLuint requestId;
310 GLsizei requestSize;
311 };
312
313 //---------------------------------------------------------------------------
314 //! @brief コマンドリストの保存を終了します。
315 //!
316 //! @param[out] pCmdListInfo コマンドリストの情報を保存する構造体へのポインタ。
317 //! @param[in] cmdListId 元に戻すコマンドリストのID。
318 //---------------------------------------------------------------------------
319 void
StopCmdListSave(CmdListInfo * pCmdListInfo,GLuint cmdListId)320 StopCmdListSave(
321 CmdListInfo* pCmdListInfo,
322 GLuint cmdListId
323 )
324 {
325 nngxStopCmdlistSave(
326 &pCmdListInfo->bufferOffset,
327 &pCmdListInfo->bufferSize,
328 &pCmdListInfo->requestId,
329 &pCmdListInfo->requestSize);
330 NW_GL_ASSERT();
331
332 // カレントを復帰
333 nngxBindCmdlist(cmdListId);
334 }
335
336 //---------------------------------------------------------------------------
337 //! @brief 保存されたコマンドリストを使用します。
338 //!
339 //! @param[in] cmdListId コマンドリストのID。
340 //! @param[in] cmdListInfo コマンドリストの情報を保存する構造体。
341 //---------------------------------------------------------------------------
342 void
UseSavedCmdlist(GLuint cmdListId,const CmdListInfo & cmdListInfo)343 UseSavedCmdlist(
344 GLuint cmdListId,
345 const CmdListInfo& cmdListInfo
346 )
347 {
348 nngxUseSavedCmdlist(
349 cmdListId,
350 cmdListInfo.bufferOffset,
351 cmdListInfo.bufferSize,
352 cmdListInfo.requestId,
353 cmdListInfo.requestSize,
354 0,
355 GL_TRUE);
356 }
357
358 } // namespace {anonymous}
359
360 //---------------------------------------------------------------------------
361 //! @brief サンプルのメイン関数です。
362 //---------------------------------------------------------------------------
363 void
nnMain()364 nnMain()
365 {
366 nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator);
367
368 nw::demo::PadFactory::Initialize(&s_DeviceAllocator);
369
370 InitializeGraphics();
371
372 // レイアウトライブラリの初期化。
373 // デモでは全てのメモリをデバイスメモリから確保していますので、
374 // 同じアロケータを渡しています。
375 // ヒープメモリと区別して扱う場合は第2引数は必ずデバイスメモリを指定してください。
376 nw::lyt::Initialize(&s_DeviceAllocator, &s_DeviceAllocator);
377
378 // レイアウトのバイナリリソース(アーカイブ)を読み込み。
379 File resLayout = nw::demo::Utility::LoadFile(
380 &s_DeviceAllocator, NW_DEMO_FILE_PATH(L"layout.arc"), 128);
381
382 if (resLayout.empty())
383 {
384 NW_FATAL_ERROR("can not open layout archive.\n");
385 }
386
387 // バイナリリソースのルートディレクトリを指定してリソースアクセサを生成。
388 nw::lyt::ArcResourceAccessor* pResAccessor = new nw::lyt::ArcResourceAccessor;
389 if (!pResAccessor->Attach(resLayout.begin(), "."))
390 {
391 NW_FATAL_ERROR("can not attach layout archive.\n");
392 }
393
394 nw::lyt::Layout* pLayout = new nw::lyt::Layout();
395
396 // レイアウトリソースの読み込み
397 {
398 const void* lytRes = pResAccessor->GetResource(0, "orthoStereo.bclyt");
399 NW_NULL_ASSERT(lytRes);
400 pLayout->Build(lytRes, pResAccessor);
401 }
402
403 nw::lyt::GraphicsResource graphicsResource;
404
405 // グローバルなリソースファイルを読み込みます。
406 {
407 graphicsResource.StartSetup();
408 const wchar_t* resourcePath = 0;
409 for (int i = 0;
410 (resourcePath = graphicsResource.GetResourcePath(i)) != NULL;
411 ++i)
412 {
413 File resource = nw::demo::Utility::LoadFile(&s_DeviceAllocator, resourcePath);
414
415 if (resource.empty())
416 {
417 NW_FATAL_ERROR("can not read lyt resource file.");
418 }
419
420 graphicsResource.SetResource(i, resource.begin(), resource.size(), false);
421 }
422
423 graphicsResource.FinishSetup();
424 }
425
426 nw::lyt::DrawInfo drawInfo;
427 drawInfo.SetGraphicsResource(&graphicsResource);
428
429 nw::lyt::Drawer drawer;
430 drawer.Initialize(graphicsResource);
431
432 // 立体視のためのカメラの初期化
433 s_StereoCamera.Initialize();
434 s_StereoCamera.SetBaseFrustum(
435 -0.04f,
436 0.04f,
437 -0.04f * nw::demo::SimpleApp::DISPLAY0_HEIGHT / nw::demo::SimpleApp::DISPLAY0_WIDTH,
438 0.04f * nw::demo::SimpleApp::DISPLAY0_HEIGHT / nw::demo::SimpleApp::DISPLAY0_WIDTH,
439 0.2f,
440 30.f);
441
442 // レイアウト描画用のコマンドリストの作成
443 const GLuint lytCmdListId = CrateCmdList(2048, 1);
444
445 bool loop = true;
446 while (loop)
447 {
448 SetupCamera(drawInfo, *pLayout);
449 NW_GL_ASSERT();
450
451 pLayout->Animate();
452 pLayout->CalculateMtx(drawInfo);
453 NW_GL_ASSERT();
454
455 // レイアウトの描画コマンドを生成
456 CmdListInfo lytCmdListInfo;
457 const GLuint crntCmdListId = StartCmdListSave(lytCmdListId);
458 drawer.DrawBegin(nw::lyt::Drawer::DONT_USE_SETUP_COMMAND);
459 drawer.Draw(pLayout, drawInfo);
460 drawer.DrawEnd(nw::lyt::Drawer::DONT_USE_SETUP_COMMAND);
461 StopCmdListSave(&lytCmdListInfo, crntCmdListId);
462
463 s_pRenderSystem->SetRenderTarget(s_pRenderTarget);
464 NW_GL_ASSERT();
465
466 // 視差の半分の値を液晶のドット単位で求めます。
467 const f32 halfParallaxDot = CalcParallaxDot(drawInfo);
468
469 // 上画面(左目用)
470 {
471 s_pRenderSystem->ClearBuffer(
472 nw::ut::FloatColor(0.2f, 0.2f, 0.2f, 0.0f));
473
474 InitDraw(
475 nw::demo::SimpleApp::DISPLAY0_WIDTH,
476 nw::demo::SimpleApp::DISPLAY0_HEIGHT);
477
478 // Drawerを使ってレイアウトを描画します。
479 drawer.SetParallax(-halfParallaxDot, s_StereoCamera.GetDistanceToLevel());
480 drawer.DrawBegin(drawInfo);
481 UseSavedCmdlist(lytCmdListId, lytCmdListInfo);
482 drawer.DrawEnd();
483
484 s_pRenderSystem->TransferBuffer(nw::demo::UPPER_SCREEN);
485 }
486
487 // 上画面(右目用)
488 {
489 s_pRenderSystem->ClearBuffer(
490 nw::ut::FloatColor(0.2f, 0.2f, 0.2f, 0.0f));
491
492 InitDraw(
493 nw::demo::SimpleApp::DISPLAY0_WIDTH,
494 nw::demo::SimpleApp::DISPLAY0_HEIGHT);
495
496 // Drawerを使ってレイアウトを描画します。
497 drawer.SetParallax( halfParallaxDot, s_StereoCamera.GetDistanceToLevel());
498 drawer.DrawBegin(drawInfo);
499 UseSavedCmdlist(lytCmdListId, lytCmdListInfo);
500 drawer.DrawEnd();
501
502 s_pRenderSystem->TransferBuffer(nw::demo::EXTENSION_SCREEN);
503 }
504
505 s_pRenderSystem->SetRenderTarget(s_pRenderTargetLower);
506
507 // 下画面
508 {
509 s_pRenderSystem->ClearBuffer(
510 nw::ut::FloatColor(0.1f, 0.1f, 0.1f, 0.0f));
511
512 s_pRenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN);
513 }
514
515 s_pRenderSystem->PresentBuffer(nw::demo::BOTH_SCREENS);
516 NW_GL_ASSERT();
517 }
518
519 drawer.Finalize();
520
521 delete pLayout;
522 delete pResAccessor;
523
524 TerminateGraphics();
525
526 nw::demo::PadFactory::Finalize();
527 }
528
529