/*---------------------------------------------------------------------------* 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 $ *---------------------------------------------------------------------------*/ //------------------------------------------------------------------ // デモ: PackedFont // // 概要 // nw::font::PackedFont の構築と破棄のサンプルです。 // フォントリソースを一旦全てメモリに読み込んで構築する方法と // 逐次読み込みながら構築していく方法の二通りを示します。 // // 操作 // なし。 // //------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include #include namespace { /* 順次読み込み用の読み込みバッファサイズ。 nw::font::PackedFont::GetRequireBufferSize() に指定するバッファのサイズは nw::font::PackedFont::HEADER_SIZE 以上である必要があります。 */ const int DEMO_STREAMING_READ_BUFFER_SIZE = 16 * 1024; const char DEMO_LOAD_GROUPS[] = "ascii"; // ASCII 文字をロードする const f32 DEMO_CACHE_RATE = 0.3f; // ロードするシートの 30 % 分のキャッシュを確保する //--------------------------------------------------------------------------- //! @brief メモリを確保します。 //! //! @param[in] size 確保するメモリのサイズ。 //! @param[in] alignment 確保するメモリのアライメント値。 //! //! @return 確保したメモリへのポインタを返します。 //--------------------------------------------------------------------------- void* MemAlloc( size_t size, u8 alignment = 4 ) { #if defined(NW_PLATFORM_CTR) return nw::demo::SimpleApp::Allocate(size, alignment); #else return nw::demo::Alloc(size, alignment); #endif } //--------------------------------------------------------------------------- //! @brief デバイスメモリからメモリを確保します。 //! //! @param[in] size 確保するメモリのサイズ。 //! @param[in] alignment 確保するメモリのアライメント値。 //! //! @return 確保したメモリへのポインタを返します。 //--------------------------------------------------------------------------- void* DevMemAlloc( size_t size, u8 alignment = 4 ) { #if defined(NW_PLATFORM_CTR) return nw::demo::SimpleApp::AllocateDeviceMemory(size, alignment); #else return nw::demo::Alloc(size, alignment); #endif } //--------------------------------------------------------------------------- //! @brief メモリを解放します。 //! //! @param[in] memory 解放するメモリへのポインタ。 //--------------------------------------------------------------------------- void MemFree(void* memory) { #if defined(NW_PLATFORM_CTR) nw::demo::SimpleApp::Free(memory); #else nw::demo::Free(memory); #endif } //--------------------------------------------------------------------------- //! @brief シェーダの初期化を行います。 //! //! @param[in,out] pResource 描画用リソースを管理するオブジェクトへのポインタ。 //--------------------------------------------------------------------------- void InitShaders(nw::font::TextWriterResource* pResource) { const wchar_t* shaders = NW_DEMO_FILE_PATH( NW_FONT_SHADERBINARY ); nn::fs::FileReader shaderReader(shaders); const u32 fileSize = (u32)shaderReader.GetSize(); void* shaderBinary = MemAlloc(fileSize); s32 read = shaderReader.Read(shaderBinary, fileSize); NN_ASSERT(read == fileSize); pResource->InitResource(shaderBinary, fileSize); MemFree(shaderBinary); } //--------------------------------------------------------------------------- //! @brief 描画の初期設定を行います。 //--------------------------------------------------------------------------- void InitDraw() { glClearColor(0.3f, 0.3f, 0.3f, 1.0f); glDisable(GL_CULL_FACE); // カリングを無効 glDisable(GL_SCISSOR_TEST); // シザー処理を無効 glDisable(GL_POLYGON_OFFSET_FILL); // ポリゴンオフセットを無効 #if defined(NW_PLATFORM_CTR) glDisable(GL_EARLY_DEPTH_TEST_DMP); // アーリーデプステストを無効 #endif glDisable(GL_DEPTH_TEST); // デプステストを無効 glDisable(GL_STENCIL_TEST); // ステンシルテストを無効 // カラーバッファの全ての成分を書き込み可 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } //--------------------------------------------------------------------------- //! @brief フォントリソースを一旦メモリに全て読み込んで //! PackedFont を構築します。 //! //! @param[out] pFont 構築するフォントへのポインタ。 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。 //! @param[in] rate 確保するシートキャッシュの割合。 //! //! @return PackedFont構築の成否を返します。 //--------------------------------------------------------------------------- bool InitFont( nw::font::PackedFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups, f32 rate ) { bool bSuccess; // フォントリソースを全てメモリに読み込みます。 const u32 fileSize = (u32)pFileReader->GetSize(); if( fileSize <= 0 ) { NN_LOG("fail to get FileStream size."); return false; } const u32 readBufferSize = fileSize; void* readBuffer = MemAlloc(readBufferSize); if (readBuffer == NULL) { NN_LOG("fail to allocate memory for resource buffer(%d byte).", readBufferSize); return false; } const int readSize = pFileReader->Read(readBuffer, readBufferSize); if (readSize != readBufferSize) { MemFree(readBuffer); NN_LOG("fail to read resource file."); return false; } // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。 // GetRequireBufferSize の第3引数には展開したシートをキャッシュする領域の割合を指定します。 // 割合は 0.0 ~ 1.0 の間で指定します。割合を小さくすれば必要なメモリ量は減りますが // 多くの文字を描画する場合のパフォーマンスが悪化します。 // 割合を大きくすればその逆となります。 const u32 fontBufferSize = nw::font::PackedFont::GetRequireBufferSize( readBuffer, glyphGroups, rate); if (fontBufferSize == 0) { MemFree(readBuffer); NN_LOG("fail to GetRequireBufferSize."); return false; } void* const fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment); if (fontBuffer == NULL) { MemFree(readBuffer); NW_WARNING(false, "fail to allocate memory for font buffer(%d byte).", fontBufferSize); return false; } // フォントを構築します。 // Construct の第4引数にはロードするグリフグループを指定します。 // fontBufferSize を求める時に使用したものと同じものを使用しなければなりません。 bSuccess = pFont->Construct(fontBuffer, fontBufferSize, readBuffer, glyphGroups); NW_ASSERT(bSuccess); //--- 既にフォントが構築されているか,リソースが不正な場合に失敗します。 if( ! bSuccess ) { NN_LOG("fail to Construct."); 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 フォントリソースを順次読み込みながら PackedFont を構築します。 //! //! @param[out] pFont 構築するフォントへのポインタ。 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。 //! @param[in] rate 確保するシートキャッシュの割合。 //! //! @return PackedFont構築の成否を返します。 //--------------------------------------------------------------------------- bool InitFontStreaming( nw::font::PackedFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups, f32 rate ) { s32 readSize; nw::font::PackedFont::ConstructContext context; nw::font::PackedFont::ConstructResult ret = nw::font::PackedFont::CONSTRUCT_ERROR; // 逐次読み込み用のバッファを確保します。 const u32 readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE; // nw::font::PackedFont::GetRequireBufferSize() に指定するバッファのサイズは // nw::font::PackedFont::HEADER_SIZE 以上である必要があります。 NN_ASSERT(readBufferSize >= nw::font::PackedFont::HEADER_SIZE); void* const readBuffer = MemAlloc(readBufferSize); if (readBuffer == NULL) { NW_WARNING(false, "fail to allocate read buffer(%d byte).", readBufferSize); return false; } // フォントの構築に必要なバッファサイズを取得するため // フォントリソースの先頭を読み取ります。 readSize = pFileReader->Read(readBuffer, nw::font::PackedFont::HEADER_SIZE); if (readSize != nw::font::PackedFont::HEADER_SIZE) { MemFree(readBuffer); NN_LOG("Fail to load %d bytes. Maybe too small bcfna.", nw::font::PackedFont::HEADER_SIZE); return false; } // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。 // GetRequireBufferSize の第3引数には展開したシートをキャッシュする領域の割合を指定します。 // 割合は 0.0 ~ 1.0 の間で指定します。割合を小さくすれば必要なメモリ量は減りますが // 多くの文字を描画する場合のパフォーマンスが悪化します。 // 割合を大きくすればその逆となります。 const u32 fontBufferSize = nw::font::PackedFont::GetRequireBufferSize( readBuffer, glyphGroups, rate); if (fontBufferSize == 0) { MemFree(readBuffer); NN_LOG("fail to GetRequireBufferSize."); return false; } void* fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment); if (fontBuffer == NULL) { MemFree(readBuffer); NN_LOG("fail to allocate memory for font buffer(%d byte).", 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::PackedFont::CONSTRUCT_ERROR) { MemFree(fontBuffer); MemFree(readBuffer); NN_LOG("fail to StreamingConstruct."); return false; } readSize = pFileReader->Read(readBuffer, readBufferSize); } if (readSize < 0) { // エラー MemFree(fontBuffer); MemFree(readBuffer); NN_LOG("fail to read resource."); return false; } // リソース読み込み完了 / フォント構築も完了しているはず NW_ASSERT(ret == nw::font::PackedFont::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 PackedFontを破棄します。 //! //! @param[in] pFont 破棄するフォントへのポインタ。 //--------------------------------------------------------------------------- void CleanupFont(nw::font::PackedFont* pFont) { // フォントを破棄します。 void* buffer = pFont->Destroy(); // 構築済みフォントであれば構築時に割り当てたバッファへのポインタが返ってきます。 if( buffer != NULL ) { MemFree(buffer); } // Destroy 後は再度 Construct するまでフォントとして使用できません。 } //--------------------------------------------------------------------------- //! @brief 文字列表示用にモデルビュー行列と射影行列を設定します。 //! //! @param[in] textWriterResource TextWriterResourceオブジェクトへの参照。 //! @param[in] width 画面の幅。 //! @param[in] height 画面の高さ。 //--------------------------------------------------------------------------- void SetupTextCamera( const nw::font::TextWriterResource& textWriterResource, int width, int height ) { #if defined(NW_PLATFORM_CTR) const GLsizei lcdWidth = height; const GLsizei lcdHeight = width; #else const GLsizei lcdWidth = width; const GLsizei lcdHeight = height; #endif glViewport(0, 0, lcdWidth, lcdHeight); // 射影行列を正射影に設定 { // 左上原点とし、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); textWriterResource.SetProjectionMtx(proj); } // モデルビュー行列を単位行列に設定 { nn::math::MTX34 mv; nn::math::MTX34Identity(&mv); textWriterResource.SetViewMtx(mv); } } //--------------------------------------------------------------------------- //! @brief ASCII文字列を描画します。 //! //! @param[in] pFont フォントへのポインタ。 //! @param[in] textWriterResource TextWriterResourceオブジェクトへの参照。 //! @param[in] title フォントオブジェクトの種類をあらわす文字列。 //--------------------------------------------------------------------------- void DrawAscii( const nw::font::Font* pFont, nw::font::TextWriterResource* pTextWriterResource, const wchar_t* title ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nw::font::WideTextWriter writer; writer.SetFont(pFont); writer.SetTextWriterResource(pTextWriterResource); writer.SetupGX(); writer.SetCursor(0, 0); 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"); glFlush(); } } // namespace //--------------------------------------------------------------------------- //! @brief サンプルのメイン関数です。 //--------------------------------------------------------------------------- void nnMain() { // os の初期化 nn::os::Initialize(); // fs の初期化 nn::fs::Initialize(); nw::demo::SimpleApp& demoApp = nw::demo::SimpleApp::GetInstance(); demoApp.Initialize(); nw::font::PackedFont fontNormal; nw::font::PackedFont 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, DEMO_CACHE_RATE); NW_ASSERTMSG(bSuccess, "Fail to load PackedFont by default."); fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN); const bool bSuccessStream = InitFontStreaming(&fontStream, &fileReader, DEMO_LOAD_GROUPS, DEMO_CACHE_RATE); NW_ASSERTMSG(bSuccessStream, "Fail to load PackedFont by streaming."); } // 描画リソースの構築 nw::font::TextWriterResource textWriterResource; InitShaders(&textWriterResource); textWriterResource.ActiveGlProgram(); InitDraw(); // フォント情報の表示 volatile bool loop = true; while (loop) { demoApp.SetRenderingTarget(demoApp.DISPLAY0); { glBindFramebuffer(GL_FRAMEBUFFER, demoApp.GetFrameBufferObject()); SetupTextCamera(textWriterResource, demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT); DrawAscii(&fontNormal, &textWriterResource, L"PackedFont - Construct"); } demoApp.SetRenderingTarget(demoApp.DISPLAY1); { glBindFramebuffer(GL_FRAMEBUFFER, demoApp.GetFrameBufferObject()); SetupTextCamera(textWriterResource, demoApp.DISPLAY1_WIDTH, demoApp.DISPLAY1_HEIGHT); DrawAscii(&fontStream, &textWriterResource, L"PackedFont - StreamingConstruct"); } demoApp.SwapBuffer(demoApp.DISPLAY_BOTH); } // フォントの破棄 CleanupFont(&fontStream); CleanupFont(&fontNormal); }