/*---------------------------------------------------------------------------* Project: NintendoWare File: main.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. 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. $Revision: 23847 $ *---------------------------------------------------------------------------*/ //------------------------------------------------------------------ // デモ: ArchiveFont // // 概要 // nw::font::ArchiveFont の構築と破棄のサンプルです。 // フォントリソースを一旦全てメモリに読み込んで構築する方法と // 逐次読み込みながら構築していく方法の二通りを示します。 // // 操作 // なし。 // //------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include #include #include namespace { /* 順次読み込み用の読み込みバッファサイズ。 nw::font::ArchiveFont::GetRequireBufferSize() に指定するバッファのサイズは nw::font::ArchiveFont::HEADER_SIZE 以上である必要があります。 */ const int DEMO_STREAMING_READ_BUFFER_SIZE = 16 * 1024; const char DEMO_LOAD_GROUPS[] = "ascii"; // ASCII 文字をロードする //--------------------------------------------------------------------------- //! @brief メモリを確保します。 //! //! @param[in] size 確保するメモリのサイズ。 //! @param[in] alignment 確保するメモリのアライメント値。 //! //! @return 確保したメモリへのポインタを返します。 //--------------------------------------------------------------------------- void* MemAlloc( size_t size, u8 alignment = 4 ) { return nw::demo::SimpleApp::Allocate(size, alignment); } //--------------------------------------------------------------------------- //! @brief デバイスメモリからメモリを確保します。 //! //! @param[in] size 確保するメモリのサイズ。 //! @param[in] alignment 確保するメモリのアライメント値。 //! //! @return 確保したメモリへのポインタを返します。 //--------------------------------------------------------------------------- void* DevMemAlloc( size_t size, u8 alignment = 4 ) { return nw::demo::SimpleApp::AllocateDeviceMemory(size, alignment); } //--------------------------------------------------------------------------- //! @brief メモリを解放します。 //! //! @param[in] memory 解放するメモリへのポインタ。 //--------------------------------------------------------------------------- void MemFree(void* memory) { nw::demo::SimpleApp::Free(memory); } //--------------------------------------------------------------------------- //! @brief シェーダの初期化を行います。 //! //! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。 //--------------------------------------------------------------------------- void* InitShaders(nw::font::RectDrawer* pDrawer) { const wchar_t* shaders = NW_DEMO_FILE_PATH( NW_FONT_RECTDRAWER_SHADERBINARY ); nn::fs::FileReader shaderReader(shaders); const u32 fileSize = (u32)shaderReader.GetSize(); void* shaderBinary = MemAlloc(fileSize); NN_NULL_ASSERT(shaderBinary); s32 read = shaderReader.Read(shaderBinary, fileSize); NN_ASSERT(read == fileSize); const u32 vtxBufCmdBufSize = nw::font::RectDrawer::GetVertexBufferCommandBufferSize(shaderBinary, fileSize); void *const vtxBufCmdBuf = DevMemAlloc(vtxBufCmdBufSize); NN_NULL_ASSERT(vtxBufCmdBuf); pDrawer->Initialize(vtxBufCmdBuf, shaderBinary, fileSize); MemFree(shaderBinary); return vtxBufCmdBuf; } //--------------------------------------------------------------------------- //! @brief 描画の初期設定を行います。 //! //! @param[in] width 画面の幅。 //! @param[in] height 画面の高さ。 //--------------------------------------------------------------------------- void InitDraw( int width, int height ) { // カラーバッファ情報 // LCDの向きに合わせて、幅と高さを入れ替えています。 const nw::font::ColorBufferInfo colBufInfo = { height, width, PICA_DATA_DEPTH24_STENCIL8_EXT }; const u32 screenSettingCommands[] = { // ビューポートの設定 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(screenSettingCommands, sizeof(screenSettingCommands), true); static const u32 s_InitCommands[] = { // カリングを無効 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(s_InitCommands, sizeof(s_InitCommands), true); } //--------------------------------------------------------------------------- //! @brief フォントリソースを一旦メモリに全て読み込んで //! ArchiveFont を構築します。 //! //! @param[out] pFont 構築するフォントへのポインタ。 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。 //! //! @return ArchiveFont構築の成否を返します。 //--------------------------------------------------------------------------- bool InitFont( nw::font::ArchiveFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups ) { bool bSuccess; // フォントリソースを全てメモリに読み込みます。 const u32 fileSize = (u32)pFileReader->GetSize(); if (fileSize <= 0) { return false; } const u32 readBufferSize = fileSize; void* readBuffer = MemAlloc(readBufferSize); if (readBuffer == NULL) { return false; } const int readSize = pFileReader->Read(readBuffer, readBufferSize); if (readSize != readBufferSize) { MemFree(readBuffer); return false; } // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。 const u32 fontBufferSize = nw::font::ArchiveFont::GetRequireBufferSize( readBuffer, glyphGroups); if (fontBufferSize == 0) { MemFree(readBuffer); return false; } void* const fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment); if (fontBuffer == NULL) { MemFree(readBuffer); return false; } // フォントを構築します。 // Construct の第4引数にはロードするグリフグループを指定します。 // fontBufferSize を求める時に使用したものと同じものを使用しなければなりません。 bSuccess = pFont->Construct(fontBuffer, fontBufferSize, readBuffer, glyphGroups); NW_ASSERT( bSuccess ); //--- 既にフォントが構築されているか,リソースが不正な場合に失敗します。 if (! bSuccess) { MemFree(fontBuffer); } // raedBuffer は以降使用しないので解放する事ができます。 // fontBuffer は構築に成功した場合は解放してはいけません。 MemFree(readBuffer); // 構築に関与するサイズを Report します。 NN_LOG("InitFont:\n" " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n", pFileReader->GetSize(), readBufferSize, fontBufferSize ); return bSuccess; } //--------------------------------------------------------------------------- //! @brief フォントリソースを順次読み込みながら ArchiveFont を構築します。 //! //! @param[out] pFont 構築するフォントへのポインタ。 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。 //! //! @return ArchiveFont構築の成否を返します。 //--------------------------------------------------------------------------- bool InitFontStreaming( nw::font::ArchiveFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups ) { s32 readSize; nw::font::ArchiveFont::ConstructContext context; nw::font::ArchiveFont::ConstructResult ret = nw::font::ArchiveFont::CONSTRUCT_ERROR; // 逐次読み込み用のバッファを確保します。 const u32 readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE; // nw::font::ArchiveFont::GetRequireBufferSize() に指定するバッファのサイズは // nw::font::ArchiveFont::HEADER_SIZE 以上である必要があります。 NN_ASSERT(readBufferSize >= nw::font::ArchiveFont::HEADER_SIZE); void* const readBuffer = MemAlloc(readBufferSize); if (readBuffer == NULL) { NN_LOG("can't alloc %d bytes", readBufferSize); return false; } // フォントの構築に必要なバッファサイズを取得するため // フォントリソースの先頭を読み取ります。 readSize = pFileReader->Read(readBuffer, nw::font::ArchiveFont::HEADER_SIZE); if (readSize != nw::font::ArchiveFont::HEADER_SIZE) { MemFree(readBuffer); NN_LOG("Fail to load %d bytes. Maybe too small bcfna.", nw::font::ArchiveFont::HEADER_SIZE); return false; } // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。 const u32 fontBufferSize = nw::font::ArchiveFont::GetRequireBufferSize( readBuffer, glyphGroups); if (fontBufferSize == 0) { MemFree(readBuffer); NN_LOG("ArchiveFont::GetRequireBufferSize failed"); return false; } void* fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment); if (fontBuffer == NULL) { MemFree(readBuffer); NW_WARNING(false, "can't alloc %d bytes", fontBufferSize); return false; } // フォントの構築を開始します。 // InitStreamingConstruct の第4引数にはロードするグリフグループを指定します。 // fontBufferSize を求める時に使用したものと同じものを使用しなければなりません。 pFont->InitStreamingConstruct(&context, fontBuffer, fontBufferSize, glyphGroups); // ファイルストリームから逐次リソースを読み取り、StreamingConstruct に渡していきます。 while (readSize > 0) { ret = pFont->StreamingConstruct(&context, readBuffer, static_cast(readSize)); if (ret == nw::font::ArchiveFont::CONSTRUCT_ERROR) { MemFree(fontBuffer); MemFree(readBuffer); NN_LOG("ArchiveFont::StreamingConstruct return error"); return false; } readSize = pFileReader->Read(readBuffer, readBufferSize); } if (readSize < 0) { // エラー MemFree(fontBuffer); MemFree(readBuffer); NN_LOG("readSize(=%d) < 0", readSize); return false; } // リソース読み込み完了 / フォント構築も完了しているはず NW_ASSERT(ret == nw::font::ArchiveFont::CONSTRUCT_FINISH); // raedBuffer は以降使用しないので解放する事ができます。 // fontBuffer は構築に成功した場合は解放してはいけません。 MemFree(readBuffer); // 構築に関与するサイズを Report します。 NN_LOG("InitFontStreaming:\n" " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n", pFileReader->GetSize(), readBufferSize, fontBufferSize ); return true; } //--------------------------------------------------------------------------- //! @brief ArchiveFontを破棄します。 //! //! @param[in] pFont 破棄するフォントへのポインタ。 //--------------------------------------------------------------------------- void CleanupFont(nw::font::ArchiveFont* pFont) { // フォントを破棄します。 void* buffer = pFont->Destroy(); // 構築済みフォントであれば構築時に割り当てたバッファへのポインタが返ってきます。 if (buffer != NULL) { MemFree(buffer); } // Destroy 後は再度 Construct するまでフォントとして使用できません。 } //--------------------------------------------------------------------------- //! @brief 表示文字列用バッファを確保します。 //! //! @param[in] charMax 表示する文字列の最大文字数。 //! //! @return 確保した表示文字列用バッファへのポインタを返します。 //--------------------------------------------------------------------------- nw::font::DispStringBuffer* AllocDispStringBuffer(int charMax) { const u32 DrawBufferSize = nw::font::CharWriter::GetDispStringBufferSize(charMax); void *const bufMem = MemAlloc(DrawBufferSize); NN_NULL_ASSERT(bufMem); return nw::font::CharWriter::InitDispStringBuffer(bufMem, charMax); } //--------------------------------------------------------------------------- //! @brief 文字列表示用にモデルビュー行列と射影行列を設定します。 //! //! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。 //! @param[in] width 画面の幅。 //! @param[in] height 画面の高さ。 //--------------------------------------------------------------------------- void SetupTextCamera( nw::font::RectDrawer* pDrawer, int width, int height ) { // 射影行列を正射影に設定 { // 左上原点とし、Y軸とZ軸の向きが逆になるように設定します。 nn::math::MTX44 proj; f32 znear = 0.0f; f32 zfar = -1.0f; f32 t = 0; f32 b = static_cast(height); f32 l = 0; f32 r = static_cast(width); nn::math::MTX44OrthoPivot(&proj, l, r, b, t, znear, zfar, nn::math::PIVOT_UPSIDE_TO_TOP); pDrawer->SetProjectionMtx(proj); } // モデルビュー行列を単位行列に設定 { nn::math::MTX34 mv; nn::math::MTX34Identity(&mv); pDrawer->SetViewMtxForText(mv); } } //--------------------------------------------------------------------------- //! @brief ASCII文字列を描画します。 //! //! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。 //! @param[in] pDrawStringBuf DispStringBufferオブジェクトへのポインタ。 //! @param[in] pFont フォントへのポインタ。 //! @param[in] width 画面の幅。 //! @param[in] height 画面の高さ。 //! @param[in] title フォントオブジェクトの種類をあらわす文字列。 //--------------------------------------------------------------------------- void DrawAscii( nw::font::RectDrawer* pDrawer, nw::font::DispStringBuffer* pDrawStringBuf, const nw::font::Font* pFont, int width, int height, const wchar_t* title ) { nw::font::WideTextWriter writer; writer.SetDispStringBuffer(pDrawStringBuf); writer.SetFont(pFont); writer.SetCursor(0, 0); writer.StartPrint(); writer.Printf(L"DEMO: %ls\n", title); // 文字見本を表示 writer.Print(L"Glyph Sample:\n"); writer.MoveCursorX(5); writer.Print(L" !\"#$%&'()*+,-./0123456789:;<=>?\n"); writer.Print(L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n"); writer.Print(L"`abcdefghijklmnopqrstuvwxyz{|}~\n"); writer.EndPrint(); pDrawer->BuildTextCommand(&writer); pDrawer->DrawBegin(); SetupTextCamera(pDrawer, width, height); writer.UseCommandBuffer(); pDrawer->DrawEnd(); } } // namespace //--------------------------------------------------------------------------- //! @brief サンプルのメイン関数です。 //--------------------------------------------------------------------------- void nnMain() { // os の初期化 nn::os::Initialize(); // fs の初期化 nn::fs::Initialize(); nw::demo::SimpleApp& demoApp = nw::demo::SimpleApp::GetInstance(); demoApp.Initialize(); nw::font::ArchiveFont fontNormal; nw::font::ArchiveFont fontStream; // フォントの構築 { nn::fs::FileReader fileReader(NW_DEMO_FILE_PATH(L"tahoma.bcfna")); fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN); const bool bSuccess = InitFont(&fontNormal, &fileReader, DEMO_LOAD_GROUPS); NW_ASSERTMSG(bSuccess, "Fail to load ArchiveFont by default."); fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN); const bool bSuccessStream = InitFontStreaming(&fontStream, &fileReader, DEMO_LOAD_GROUPS); NW_ASSERTMSG(bSuccessStream, "Fail to load ArchiveFont by streaming."); } // 描画リソースの構築 nw::font::RectDrawer drawer; void *const drawerBuf = InitShaders(&drawer); // 描画文字列用バッファの確保 nw::font::DispStringBuffer *const pDrawStringBuf = AllocDispStringBuffer(512); const nw::ut::FloatColor clearColor(0.3f, 0.3f, 0.3f, 1.0f); const f32 clearDepth = 0.0f; // フォント情報の表示 volatile bool loop = true; while (loop) { demoApp.SetRenderingTarget(demoApp.DISPLAY0); { demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth); InitDraw(demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT); DrawAscii( &drawer, pDrawStringBuf, &fontNormal, demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT, L"ArchiveFont - Construct"); } demoApp.SetRenderingTarget(demoApp.DISPLAY1); { demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth); InitDraw(demoApp.DISPLAY1_WIDTH, demoApp.DISPLAY1_HEIGHT); DrawAscii( &drawer, pDrawStringBuf, &fontStream, demoApp.DISPLAY1_WIDTH, demoApp.DISPLAY1_HEIGHT, L"ArchiveFont - StreamingConstruct"); } demoApp.SwapBuffer(demoApp.DISPLAY_BOTH); } // 描画文字列用バッファの解放 MemFree(pDrawStringBuf); drawer.Finalize(); MemFree(drawerBuf); // フォントの破棄 CleanupFont(&fontStream); CleanupFont(&fontNormal); }