diff --git a/branches/CardCupForNBD/CardCup/Drawer.cpp b/branches/CardCupForNBD/CardCup/Drawer.cpp new file mode 100644 index 0000000..c5cbc4d --- /dev/null +++ b/branches/CardCupForNBD/CardCup/Drawer.cpp @@ -0,0 +1,683 @@ +/*---------------------------------------------------------------------------* + 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$ + *---------------------------------------------------------------------------*/ + +//------------------------------------------------------------------ +// デモ: simple +// +// 概要 +// レイアウトデータの表示とアニメーションの再生を行うデモです。 +// レイアウトデータ、アニメーションデータは次のものが含まれています。 +// +// simple.clyt ... レイアウトデータ +// simple.clan ... アニメーションデータ +// - ペインのSRTアニメーション +// - テクスチャパターンアニメーション +// - ビジビリティアニメーション +// - 頂点カラーアニメーション +// - マテリアルカラーアニメーション +// - テクスチャSRTアニメーション +// +//------------------------------------------------------------------ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +void DrawThreadMain(); + +namespace +{ + +const size_t DRAWER_STACK_SIZE = 0x1000; +nn::os::Thread s_DrawerThread; +nn::os::StackBuffer s_DrawerThreadStack; + +// 終了処理をしても良いかどうか +bool s_IsExpectedToFinalize = false; + +// 終了処理が完了したかどうか +bool s_IsPreparedToFinalize = false; + +enum LayoutType +{ + LAYOUT_UPPER_LOGO, + LAYOUT_UPPER_FADE, + + LAYOUT_MAX +}; + +enum DrawState +{ + DRAW_STATE_START, + DRAW_STATE_FADE_IN, + DRAW_STATE_LOGO_FADE_IN, + DRAW_STATE_LOGO_DRAW, + DRAW_STATE_LOGO_FADE_OUT, + DRAW_STATE_FADE_OUT, + + DRAW_STATE_MAX +}; + +struct LayoutAnimation +{ + nw::lyt::Layout* pLayout; + nw::lyt::AnimTransform* pAnimTrans[5]; +}; + +struct LayoutAnimationIndex +{ + size_t layoutType; + size_t animIndex; +}; + +// 3DSロゴレイアウト用アニメーション +const char* s_LogoAnimName[] = +{ "U_Wait_Fade_IN.bclan", "U_Wait_3DS_Rogo.bclan", "U_Wait_Fade.bclan" }; + +// フェードイン・フェードアウトレイアウト用アニメーション +const char* s_FadeAnimName[] = +{ "Fade_Fade_Out_Black.bclan", "Fade_Fade_IN_Black.bclan", "Fade_Fade_IN.bclan", "Fade_Fade_Out.bclan" }; + +/*---------------------------------------------------------------------------* + @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 ファイルの読み込みを行うクラスです。 + *---------------------------------------------------------------------------*/ +class File +{ +public: + //! + //! @brief コンストラクタです。 + //! + File() + : m_Buffer(NULL), m_Size(0) + { + } + + //! + //! @brief ファイルを読み込みます。 + //! + //! @param fileName ファイル名です。 + //! @param allocator メモリアロケータです。 + //! + //! @return 読み込みに成功したら true を返します。 + //! + bool Read(const wchar_t* fileName, nw::os::IAllocator& allocator) + { + NW_ASSERT(m_Buffer == NULL); + + nn::fs::FileReader fileReader(fileName); + if (fileReader.GetSize() <= 0) + { + return false; + } + + this->m_Size = static_cast(fileReader.GetSize()); + this->m_Buffer = static_cast(allocator.Alloc(this->m_Size, 128)); + if (this->m_Buffer == NULL) + { + this->m_Size = 0; + return false; + } + + fileReader.Read(this->m_Buffer, this->m_Size); + fileReader.Finalize(); + + return true; + } + + //! + //! @brief ファイルの読み込まれたバッファを取得します。 + //! + //! @return ポインタを返します。 + //! + u8* Buffer() + { + return this->m_Buffer; + } + + //! + //! @brief 読み込まれたファイルのサイズを取得します。 + //! + //! @return 読み込まれたファイルのサイズを返します。 + //! + u32 Size() + { + return this->m_Size; + } + +private: + u8* m_Buffer; + u32 m_Size; +}; + +/*---------------------------------------------------------------------------* + @brief モデルビュー行列と射影行列を設定します。 + + @param drawInfo 描画情報です。 + @param layout レイアウトです。 + *---------------------------------------------------------------------------*/ +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); + + // モデルビュー行列を設定 + // (Layoutデータは横向きなので画面の上方向はレイアウトの-X方向) + nw::math::VEC3 pos(0, 0, 1); + 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); +} + +void +SetupLowerCamera(nw::lyt::DrawInfo& drawInfo, const nw::lyt::Layout& layout) +{ + nw::ut::Rect layoutRect = layout.GetLayoutRect(); + + f32 znear = 0.f; + f32 zfar = 500.f; + layoutRect.left = 80.f; + layoutRect.right = 120.f; + layoutRect.bottom = -120.f; + layoutRect.top = -80.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); + + // モデルビュー行列を設定 + // (Layoutデータは横向きなので画面の上方向はレイアウトの-X方向) + nw::math::VEC3 pos(0, 0, 1); + 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); +} + +void SetupLytResource(LayoutAnimation& layoutAnim, nw::lyt::ArcResourceAccessor* pResAccessor, const char* layoutName, + const char* animName[], size_t animNum) +{ + // レイアウトリソースの読み込み + { + const void* lytRes = pResAccessor->GetResource(0, layoutName); + NW_NULL_ASSERT(lytRes); + layoutAnim.pLayout->Build(lytRes, pResAccessor); + } + + for (u32 i = 0; i < animNum; i++) + { + // アニメーションリソースの読み込み + const void* lpaRes = pResAccessor->GetResource(0, animName[i]); + NW_NULL_ASSERT(lpaRes); + layoutAnim.pAnimTrans[i] = layoutAnim.pLayout->CreateAnimTransform(lpaRes, pResAccessor); + } +} + +void GetNextLayoutAnimationIndex(LayoutAnimationIndex& index, u32 state, nw::demo::SimpleApp::Display display) +{ + if (display == nw::demo::SimpleApp::DISPLAY0) + { + switch (state) + { + case DRAW_STATE_START: + { + index.layoutType = LAYOUT_UPPER_FADE; + index.animIndex = 0; + } + break; + case DRAW_STATE_FADE_IN: + { + index.layoutType = LAYOUT_UPPER_LOGO; + index.animIndex = 0; + } + break; + case DRAW_STATE_LOGO_FADE_IN: + { + index.layoutType = LAYOUT_UPPER_LOGO; + index.animIndex = 1; + } + break; + case DRAW_STATE_LOGO_DRAW: + { + index.layoutType = LAYOUT_UPPER_LOGO; + index.animIndex = 2; + } + break; + case DRAW_STATE_LOGO_FADE_OUT: + { + index.layoutType = LAYOUT_UPPER_FADE; + index.animIndex = 1; + } + break; + } + } + else if(display == nw::demo::SimpleApp::DISPLAY1) + { + switch (state) + { + case DRAW_STATE_START: + { + index.layoutType = LAYOUT_UPPER_FADE; + index.animIndex = 0; + } + break; + case DRAW_STATE_FADE_IN: + { + index.layoutType = LAYOUT_UPPER_LOGO; + index.animIndex = 0; + } + break; + case DRAW_STATE_LOGO_FADE_IN: + { + index.layoutType = LAYOUT_UPPER_LOGO; + index.animIndex = 1; + } + break; + case DRAW_STATE_LOGO_DRAW: + { + index.layoutType = LAYOUT_UPPER_LOGO; + index.animIndex = 2; + } + break; + case DRAW_STATE_LOGO_FADE_OUT: + { + index.layoutType = LAYOUT_UPPER_FADE; + index.animIndex = 1; + } + break; + } + } +} + +} // namespace {anonymous} + +void StartDrawerThread() +{ + s_DrawerThread.Start(DrawThreadMain, s_DrawerThreadStack); +} + +bool IsDrawerThreadFinished() +{ + return s_IsPreparedToFinalize; +} + +void FinalizeDrawerThread() +{ + s_DrawerThread.Join(); + s_DrawerThread.Finalize(); +} + +void RestoreGraphics() +{ + // GPU レジスタ設定の復帰 + nngxUpdateState(NN_GX_STATE_ALL); + nngxValidateState(NN_GX_STATE_ALL,GL_TRUE); +} + +void NotifyFailed(s32 error) +{ + nn::applet::AppletWakeupState wstate; + nn::erreula::Parameter ere_param; // エラーEULAの設定構造体 + + // 設定構造体初期化 + nn::erreula::InitializeConfig(&ere_param.config); + + ere_param.config.errorType = nn::erreula::ERROR_TYPE_ERROR_CODE; + ere_param.config.errorCode = error; + ere_param.config.upperScreenFlag = nn::erreula::UPPER_SCREEN_NORMAL; + ere_param.config.homeButton = true; + ere_param.config.softwareReset = false; + ere_param.config.appJump = false; + + nn::erreula::CancelPreloadErrEulaApplet(); + nn::erreula::StartErrEulaApplet(&wstate, &ere_param); + + // GPU レジスタ設定の復帰 + RestoreGraphics(); +} + +void NotifyFinished() +{ + s_IsExpectedToFinalize = true; +} + + +/*---------------------------------------------------------------------------* + @brief サンプルのメイン関数です。 + *---------------------------------------------------------------------------*/ +void +DrawThreadMain() +{ + // アプリケーションの初期化。 + nw::demo::SimpleApp& demoApp = nw::demo::SimpleApp::GetInstance(); + demoApp.Initialize(); + + // レイアウトライブラリの初期化。 + nw::lyt::Initialize(&demoApp.GetAllocator(), &demoApp.GetDeviceAllocator()); + + // レイアウトのバイナリリソース(アーカイブ)を読み込み。 + File fileLayout; + if (!fileLayout.Read(NW_DEMO_FILE_PATH(L"All.arc"), demoApp.GetDeviceAllocator())) + { + NW_FATAL_ERROR("can not open layout archive.\n"); + } + + // バイナリリソースのルートディレクトリを指定してリソースアクセサを生成。 + nw::lyt::ArcResourceAccessor* pResAccessor = new nw::lyt::ArcResourceAccessor; + if (!pResAccessor->Attach(fileLayout.Buffer(), ".")) + { + NW_FATAL_ERROR("can not attach layout archive.\n"); + } + + LayoutAnimation layoutAnim[LAYOUT_MAX]; + + // 上画面ロゴ + { + layoutAnim[LAYOUT_UPPER_LOGO].pLayout = new nw::lyt::Layout(); + SetupLytResource(layoutAnim[LAYOUT_UPPER_LOGO], pResAccessor, "U_Wait.bclyt", s_LogoAnimName, + sizeof(s_LogoAnimName) / sizeof(s_LogoAnimName[0])); + } + + // フェードイン・フェードアウト + { + layoutAnim[LAYOUT_UPPER_FADE].pLayout = new nw::lyt::Layout(); + SetupLytResource(layoutAnim[LAYOUT_UPPER_FADE], pResAccessor, "Fade.bclyt", s_FadeAnimName, + sizeof(s_FadeAnimName) / sizeof(s_FadeAnimName[0])); + } + + f32 animFrame = 0; + nw::lyt::GraphicsResource graphicsResource; + + // グローバルなリソースファイルを読み込みます。 + { + graphicsResource.StartSetup(); + const wchar_t* resourcePath = 0; + for (int i = 0; + (resourcePath = graphicsResource.GetResourcePath(i)) != NULL; + ++i) + { + File file; + if (!file.Read(resourcePath, demoApp.GetAllocator())) + { + NW_FATAL_ERROR("can not read lyt resource file."); + } + graphicsResource.SetResource(i, file.Buffer(), file.Size()); + } + graphicsResource.FinishSetup(); + } + + nw::lyt::DrawInfo drawInfo; + drawInfo.SetGraphicsResource(&graphicsResource); + + nw::lyt::Drawer drawer; + drawer.Initialize(graphicsResource); + + const nw::ut::FloatColor clearColor(0.0f, 0.0f, 0.0f, 1.0f); + const f32 clearDepth = 0.0f; + + bool mainloop = true; + + nn::hid::PadReader padReader; + nn::hid::PadStatus padStatus; + + nw::lyt::Layout* pUpperLayout; + nw::lyt::Layout* pLowerLayout; + + u32 drawState = DRAW_STATE_START; + + LayoutAnimation* pUpperLayoutAnim; + LayoutAnimation* pLowerLayoutAnim; + LayoutAnimationIndex upperLayoutAnimIndex; + LayoutAnimationIndex lowerLayoutAnimIndex; + GetNextLayoutAnimationIndex(upperLayoutAnimIndex, drawState, demoApp.DISPLAY0); + GetNextLayoutAnimationIndex(lowerLayoutAnimIndex, drawState, demoApp.DISPLAY1); + pUpperLayoutAnim = &layoutAnim[upperLayoutAnimIndex.layoutType]; + pLowerLayoutAnim = &layoutAnim[lowerLayoutAnimIndex.layoutType]; + + const s32 KEEP_FRAME_INTERVAL = 180; + s32 keepFrame = KEEP_FRAME_INTERVAL; + + while (mainloop) + { + padReader.ReadLatest(&padStatus); + + // 上画面描画 + demoApp.SetRenderingTarget(demoApp.DISPLAY0); + pUpperLayout = pUpperLayoutAnim->pLayout; + pUpperLayout->UnbindAllAnimation(); + pUpperLayout->BindAnimation(pUpperLayoutAnim->pAnimTrans[upperLayoutAnimIndex.animIndex]); + { + demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth); + + SetupCamera(drawInfo, *pUpperLayout); + + InitDraw(demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT); + pUpperLayout->Animate(); + pUpperLayout->CalculateMtx(drawInfo); + + drawer.DrawBegin(drawInfo); + drawer.Draw(pUpperLayout, drawInfo); + drawer.DrawEnd(drawInfo); + } + + // 下画面描画 + demoApp.SetRenderingTarget(demoApp.DISPLAY1); + if (drawState == DRAW_STATE_LOGO_DRAW) + { + const nw::ut::FloatColor white(1.0f, 1.0f, 1.0f, 1.0f); + demoApp.GetFrameBufferObject().ClearBuffer(white, clearDepth); + } + else + { + pLowerLayout = pLowerLayoutAnim->pLayout; + pLowerLayout->UnbindAllAnimation(); + pLowerLayout->BindAnimation(pLowerLayoutAnim->pAnimTrans[lowerLayoutAnimIndex.animIndex]); + { + demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth); + + if(DRAW_STATE_LOGO_FADE_IN <= drawState && drawState <= DRAW_STATE_LOGO_FADE_OUT) + { + SetupLowerCamera(drawInfo, *pLowerLayout); + } + else + { + SetupCamera(drawInfo, *pLowerLayout); + } + + + InitDraw(demoApp.DISPLAY1_WIDTH, demoApp.DISPLAY1_HEIGHT); + pLowerLayout->Animate(); + pLowerLayout->CalculateMtx(drawInfo); + + drawer.DrawBegin(drawInfo); + drawer.Draw(pLowerLayout, drawInfo); + drawer.DrawEnd(drawInfo); + } + } + + // フレームの更新 + f32 step = 1.0f; + if (animFrame < pUpperLayoutAnim->pAnimTrans[upperLayoutAnimIndex.animIndex]->GetFrameMax() && + (drawState == DRAW_STATE_LOGO_FADE_OUT && animFrame < 10.0f)) + { + animFrame = nw::ut::Min(pUpperLayoutAnim->pAnimTrans[upperLayoutAnimIndex.animIndex]->GetFrameMax(), + animFrame + step); + } + // 1アニメーション終了 + else + { + if (drawState < DRAW_STATE_FADE_OUT) + { + if (!(drawState == DRAW_STATE_LOGO_DRAW && --keepFrame > 0)) + { + // 次のアニメーションへ遷移 + GetNextLayoutAnimationIndex(upperLayoutAnimIndex, drawState, demoApp.DISPLAY0); + GetNextLayoutAnimationIndex(lowerLayoutAnimIndex, drawState, demoApp.DISPLAY1); + pUpperLayoutAnim = &layoutAnim[upperLayoutAnimIndex.layoutType]; + pLowerLayoutAnim = &layoutAnim[lowerLayoutAnimIndex.layoutType]; + + // 終了処理を依頼されたときのみロゴフェードアウト移行に進む + if(drawState < DRAW_STATE_LOGO_DRAW || s_IsExpectedToFinalize) + { + drawState++; + } + + if(drawState == DRAW_STATE_LOGO_FADE_IN) + { + animFrame = 11.f; + } + else + { + animFrame = 0; + } + + NN_LOG("State = %d\n", drawState); + NN_LOG( + "Upper: layout: %d, anim: %d\n", upperLayoutAnimIndex.layoutType, upperLayoutAnimIndex.animIndex); + NN_LOG( + "Lower: layout: %d, anim: %d\n\n", lowerLayoutAnimIndex.layoutType, lowerLayoutAnimIndex.animIndex); + } + + } + else + { + // 終了処理へ + break; + } + } + + pUpperLayoutAnim->pAnimTrans[upperLayoutAnimIndex.animIndex]->SetFrame(animFrame); + pLowerLayoutAnim->pAnimTrans[lowerLayoutAnimIndex.animIndex]->SetFrame(animFrame); + demoApp.SwapBuffer(demoApp.DISPLAY_BOTH); + } + + delete pResAccessor; + + demoApp.GetDeviceAllocator().Free(fileLayout.Buffer()); + s_IsPreparedToFinalize = true; +} + diff --git a/branches/CardCupForNBD/CardCup/Drawer.h b/branches/CardCupForNBD/CardCup/Drawer.h new file mode 100644 index 0000000..b02d7f4 --- /dev/null +++ b/branches/CardCupForNBD/CardCup/Drawer.h @@ -0,0 +1,25 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: Drawer.h + + Copyright 2009-2011 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. 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. + + $Rev$ + *---------------------------------------------------------------------------*/ + +#ifndef DRAWER_H_ +#define DRAWER_H_ + +void StartDrawerThread(); +bool IsDrawerThreadFinished(); +void FinalizeDrawerThread(); +void NotifyFailed(s32 error); +void NotifyFinished(); + +#endif /* DRAWER_H_ */ diff --git a/branches/CardCupForNBD/CardCup/OMakefile b/branches/CardCupForNBD/CardCup/OMakefile index df3abc5..7e3e283 100644 --- a/branches/CardCupForNBD/CardCup/OMakefile +++ b/branches/CardCupForNBD/CardCup/OMakefile @@ -27,6 +27,7 @@ LIBS += lib_demo \ libnn_am \ libnn_cup \ libnn_ns \ + libnn_erreula \ LIBFILES += $`(addprefix $(NW4C_ROOT)$(DIRSEP)libraries$(DIRSEP)$(config.getTargetSubDirectory true)$(DIRSEP), libnw_demo) LIBFILES += $`(addprefix $(NW4C_ROOT)$(DIRSEP)libraries$(DIRSEP)$(config.getTargetSubDirectory true)$(DIRSEP), libnw_dev) diff --git a/branches/CardCupForNBD/CardCup/main.cpp b/branches/CardCupForNBD/CardCup/main.cpp index dd16091..b51b510 100644 --- a/branches/CardCupForNBD/CardCup/main.cpp +++ b/branches/CardCupForNBD/CardCup/main.cpp @@ -30,6 +30,8 @@ #include +#include "Drawer.h" + namespace { char s_updaterBuffer[1<<20] NN_ATTRIBUTE_ALIGN(4096); @@ -145,6 +147,9 @@ extern "C" void nnMain() nn::Result result; Initialize(); + // ロゴ表示開始 + StartDrawerThread(); + nn::ProgramId MMEN_PROGRAM_ID = 0x0004003000008202; nn::cfg::CfgRegionCode region = nn::cfg::GetRegion(); @@ -189,34 +194,38 @@ extern "C" void nnMain() // TODO:HOMEメニューが無いエラーをエラーアプレットで表示する } + NotifyFinished(); + nn::os::Tick before = nn::os::Tick::GetSystemCurrent(); const u8 SHUTDOWN_WAIT_SECONDS = 2; for(;;) { - nn::os::Tick current = nn::os::Tick::GetSystemCurrent(); - if((current - before).ToTimeSpan().GetSeconds() > SHUTDOWN_WAIT_SECONDS) - { - break; - } - // 画面描画 - if(result.IsSuccess() || result == nn::cup::CTR::ResultUpdateNotRequired()) + if (result.IsSuccess() || result == nn::cup::CTR::ResultUpdateNotRequired()) { // TODO:成功したので終了処理に入る + nn::os::Tick current = nn::os::Tick::GetSystemCurrent(); + if ((current - before).ToTimeSpan().GetSeconds() > SHUTDOWN_WAIT_SECONDS) + { + break; + } } else { // TODO:失敗したのでエラー表示を続ける + NotifyFailed(0); } - if ( nn::applet::IsExpectedToCloseApplication() ) + if (nn::applet::IsExpectedToCloseApplication()) { nn::applet::PrepareToCloseApplication(); nn::applet::CloseApplication(); } } + FinalizeDrawerThread(); + nn::ns::ShutdownAsync(); nn::ns::FinalizeForShell(); }