/*---------------------------------------------------------------------------* 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: ArchiveFont // // Overview // This sample builds and destroys nn::font::ArchiveFont. // There are two methods described for building the font resources: load all into the memory at once and build or load sequentially and build as it loads. // // // Controls // None. // //------------------------------------------------------------------ #include #include #include #include #include "demo.h" #include "applet.h" namespace { const char s_ShaderBinaryFilePath[] = "rom:/nnfont_RectDrawerShader.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::ArchiveFont::GetRequireBufferSize must be greater than nn::font::ArchiveFont::HEADER_SIZE. */ const int DEMO_STREAMING_READ_BUFFER_SIZE = 16 * 1024; const char DEMO_LOAD_GROUPS[] = "ascii"; // Load ASCII characters //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void* InitShaders(nn::font::RectDrawer* pDrawer) { nn::fs::FileReader shaderReader(s_ShaderBinaryFilePath); const u32 fileSize = (u32)shaderReader.GetSize(); void* shaderBinary = s_AppHeap.Allocate(fileSize); NN_NULL_ASSERT(shaderBinary); #ifndef NN_BUILD_RELEASE s32 read = #endif // NN_BUILD_RELEASE shaderReader.Read(shaderBinary, fileSize); NN_ASSERT(read == fileSize); const u32 vtxBufCmdBufSize = nn::font::RectDrawer::GetVertexBufferCommandBufferSize(shaderBinary, fileSize); void *const vtxBufCmdBuf = s_AppHeap.Allocate(vtxBufCmdBufSize); NN_NULL_ASSERT(vtxBufCmdBuf); pDrawer->Initialize(vtxBufCmdBuf, shaderBinary, fileSize); s_AppHeap.Free(shaderBinary); return vtxBufCmdBuf; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ void InitGX() { glClearColor(0.3f, 0.3f, 0.3f, 1.0f); } //--------------------------------------------------------------------------- // // // // //--------------------------------------------------------------------------- void InitDraw( int width, int height ) { // Color buffer information // Switches the width and height to match the LCD direction. const nn::font::ColorBufferInfo colBufInfo = { height, width, PICA_DATA_DEPTH24_STENCIL8_EXT }; const u32 screenSettingCommands[] = { // Viewport settings NN_FONT_CMD_SET_VIEWPORT( 0, 0, colBufInfo.width, colBufInfo.height ), // Disable scissoring NN_FONT_CMD_SET_DISABLE_SCISSOR( colBufInfo ), // Disable W buffer // Set the depth range // Disable polygon offset NN_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET( 0.0f, // wScale : W buffer is disabled at 0.0 0.0f, // depth range near 1.0f, // depth range far 0, // polygon offset units : polygon offset is disabled with 0.0 colBufInfo), }; nngxAdd3DCommand(screenSettingCommands, sizeof(screenSettingCommands), true); static const u32 s_InitCommands[] = { // Disable culling NN_FONT_CMD_SET_CULL_FACE( NN_FONT_CMD_CULL_FACE_DISABLE ), // Disable stencil test NN_FONT_CMD_SET_DISABLE_STENCIL_TEST(), // Disable depth test // Make all elements of the color buffer writable NN_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK( false, // isDepthTestEnabled 0, // depthFunc true, // depthMask true, // red true, // Green true, // Blue true), // Alpha // Disable early depth test NN_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST( false ), // Framebuffer access control NN_FONT_CMD_SET_FBACCESS( true, // colorRead true, // colorWrite false, // depthRead false, // depthWrite false, // stencilRead false), // stencilWrite }; nngxAdd3DCommand(s_InitCommands, sizeof(s_InitCommands), true); } //--------------------------------------------------------------------------- // // // // // // // // //--------------------------------------------------------------------------- bool InitFont( nn::font::ArchiveFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups ) { bool bSuccess; // Loads all font resource to the memory. const u32 fileSize = (u32)pFileReader->GetSize(); if (fileSize <= 0) { return false; } const u32 readBufferSize = fileSize; void* readBuffer = s_AppHeap.Allocate(readBufferSize); if (readBuffer == NULL) { return false; } const int readSize = pFileReader->Read(readBuffer, readBufferSize); if (readSize != readBufferSize) { s_AppHeap.Free(readBuffer); 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. const u32 fontBufferSize = nn::font::ArchiveFont::GetRequireBufferSize( readBuffer, glyphGroups); if (fontBufferSize == 0) { s_AppHeap.Free(readBuffer); return false; } void* const fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment); if (fontBuffer == NULL) { s_AppHeap.Free(readBuffer); 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) { 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::ArchiveFont* pFont, nn::fs::FileReader* pFileReader, const char* glyphGroups ) { s32 readSize; nn::font::ArchiveFont::ConstructContext context; nn::font::ArchiveFont::ConstructResult ret = nn::font::ArchiveFont::CONSTRUCT_ERROR; // Allocates buffer for sequential loading. const u32 readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE; // The size of the buffer specified in nn::font::ArchiveFont::GetRequireBufferSize function must be greater than nn::font::ArchiveFont::HEADER_SIZE. // NN_ASSERT(readBufferSize >= nn::font::ArchiveFont::HEADER_SIZE); void* const readBuffer = s_AppHeap.Allocate(readBufferSize); if (readBuffer == NULL) { NN_LOG("can't alloc %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::ArchiveFont::HEADER_SIZE); if (readSize != nn::font::ArchiveFont::HEADER_SIZE) { s_AppHeap.Free(readBuffer); NN_LOG("Fail to load %d bytes. The BCFNA may be too small.", nn::font::ArchiveFont::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. const u32 fontBufferSize = nn::font::ArchiveFont::GetRequireBufferSize( readBuffer, glyphGroups); if (fontBufferSize == 0) { s_AppHeap.Free(readBuffer); NN_LOG("ArchiveFont::GetRequireBufferSize failed"); return false; } void* fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment); if (fontBuffer == NULL) { s_AppHeap.Free(readBuffer); NN_WARNING(false, "can't alloc %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::ArchiveFont::CONSTRUCT_ERROR) { s_AppHeap.Free(fontBuffer); s_AppHeap.Free(readBuffer); NN_LOG("ArchiveFont::StreamingConstruct return error"); return false; } readSize = pFileReader->Read(readBuffer, readBufferSize); } if (readSize < 0) { // Error s_AppHeap.Free(fontBuffer); s_AppHeap.Free(readBuffer); NN_LOG("readSize(=%d) < 0", readSize); return false; } // Resource load completion / font building should also be completed. NN_ASSERT(ret == nn::font::ArchiveFont::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::ArchiveFont* 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. } //--------------------------------------------------------------------------- // // // // // //--------------------------------------------------------------------------- nn::font::DispStringBuffer* AllocDispStringBuffer(int charMax) { const u32 DrawBufferSize = nn::font::CharWriter::GetDispStringBufferSize(charMax); void *const bufMem = s_AppHeap.Allocate(DrawBufferSize); NN_NULL_ASSERT(bufMem); return nn::font::CharWriter::InitDispStringBuffer(bufMem, charMax); } //--------------------------------------------------------------------------- // // // // // //--------------------------------------------------------------------------- void SetupTextCamera( nn::font::RectDrawer* pDrawer, int width, int height ) { // 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); pDrawer->SetProjectionMtx(proj); } // Set the model view matrix as an identity matrix { nn::math::MTX34 mv; nn::math::MTX34Identity(&mv); pDrawer->SetViewMtxForText(mv); } } //--------------------------------------------------------------------------- // // // // // // // // //--------------------------------------------------------------------------- void DrawAscii( nn::font::RectDrawer* pDrawer, nn::font::DispStringBuffer* pDrawStringBuf, const nn::font::Font* pFont, int width, int height, const wchar_t* title ) { nn::font::WideTextWriter writer; writer.SetDispStringBuffer(pDrawStringBuf); writer.SetFont(pFont); writer.SetCursor(0, 0); writer.StartPrint(); 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"); writer.EndPrint(); pDrawer->BuildTextCommand(&writer); pDrawer->DrawBegin(); SetupTextCamera(pDrawer, width, height); writer.UseCommandBuffer(); pDrawer->DrawEnd(); } } // 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); InitGX(); nn::font::ArchiveFont fontNormal; nn::font::ArchiveFont fontStream; // 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(&fontNormal, &fileReader, DEMO_LOAD_GROUPS); NN_ASSERTMSG(bSuccess, "Fail to load ArchiveFont by default."); fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN); #ifndef NN_BUILD_RELEASE const bool bSuccessStream = #endif // NN_BUILD_RELEASE InitFontStreaming(&fontStream, &fileReader, DEMO_LOAD_GROUPS); NN_ASSERTMSG(bSuccessStream, "Fail to load ArchiveFont by streaming."); } // Build the render resource nn::font::RectDrawer drawer; void *const drawerBuf = InitShaders(&drawer); // Allocate buffer for render string nn::font::DispStringBuffer *const pDrawStringBuf = AllocDispStringBuffer(512); // After this, the application itself handles sleep TransitionHandler::EnableSleep(); // Display font data volatile bool loop = true; while (loop) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); InitDraw(NN_GX_DISPLAY0_HEIGHT, NN_GX_DISPLAY0_WIDTH); DrawAscii( &drawer, pDrawStringBuf, &fontNormal, NN_GX_DISPLAY0_HEIGHT, NN_GX_DISPLAY0_WIDTH, L"ArchiveFont - Construct"); } s_RenderSystem.SwapBuffers(); s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); InitDraw(NN_GX_DISPLAY1_HEIGHT, NN_GX_DISPLAY1_WIDTH); DrawAscii( &drawer, pDrawStringBuf, &fontStream, NN_GX_DISPLAY1_HEIGHT, NN_GX_DISPLAY1_WIDTH, L"ArchiveFont - 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; } } drawer.Finalize(); // Destroy render resource s_AppHeap.Free(drawerBuf); // Destroy font CleanupFont(&fontStream); CleanupFont(&fontNormal); // Free the render string buffer s_AppHeap.Free(pDrawStringBuf); 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(); }