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