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: 26555 $
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
CreateCmdList(GLsizei bufSize,GLsizei requestCount)260 CreateCmdList(
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 = CreateCmdList(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