/*---------------------------------------------------------------------------* Project: NintendoWare File: main.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ //------------------------------------------------------------------ // デモ: orthoStereo // // 概要 // レイアウトを正射影で立体視するサンプルです。 // //------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include namespace { nw::demo::RenderSystem* s_pRenderSystem = NULL; nw::gfx::IRenderTarget* s_pRenderTarget = NULL; nw::gfx::IRenderTarget* s_pRenderTargetLower = NULL; //---------------------------------------- // メモリ関係 // デバイスメモリを確保するためのアロケータです。 nw::demo::DemoAllocator s_DeviceAllocator; //---------------------------------------- typedef nw::ut::MoveArray File; nn::ulcd::CTR::StereoCamera s_StereoCamera; f32 s_DepthLevel = 10.0f; // LCD 上に配置したい場所(基準面)までのカメラからの距離 f32 s_StereoFactor = 1.0f; // 立体具合の調整係数(0で視差が無くなり、1で標準となります。) /*---------------------------------------------------------------------------* @brief グラフィックス関連の初期化を行います。 *---------------------------------------------------------------------------*/ void InitializeGraphics() { nw::demo::RenderSystem::Description renderDesc; nw::demo::DisplayBufferSwapper::Description& upperScreenDesc = renderDesc.upperScreenDescription; nw::demo::DisplayBufferSwapper::Description& lowerScreenDesc = renderDesc.lowerScreenDescription; renderDesc.upperScreenMode = nw::demo::UPPER_SCREEN_MODE_STEREO; s_pRenderSystem = nw::demo::RenderSystem::Create( &s_DeviceAllocator, renderDesc); NW_ASSERT(s_pRenderSystem != NULL); s_pRenderTarget = nw::gfx::IRenderTarget::Builder() .BufferSize(upperScreenDesc.height, upperScreenDesc.width) .ColorFormat(renderDesc.renderColorFormat) .Create(&s_DeviceAllocator); NW_ASSERT(s_pRenderTarget != NULL); s_pRenderTargetLower = nw::gfx::IRenderTarget::Builder() .BufferSize(lowerScreenDesc.height, lowerScreenDesc.width) .ColorFormat(renderDesc.renderColorFormat) .Create(&s_DeviceAllocator); NW_ASSERT(s_pRenderTargetLower != NULL); NW_GL_ASSERT(); } //--------------------------------------------------------------------------- //! @brief グラフィックス関連の後始末を行います。 //--------------------------------------------------------------------------- void TerminateGraphics() { nw::gfx::SafeDestroy(s_pRenderSystem); nw::gfx::SafeDestroy(s_pRenderTarget); nw::gfx::SafeDestroy(s_pRenderTargetLower); } /*---------------------------------------------------------------------------* @brief 描画の初期設定を行います。 @param width 画面の幅。 @param height 画面の高さ。 *---------------------------------------------------------------------------*/ void InitDraw(int width, int height) { // カラーバッファ情報 // LCDの向きに合わせて、幅と高さを入れ替えています。 const nw::font::ColorBufferInfo colBufInfo = { height, width, PICA_DATA_DEPTH24_STENCIL8_EXT }; const u32 commands[] = { // ビューポートの設定 NW_FONT_CMD_SET_VIEWPORT(0, 0, colBufInfo.width, colBufInfo.height), // シザー処理を無効 NW_FONT_CMD_SET_DISABLE_SCISSOR(colBufInfo), // wバッファの無効化 // デプスレンジの設定 // ポリゴンオフセットの無効化 NW_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET( 0.0f, // wScale : 0.0 でWバッファが無効 0.0f, // depth range near 1.0f, // depth range far 0, // polygon offset units : 0.0 で ポリゴンオフセットが無効 colBufInfo), }; nngxAdd3DCommand(commands, sizeof(commands), true); static const u32 constCommands[] = { // カリングを無効 NW_FONT_CMD_SET_CULL_FACE(NW_FONT_CMD_CULL_FACE_DISABLE), // ステンシルテストを無効 NW_FONT_CMD_SET_DISABLE_STENCIL_TEST(), // デプステストを無効 // カラーバッファの全ての成分を書き込み可 NW_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK( false, // isDepthTestEnabled 0, // depthFunc true, // depthMask true, // red true, // green true, // blue true), // alpha // アーリーデプステストを無効 NW_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST(false), // フレームバッファアクセス制御 NW_FONT_CMD_SET_FBACCESS( true, // colorRead true, // colorWrite false, // depthRead false, // depthWrite false, // stencilRead false), // stencilWrite }; nngxAdd3DCommand(constCommands, sizeof(constCommands), true); } //--------------------------------------------------------------------------- //! @brief モデルビュー行列と射影行列を設定します。 //! //! @param[in] drawInfo 描画情報です。 //! @param[in] layout レイアウトです。 //! //! @return 視差の半分の値を返します(液晶のドット単位)。 //--------------------------------------------------------------------------- void SetupCamera( nw::lyt::DrawInfo& drawInfo, const nw::lyt::Layout& layout ) { nw::ut::Rect layoutRect = layout.GetLayoutRect(); f32 znear = 0.f; f32 zfar = 500.f; // 射影行列を正射影に設定 // (Layoutデータは横向きなので向きを変換する) nw::math::MTX44 projMtx; nw::math::MTX44OrthoPivot( &projMtx, layoutRect.left, // left layoutRect.right, // right layoutRect.bottom, // bottom layoutRect.top, // top znear, zfar, nw::math::PIVOT_UPSIDE_TO_TOP); drawInfo.SetProjectionMtx(projMtx); // モデルビュー行列を設定 nw::math::VEC3 pos(0, 0, s_DepthLevel); nw::math::VEC3 up(0, 1, 0); nw::math::VEC3 target(0, 0, 0); nw::math::MTX34 viewMtx; nw::math::MTX34LookAt(&viewMtx, &pos, &up, &target); drawInfo.SetViewMtx(viewMtx); } //--------------------------------------------------------------------------- //! @brief 視差の半分の値を液晶のドット単位で求めます。 //! //! @param[in] drawInfo 描画情報です。 //! //! @return 視差の半分の値を返します(液晶のドット単位)。 //--------------------------------------------------------------------------- f32 CalcParallaxDot(nw::lyt::DrawInfo& drawInfo) { // 左右の視差に対応した絵を描画するための射影行列、ビュー行列を計算する nn::math::MTX34 view = drawInfo.GetViewMtx(); s_StereoCamera.SetBaseCamera(&view); nn::math::MTX44 projL, projR; nn::math::MTX34 viewL, viewR; s_StereoCamera.CalculateMatrices( &projL, &viewL, &projR, &viewR, s_DepthLevel, s_StereoFactor, nn::math::PIVOT_UPSIDE_TO_TOP); // 視差の半分の値を液晶のドット単位で求める。 f32 wkParallax = s_StereoCamera.GetCoefficientForParallax(); return wkParallax * nw::demo::SimpleApp::DISPLAY0_WIDTH; } //--------------------------------------------------------------------------- //! @brief コマンドリストを作成します。 //! //! @param[in] bufSize 3Dコマンドバッファのサイズです。 //! @param[in] requestCount コマンドリクエストの個数です。 //! //! @return コマンドリストIDを返します。 //--------------------------------------------------------------------------- GLuint CreateCmdList( GLsizei bufSize, GLsizei requestCount ) { // カレントを退避 GLuint crntCmdListId; nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, reinterpret_cast(&crntCmdListId)); // 生成 GLuint lytCmdListId; nngxGenCmdlists(1, &lytCmdListId); nngxBindCmdlist(lytCmdListId); nngxCmdlistStorage(bufSize, requestCount); // カレントを復帰 nngxBindCmdlist(crntCmdListId); return lytCmdListId; } //--------------------------------------------------------------------------- //! @brief コマンドリストの保存を開始します。 //! //! @param[in] cmdListId 保存するコマンドリストのID。 //! //! @return 現在のコマンドリストIDを返します。 //--------------------------------------------------------------------------- GLuint StartCmdListSave(GLuint cmdListId) { // カレントを退避 GLuint crntCmdListId; nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, reinterpret_cast(&crntCmdListId)); nngxBindCmdlist(cmdListId); // バインド nngxClearCmdlist(); // クリア nngxStartCmdlistSave(); // セーブ開始 return crntCmdListId; } //--------------------------------------------------------------------------- //! @brief 保存したコマンドリストの情報を保存する構造体。 //--------------------------------------------------------------------------- struct CmdListInfo { GLuint bufferOffset; GLsizei bufferSize; GLuint requestId; GLsizei requestSize; }; //--------------------------------------------------------------------------- //! @brief コマンドリストの保存を終了します。 //! //! @param[out] pCmdListInfo コマンドリストの情報を保存する構造体へのポインタ。 //! @param[in] cmdListId 元に戻すコマンドリストのID。 //--------------------------------------------------------------------------- void StopCmdListSave( CmdListInfo* pCmdListInfo, GLuint cmdListId ) { nngxStopCmdlistSave( &pCmdListInfo->bufferOffset, &pCmdListInfo->bufferSize, &pCmdListInfo->requestId, &pCmdListInfo->requestSize); NW_GL_ASSERT(); // カレントを復帰 nngxBindCmdlist(cmdListId); } //--------------------------------------------------------------------------- //! @brief 保存されたコマンドリストを使用します。 //! //! @param[in] cmdListId コマンドリストのID。 //! @param[in] cmdListInfo コマンドリストの情報を保存する構造体。 //--------------------------------------------------------------------------- void UseSavedCmdlist( GLuint cmdListId, const CmdListInfo& cmdListInfo ) { nngxUseSavedCmdlist( cmdListId, cmdListInfo.bufferOffset, cmdListInfo.bufferSize, cmdListInfo.requestId, cmdListInfo.requestSize, 0, GL_TRUE); } } // namespace {anonymous} //--------------------------------------------------------------------------- //! @brief サンプルのメイン関数です。 //--------------------------------------------------------------------------- void nnMain() { nw::demo::InitializeGraphicsSystem(&s_DeviceAllocator); nw::demo::PadFactory::Initialize(&s_DeviceAllocator); InitializeGraphics(); // レイアウトライブラリの初期化。 // デモでは全てのメモリをデバイスメモリから確保していますので、 // 同じアロケータを渡しています。 // ヒープメモリと区別して扱う場合は第2引数は必ずデバイスメモリを指定してください。 nw::lyt::Initialize(&s_DeviceAllocator, &s_DeviceAllocator); // レイアウトのバイナリリソース(アーカイブ)を読み込み。 File resLayout = nw::demo::Utility::LoadFile( &s_DeviceAllocator, NW_DEMO_FILE_PATH(L"layout.arc"), 128); if (resLayout.empty()) { NW_FATAL_ERROR("can not open layout archive.\n"); } // バイナリリソースのルートディレクトリを指定してリソースアクセサを生成。 nw::lyt::ArcResourceAccessor* pResAccessor = new nw::lyt::ArcResourceAccessor; if (!pResAccessor->Attach(resLayout.begin(), ".")) { NW_FATAL_ERROR("can not attach layout archive.\n"); } nw::lyt::Layout* pLayout = new nw::lyt::Layout(); // レイアウトリソースの読み込み { const void* lytRes = pResAccessor->GetResource(0, "orthoStereo.bclyt"); NW_NULL_ASSERT(lytRes); pLayout->Build(lytRes, pResAccessor); } nw::lyt::GraphicsResource graphicsResource; // グローバルなリソースファイルを読み込みます。 { graphicsResource.StartSetup(); const wchar_t* resourcePath = 0; for (int i = 0; (resourcePath = graphicsResource.GetResourcePath(i)) != NULL; ++i) { File resource = nw::demo::Utility::LoadFile(&s_DeviceAllocator, resourcePath); if (resource.empty()) { NW_FATAL_ERROR("can not read lyt resource file."); } graphicsResource.SetResource(i, resource.begin(), resource.size(), false); } graphicsResource.FinishSetup(); } nw::lyt::DrawInfo drawInfo; drawInfo.SetGraphicsResource(&graphicsResource); nw::lyt::Drawer drawer; drawer.Initialize(graphicsResource); // 立体視のためのカメラの初期化 s_StereoCamera.Initialize(); s_StereoCamera.SetBaseFrustum( -0.04f, 0.04f, -0.04f * nw::demo::SimpleApp::DISPLAY0_HEIGHT / nw::demo::SimpleApp::DISPLAY0_WIDTH, 0.04f * nw::demo::SimpleApp::DISPLAY0_HEIGHT / nw::demo::SimpleApp::DISPLAY0_WIDTH, 0.2f, 30.f); // レイアウト描画用のコマンドリストの作成 const GLuint lytCmdListId = CreateCmdList(2048, 1); bool loop = true; while (loop) { SetupCamera(drawInfo, *pLayout); NW_GL_ASSERT(); pLayout->Animate(); pLayout->CalculateMtx(drawInfo); NW_GL_ASSERT(); // レイアウトの描画コマンドを生成 CmdListInfo lytCmdListInfo; const GLuint crntCmdListId = StartCmdListSave(lytCmdListId); drawer.DrawBegin(nw::lyt::Drawer::DONT_USE_SETUP_COMMAND); drawer.Draw(pLayout, drawInfo); drawer.DrawEnd(nw::lyt::Drawer::DONT_USE_SETUP_COMMAND); StopCmdListSave(&lytCmdListInfo, crntCmdListId); s_pRenderSystem->SetRenderTarget(s_pRenderTarget); NW_GL_ASSERT(); // 視差の半分の値を液晶のドット単位で求めます。 const f32 halfParallaxDot = CalcParallaxDot(drawInfo); // 上画面(左目用) { s_pRenderSystem->ClearBuffer( nw::ut::FloatColor(0.2f, 0.2f, 0.2f, 0.0f)); InitDraw( nw::demo::SimpleApp::DISPLAY0_WIDTH, nw::demo::SimpleApp::DISPLAY0_HEIGHT); // Drawerを使ってレイアウトを描画します。 drawer.SetParallax(-halfParallaxDot, s_StereoCamera.GetDistanceToLevel()); drawer.DrawBegin(drawInfo); UseSavedCmdlist(lytCmdListId, lytCmdListInfo); drawer.DrawEnd(); s_pRenderSystem->TransferBuffer(nw::demo::UPPER_SCREEN); } // 上画面(右目用) { s_pRenderSystem->ClearBuffer( nw::ut::FloatColor(0.2f, 0.2f, 0.2f, 0.0f)); InitDraw( nw::demo::SimpleApp::DISPLAY0_WIDTH, nw::demo::SimpleApp::DISPLAY0_HEIGHT); // Drawerを使ってレイアウトを描画します。 drawer.SetParallax( halfParallaxDot, s_StereoCamera.GetDistanceToLevel()); drawer.DrawBegin(drawInfo); UseSavedCmdlist(lytCmdListId, lytCmdListInfo); drawer.DrawEnd(); s_pRenderSystem->TransferBuffer(nw::demo::EXTENSION_SCREEN); } s_pRenderSystem->SetRenderTarget(s_pRenderTargetLower); // 下画面 { s_pRenderSystem->ClearBuffer( nw::ut::FloatColor(0.1f, 0.1f, 0.1f, 0.0f)); s_pRenderSystem->TransferBuffer(nw::demo::LOWER_SCREEN); } s_pRenderSystem->PresentBuffer(nw::demo::BOTH_SCREENS); NW_GL_ASSERT(); } drawer.Finalize(); delete pLayout; delete pResAccessor; TerminateGraphics(); nw::demo::PadFactory::Finalize(); }