/*---------------------------------------------------------------------------* Project: NintendoWare File: main.cpp Copyright (C)2009-2011 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: 47435 $ *---------------------------------------------------------------------------*/ //------------------------------------------------------------------ // Demo: PackedFont // // Overview // This sample builds and destroys nn::font::PackedFont. // Two methods are shown: one builds after loading all font resources into memory at once, and the other builds while sequentially loading font resources. // // // Controls // None. // //------------------------------------------------------------------ #include #include #include #include #include "demo.h" #include "applet.h" namespace { const char s_ShaderBinaryFilePath[] = "rom:/nnfont_TextWriterShader.shbin"; const char s_FontFilePath[] = "rom:/tahoma.bcfna"; nn::fnd::ExpHeap s_AppHeap; demo::RenderSystemDrawing s_RenderSystem; const s32 nDeviceMemorySizeVideo = 4 * 1024 * 1024; const s32 nDeviceMemorySizeOther = 4 * 1024 * 1024; const s32 nDeviceMemorySize = nDeviceMemorySizeVideo + nDeviceMemorySizeOther; /* Load buffer size for sequential loading. The size of the buffer specified in nn::font::PackedFont::GetRequireBufferSize function must be greater than nn::font::PackedFont::HEADER_SIZE. */ const int DEMO_STREAMING_READ_BUFFER_SIZE = 16 * 1024; const char DEMO_LOAD_GROUPS[] = "ascii"; // Load ASCII characters const f32 DEMO_CACHE_RATE = 0.3f; // Allocate a cache that is 30% worth of the sheet loaded. //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void InitShaders(nn::font::TextWriterResource* pResource) { nn::fs::FileReader shaderReader(s_ShaderBinaryFilePath); const u32 fileSize = (u32)shaderReader.GetSize(); void* shaderBinary = s_AppHeap.Allocate(fileSize); #ifndef NN_BUILD_RELEASE s32 read = #endif // NN_BUILD_RELEASE shaderReader.Read(shaderBinary, fileSize); NN_ASSERT(read == fileSize); pResource->InitResource(shaderBinary, fileSize); s_AppHeap.Free(shaderBinary); } //--------------------------------------------------------------------------- // //--------------------------------------------------------------------------- void InitDraw() { glClearColor(0.3f, 0.3f, 0.3f, 1.0f); glDisable(GL_CULL_FACE); // Disable culling glDisable(GL_SCISSOR_TEST); // Disable scissoring glDisable(GL_POLYGON_OFFSET_FILL); // Disable polygon offset #if defined(NN_PLATFORM_CTR) glDisable(GL_EARLY_DEPTH_TEST_DMP); // Disable early depth test #endif glDisable(GL_DEPTH_TEST); // Disable depth test glDisable(GL_STENCIL_TEST); // Disable stencil test // Make all elements of the color buffer writable glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } //--------------------------------------------------------------------------- // // // // // // // // // //--------------------------------------------------------------------------- bool InitFont( nn::font::PackedFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups, f32 rate ) { bool bSuccess; // Loads all font resource to the memory. const u32 fileSize = (u32)pFileReader->GetSize(); if( fileSize <= 0 ) { NN_LOG("Failed to get FileStream size."); return false; } const u32 readBufferSize = fileSize; void* readBuffer = s_AppHeap.Allocate(readBufferSize); if (readBuffer == NULL) { NN_LOG("Failed to allocate memory for the resource buffer (%d bytes).", readBufferSize); return false; } const int readSize = pFileReader->Read(readBuffer, readBufferSize); if (readSize != readBufferSize) { s_AppHeap.Free(readBuffer); NN_LOG("Failed to read resource file."); return false; } // Gets the buffer size necessary for building the font, and allocates the buffer. // Specifies the glyph group to load for the second argument of GetRequireBufferSize. // Specifies the ratio of the area to cache the expanded sheet for the third argument of GetRequireBufferSize. // Specifies the ratio in values 0.0 - 1.0. // If the ratio is decreased, then the amount of memory required is reduced, but performance will be worse when rendering a large number of characters. // Increasing the ratio will have the opposite effect. const u32 fontBufferSize = nn::font::PackedFont::GetRequireBufferSize( readBuffer, glyphGroups, rate); if (fontBufferSize == 0) { s_AppHeap.Free(readBuffer); NN_LOG("GetRequireBufferSize failed."); return false; } void* const fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment); if (fontBuffer == NULL) { s_AppHeap.Free(readBuffer); NN_WARNING(false, "Failed to allocate memory for the font buffer (%d bytes).", fontBufferSize); return false; } // Builds fonts. // Specifies the glyph group to load for the fourth argument of Construct. // Same glyph group used when obtaining the fontBufferSize must be used. bSuccess = pFont->Construct(fontBuffer, fontBufferSize, readBuffer, glyphGroups); NN_ASSERT(bSuccess); //--- Fails if the font is already built or if the resource is invalid. if( ! bSuccess ) { NN_LOG("Failed to Construct."); s_AppHeap.Free(fontBuffer); } // readBuffer will not be used anymore, so it may be released. // fontBuffer must not be released if the build is successful. s_AppHeap.Free(readBuffer); // The size associated with building is reported. NN_LOG("InitFont:\n" " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n", pFileReader->GetSize(), readBufferSize, fontBufferSize); return bSuccess; } //--------------------------------------------------------------------------- // // // // // // // // //--------------------------------------------------------------------------- bool InitFontStreaming( nn::font::PackedFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups, f32 rate ) { s32 readSize; nn::font::PackedFont::ConstructContext context; nn::font::PackedFont::ConstructResult ret = nn::font::PackedFont::CONSTRUCT_ERROR; // Allocates buffer for sequential loading. const int readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE; // The size of the buffer specified in nn::font::PackedFont::GetRequireBufferSize must be greater than nn::font::PackedFont::HEADER_SIZE. // NN_ASSERT(readBufferSize >= nn::font::PackedFont::HEADER_SIZE); void* const readBuffer = s_AppHeap.Allocate(readBufferSize); if( readBuffer == NULL ) { NN_WARNING(false, "Failed to allocate the read buffer (%d bytes).", readBufferSize); return false; } // Loads the start of the font resource in order to obtain the buffer size required for font building. // readSize = pFileReader->Read(readBuffer, nn::font::PackedFont::HEADER_SIZE); if (readSize != nn::font::PackedFont::HEADER_SIZE) { s_AppHeap.Free(readBuffer); NN_LOG("Fail to load %d bytes. The BCFNA may be too small.", nn::font::PackedFont::HEADER_SIZE); return false; } // Gets the buffer size necessary for building the font, and allocates the buffer. // Specifies the glyph group to load for the second argument of GetRequireBufferSize. // Specifies the ratio of the area to cache the expanded sheet for the third argument of GetRequireBufferSize. // Specifies the ratio in values 0.0 - 1.0. // If the ratio is decreased, then the amount of memory required is reduced, but performance will be worse when rendering a large number of characters. // Increasing the ratio will have the opposite effect. const u32 fontBufferSize = nn::font::PackedFont::GetRequireBufferSize( readBuffer, glyphGroups, rate); if (fontBufferSize == 0) { s_AppHeap.Free(readBuffer); NN_LOG("GetRequireBufferSize failed."); return false; } void* fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment); if (fontBuffer == NULL) { s_AppHeap.Free(readBuffer); NN_LOG("Failed to allocate memory for the font buffer (%d bytes).", fontBufferSize); return false; } // Starts font building. // Specifies the glyph group to load for the fourth argument of InitStreamingConstruct. // Same glyph group used when obtaining the fontBufferSize must be used. pFont->InitStreamingConstruct(&context, fontBuffer, fontBufferSize, glyphGroups); // Loads resource successively from the file stream, and passes the resource to the StreamingConstruct. while (readSize > 0) { ret = pFont->StreamingConstruct(&context, readBuffer, static_cast(readSize)); if (ret == nn::font::PackedFont::CONSTRUCT_ERROR) { s_AppHeap.Free(fontBuffer); s_AppHeap.Free(readBuffer); NN_LOG("StreamingConstruct failed."); return false; } readSize = pFileReader->Read(readBuffer, readBufferSize); } if (readSize < 0) { // Error s_AppHeap.Free(fontBuffer); s_AppHeap.Free(readBuffer); NN_LOG("Failed to read the resource."); return false; } // Resource load completion / font building should also be completed. NN_ASSERT(ret == nn::font::PackedFont::CONSTRUCT_FINISH); // readBuffer will not be used anymore, so it may be released. // fontBuffer must not be released if the build is successful. s_AppHeap.Free(readBuffer); // The size associated with building is reported. NN_LOG("InitFontStreaming:\n" " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n", pFileReader->GetSize(), readBufferSize, fontBufferSize); return true; } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void CleanupFont(nn::font::PackedFont* pFont) { // Destroys fonts. void* buffer = pFont->Destroy(); // If the font is already built, a pointer to the buffer allocated at the build operation will be returned. if( buffer != NULL ) { s_AppHeap.Free(buffer); } // After font data is destroyed, it cannot be used as a font until another Construct. } //--------------------------------------------------------------------------- // // // // // //--------------------------------------------------------------------------- void SetupTextCamera( const nn::font::TextWriterResource& textWriterResource, int width, int height ) { #if defined(NN_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); // Set the projection matrix for an orthogonal projection { // Sets the origin at the upper left, and the Y and Z axes in opposite directions. 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); } // Set the model view matrix as an identity matrix { nn::math::MTX34 mv; nn::math::MTX34Identity(&mv); textWriterResource.SetViewMtx(mv); } } //--------------------------------------------------------------------------- // // // // // //--------------------------------------------------------------------------- void DrawAscii( const nn::font::Font* pFont, nn::font::TextWriterResource* pTextWriterResource, const wchar_t* title ) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nn::font::WideTextWriter writer; writer.SetFont(pFont); writer.SetTextWriterResource(pTextWriterResource); writer.SetupGX(); writer.SetCursor(0, 0); writer.Printf(L"DEMO: %ls\n", title); // Displays text sample. 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 //--------------------------------------------------------------------------- // //--------------------------------------------------------------------------- void StartDemo() { nn::fs::Initialize(); const size_t ROMFS_BUFFER_SIZE = 1024 * 64; static char buffer[ROMFS_BUFFER_SIZE]; NN_UTIL_PANIC_IF_FAILED( nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE)); // Prepare device memory uptr addrDeviceMemory = nn::os::GetDeviceMemoryAddress(); s_AppHeap.Initialize(addrDeviceMemory, nDeviceMemorySize ); uptr addrDeviceMemoryVideo = reinterpret_cast(s_AppHeap.Allocate(nDeviceMemorySizeVideo)); s_RenderSystem.Initialize(addrDeviceMemoryVideo, nDeviceMemorySizeVideo); nn::font::PackedFont fontDvdNormal; nn::font::PackedFont fontDvdStream; // Build font { nn::fs::FileReader fileReader(s_FontFilePath); fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN); #ifndef NN_BUILD_RELEASE const bool bSuccess = #endif // NN_BUILD_RELEASE InitFont(&fontDvdNormal, &fileReader, DEMO_LOAD_GROUPS, DEMO_CACHE_RATE); NN_ASSERTMSG(bSuccess, "Failed to load PackedFont by default."); fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN); #ifndef NN_BUILD_RELEASE const bool bSuccessStream = #endif // NN_BUILD_RELEASE InitFontStreaming(&fontDvdStream, &fileReader, DEMO_LOAD_GROUPS, DEMO_CACHE_RATE); NN_ASSERTMSG(bSuccessStream, "Failed to load PackedFont by streaming."); } // Build the render resource nn::font::TextWriterResource textWriterResource; InitShaders(&textWriterResource); textWriterResource.ActiveGlProgram(); InitDraw(); // After this, the application itself handles sleep TransitionHandler::EnableSleep(); // Display font data volatile bool loop = true; while (loop) { // Display font data s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); SetupTextCamera(textWriterResource, NN_GX_DISPLAY0_HEIGHT, NN_GX_DISPLAY0_WIDTH); DrawAscii(&fontDvdNormal, &textWriterResource, L"PackedFont - Construct"); s_RenderSystem.SwapBuffers(); s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); SetupTextCamera(textWriterResource, NN_GX_DISPLAY1_HEIGHT, NN_GX_DISPLAY1_WIDTH); DrawAscii(&fontDvdStream, &textWriterResource, L"PackedFont - StreamingConstruct"); s_RenderSystem.SwapBuffers(); s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); // Run sleep, HOME Menu, and POWER Menu transitions. TransitionHandler::Process(); // Determine whether there has been an exit notification. if (TransitionHandler::IsExitRequired()) { break; } } // Destroy font CleanupFont(&fontDvdStream); CleanupFont(&fontDvdNormal); s_AppHeap.Free(reinterpret_cast(addrDeviceMemoryVideo)); s_AppHeap.Finalize(); } //--------------------------------------------------------------------------- // //--------------------------------------------------------------------------- void nnMain() { NN_LOG("Demo Start\n"); // Initialize via the applet. // Sleep Mode is rejected automatically until TransitionHandler::EnableSleep is called. TransitionHandler::Initialize(); // Here we need to check for exit notifications. if (!TransitionHandler::IsExitRequired()) { StartDemo(); } // Finalize via the applet. TransitionHandler::Finalize(); NN_LOG("Demo End\n"); // Finalize the application. The call to nn::applet::CloseApplication does not return. nn::applet::CloseApplication(); }