1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     main.cpp
4 
5   Copyright (C)2009-2011 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 47435 $
14  *---------------------------------------------------------------------------*/
15 
16 
17 //------------------------------------------------------------------
18 // Demo: PackedFont
19 //
20 // Overview
21 //   This sample builds and destroys nn::font::PackedFont.
22 //   Two methods are shown: one builds after loading all font resources into memory at once, and the other builds while sequentially loading font resources.
23 //
24 //
25 // Controls
26 //   None.
27 //
28 //------------------------------------------------------------------
29 
30 #include <nn.h>
31 #include <nn/fs.h>
32 #include <nn/font.h>
33 #include <nn/math.h>
34 
35 #include "demo.h"
36 #include "applet.h"
37 
38 namespace
39 {
40 const char s_ShaderBinaryFilePath[] = "rom:/nnfont_TextWriterShader.shbin";
41 const char s_FontFilePath[] = "rom:/tahoma.bcfna";
42 
43 nn::fnd::ExpHeap          s_AppHeap;
44 demo::RenderSystemDrawing s_RenderSystem;
45 
46 const s32 nDeviceMemorySizeVideo = 4 * 1024 * 1024;
47 const s32 nDeviceMemorySizeOther = 4 * 1024 * 1024;
48 const s32 nDeviceMemorySize = nDeviceMemorySizeVideo + nDeviceMemorySizeOther;
49 
50 /*
51     Load buffer size for sequential loading.
52 
53     The size of the buffer specified in nn::font::PackedFont::GetRequireBufferSize function must be greater than nn::font::PackedFont::HEADER_SIZE.
54 
55  */
56 const int DEMO_STREAMING_READ_BUFFER_SIZE   = 16 * 1024;
57 
58 const char DEMO_LOAD_GROUPS[]    = "ascii";
59     // Load ASCII characters
60 const f32 DEMO_CACHE_RATE        = 0.3f;
61     // Allocate a cache that is 30% worth of the sheet loaded.
62 
63 //---------------------------------------------------------------------------
64 //
65 //
66 //
67 //---------------------------------------------------------------------------
68 void
InitShaders(nn::font::TextWriterResource * pResource)69 InitShaders(nn::font::TextWriterResource* pResource)
70 {
71     nn::fs::FileReader shaderReader(s_ShaderBinaryFilePath);
72 
73     const u32 fileSize = (u32)shaderReader.GetSize();
74 
75     void* shaderBinary = s_AppHeap.Allocate(fileSize);
76 
77 #ifndef NN_BUILD_RELEASE
78     s32 read =
79 #endif // NN_BUILD_RELEASE
80     shaderReader.Read(shaderBinary, fileSize);
81     NN_ASSERT(read == fileSize);
82 
83     pResource->InitResource(shaderBinary, fileSize);
84 
85     s_AppHeap.Free(shaderBinary);
86 }
87 
88 //---------------------------------------------------------------------------
89 //
90 //---------------------------------------------------------------------------
91 void
InitDraw()92 InitDraw()
93 {
94     glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
95 
96     glDisable(GL_CULL_FACE);            // Disable culling
97     glDisable(GL_SCISSOR_TEST);         // Disable scissoring
98     glDisable(GL_POLYGON_OFFSET_FILL);  // Disable polygon offset
99 #if defined(NN_PLATFORM_CTR)
100     glDisable(GL_EARLY_DEPTH_TEST_DMP); // Disable early depth test
101 #endif
102     glDisable(GL_DEPTH_TEST);           // Disable depth test
103     glDisable(GL_STENCIL_TEST);         // Disable stencil test
104 
105     // Make all elements of the color buffer writable
106     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
107 }
108 
109 //---------------------------------------------------------------------------
110 //
111 //
112 //
113 //
114 //
115 //
116 //
117 //
118 //
119 //---------------------------------------------------------------------------
120 bool
InitFont(nn::font::PackedFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups,f32 rate)121 InitFont(
122     nn::font::PackedFont*   pFont,
123     nn::fs::FileReader*     pFileReader,
124     const char*             glyphGroups,
125     f32                     rate
126 )
127 {
128     bool bSuccess;
129 
130     // Loads all font resource to the memory.
131     const u32 fileSize = (u32)pFileReader->GetSize();
132     if( fileSize <= 0 )
133     {
134         NN_LOG("Failed to get FileStream size.");
135         return false;
136     }
137 
138     const u32 readBufferSize = fileSize;
139     void* readBuffer = s_AppHeap.Allocate(readBufferSize);
140     if (readBuffer == NULL)
141     {
142         NN_LOG("Failed to allocate memory for the resource buffer (%d bytes).", readBufferSize);
143         return false;
144     }
145 
146     const int readSize = pFileReader->Read(readBuffer, readBufferSize);
147     if (readSize != readBufferSize)
148     {
149         s_AppHeap.Free(readBuffer);
150         NN_LOG("Failed to read resource file.");
151         return false;
152     }
153 
154 
155     // Gets the buffer size necessary for building the font, and allocates the buffer.
156     // Specifies the glyph group to load for the second argument of GetRequireBufferSize.
157     // Specifies the ratio of the area to cache the expanded sheet for the third argument of GetRequireBufferSize.
158     // Specifies the ratio in values 0.0 - 1.0.
159     // 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.
160     // Increasing the ratio will have the opposite effect.
161     const u32 fontBufferSize = nn::font::PackedFont::GetRequireBufferSize(
162                                             readBuffer, glyphGroups, rate);
163     if (fontBufferSize == 0)
164     {
165         s_AppHeap.Free(readBuffer);
166         NN_LOG("GetRequireBufferSize failed.");
167         return false;
168     }
169 
170     void* const fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment);
171     if (fontBuffer == NULL)
172     {
173         s_AppHeap.Free(readBuffer);
174         NN_WARNING(false, "Failed to allocate memory for the font buffer (%d bytes).", fontBufferSize);
175         return false;
176     }
177 
178     // Builds fonts.
179     // Specifies the glyph group to load for the fourth argument of Construct.
180     // Same glyph group used when obtaining the fontBufferSize must be used.
181     bSuccess = pFont->Construct(fontBuffer, fontBufferSize, readBuffer, glyphGroups);
182     NN_ASSERT(bSuccess);
183 
184 
185     //--- Fails if the font is already built or if the resource is invalid.
186     if( ! bSuccess )
187     {
188         NN_LOG("Failed to Construct.");
189         s_AppHeap.Free(fontBuffer);
190     }
191 
192     // readBuffer will not be used anymore, so it may be released.
193     // fontBuffer must not be released if the build is successful.
194     s_AppHeap.Free(readBuffer);
195 
196     // The size associated with building is reported.
197     NN_LOG("InitFont:\n"
198            "  fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
199            pFileReader->GetSize(), readBufferSize, fontBufferSize);
200 
201     return bSuccess;
202 }
203 
204 //---------------------------------------------------------------------------
205 //
206 //
207 //
208 //
209 //
210 //
211 //
212 //
213 //---------------------------------------------------------------------------
214 bool
InitFontStreaming(nn::font::PackedFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups,f32 rate)215 InitFontStreaming(
216     nn::font::PackedFont*   pFont,
217     nn::fs::FileReader*     pFileReader,
218     const char*             glyphGroups,
219     f32                     rate
220 )
221 {
222     s32 readSize;
223     nn::font::PackedFont::ConstructContext context;
224     nn::font::PackedFont::ConstructResult ret = nn::font::PackedFont::CONSTRUCT_ERROR;
225 
226     // Allocates buffer for sequential loading.
227     const int readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE;
228 
229     // The size of the buffer specified in nn::font::PackedFont::GetRequireBufferSize must be greater than nn::font::PackedFont::HEADER_SIZE.
230     //
231     NN_ASSERT(readBufferSize >= nn::font::PackedFont::HEADER_SIZE);
232 
233     void* const readBuffer = s_AppHeap.Allocate(readBufferSize);
234     if( readBuffer == NULL )
235     {
236         NN_WARNING(false, "Failed to allocate the read buffer (%d bytes).", readBufferSize);
237         return false;
238     }
239 
240     // Loads the start of the font resource in order to obtain the buffer size required for font building.
241     //
242     readSize = pFileReader->Read(readBuffer, nn::font::PackedFont::HEADER_SIZE);
243     if (readSize != nn::font::PackedFont::HEADER_SIZE)
244     {
245         s_AppHeap.Free(readBuffer);
246         NN_LOG("Fail to load %d bytes. The BCFNA may be too small.", nn::font::PackedFont::HEADER_SIZE);
247         return false;
248     }
249 
250 
251     // Gets the buffer size necessary for building the font, and allocates the buffer.
252     // Specifies the glyph group to load for the second argument of GetRequireBufferSize.
253     // Specifies the ratio of the area to cache the expanded sheet for the third argument of GetRequireBufferSize.
254     // Specifies the ratio in values 0.0 - 1.0.
255     // 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.
256     // Increasing the ratio will have the opposite effect.
257     const u32 fontBufferSize = nn::font::PackedFont::GetRequireBufferSize(
258                                             readBuffer, glyphGroups, rate);
259     if (fontBufferSize == 0)
260     {
261         s_AppHeap.Free(readBuffer);
262         NN_LOG("GetRequireBufferSize failed.");
263         return false;
264     }
265 
266     void* fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment);
267     if (fontBuffer == NULL)
268     {
269         s_AppHeap.Free(readBuffer);
270         NN_LOG("Failed to allocate memory for the font buffer (%d bytes).", fontBufferSize);
271         return false;
272     }
273 
274 
275     // Starts font building.
276     // Specifies the glyph group to load for the fourth argument of InitStreamingConstruct.
277     // Same glyph group used when obtaining the fontBufferSize must be used.
278     pFont->InitStreamingConstruct(&context, fontBuffer, fontBufferSize, glyphGroups);
279 
280     // Loads resource successively from the file stream, and passes the resource to the StreamingConstruct.
281     while (readSize > 0)
282     {
283         ret = pFont->StreamingConstruct(&context, readBuffer, static_cast<u32>(readSize));
284         if (ret == nn::font::PackedFont::CONSTRUCT_ERROR)
285         {
286             s_AppHeap.Free(fontBuffer);
287             s_AppHeap.Free(readBuffer);
288             NN_LOG("StreamingConstruct failed.");
289             return false;
290         }
291 
292         readSize = pFileReader->Read(readBuffer, readBufferSize);
293     }
294 
295     if (readSize < 0)
296     {
297         // Error
298         s_AppHeap.Free(fontBuffer);
299         s_AppHeap.Free(readBuffer);
300         NN_LOG("Failed to read the resource.");
301         return false;
302     }
303 
304     // Resource load completion / font building should also be completed.
305     NN_ASSERT(ret == nn::font::PackedFont::CONSTRUCT_FINISH);
306 
307     // readBuffer will not be used anymore, so it may be released.
308     // fontBuffer must not be released if the build is successful.
309     s_AppHeap.Free(readBuffer);
310 
311     // The size associated with building is reported.
312     NN_LOG("InitFontStreaming:\n"
313            "  fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
314            pFileReader->GetSize(), readBufferSize, fontBufferSize);
315 
316     return true;
317 }
318 
319 //---------------------------------------------------------------------------
320 //
321 //
322 //
323 //---------------------------------------------------------------------------
324 void
CleanupFont(nn::font::PackedFont * pFont)325 CleanupFont(nn::font::PackedFont* pFont)
326 {
327     // Destroys fonts.
328     void* buffer = pFont->Destroy();
329 
330     // If the font is already built, a pointer to the buffer allocated at the build operation will be returned.
331     if( buffer != NULL )
332     {
333         s_AppHeap.Free(buffer);
334     }
335 
336     // After font data is destroyed, it cannot be used as a font until another Construct.
337 }
338 
339 //---------------------------------------------------------------------------
340 //
341 //
342 //
343 //
344 //
345 //---------------------------------------------------------------------------
346 void
SetupTextCamera(const nn::font::TextWriterResource & textWriterResource,int width,int height)347 SetupTextCamera(
348     const nn::font::TextWriterResource&
349                 textWriterResource,
350     int         width,
351     int         height
352 )
353 {
354 #if defined(NN_PLATFORM_CTR)
355     const GLsizei lcdWidth  = height;
356     const GLsizei lcdHeight = width;
357 #else
358     const GLsizei lcdWidth  = width;
359     const GLsizei lcdHeight = height;
360 #endif
361     glViewport(0, 0, lcdWidth, lcdHeight);
362 
363     // Set the projection matrix for an orthogonal projection
364     {
365         // Sets the origin at the upper left, and the Y and Z axes in opposite directions.
366         nn::math::MTX44 proj;
367         f32 znear   =  0.0f;
368         f32 zfar    = -1.0f;
369         f32 t       =  0;
370         f32 b       =  static_cast<f32>(height);
371         f32 l       =  0;
372         f32 r       =  static_cast<f32>(width);
373         nn::math::MTX44OrthoPivot(&proj, l, r, b, t, znear, zfar, nn::math::PIVOT_UPSIDE_TO_TOP);
374         textWriterResource.SetProjectionMtx(proj);
375     }
376 
377     // Set the model view matrix as an identity matrix
378     {
379         nn::math::MTX34 mv;
380         nn::math::MTX34Identity(&mv);
381         textWriterResource.SetViewMtx(mv);
382     }
383 }
384 
385 //---------------------------------------------------------------------------
386 //
387 //
388 //
389 //
390 //
391 //---------------------------------------------------------------------------
392 void
DrawAscii(const nn::font::Font * pFont,nn::font::TextWriterResource * pTextWriterResource,const wchar_t * title)393 DrawAscii(
394     const nn::font::Font*           pFont,
395     nn::font::TextWriterResource*   pTextWriterResource,
396     const wchar_t*                  title
397 )
398 {
399     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
400 
401     nn::font::WideTextWriter writer;
402 
403     writer.SetFont(pFont);
404     writer.SetTextWriterResource(pTextWriterResource);
405     writer.SetupGX();
406     writer.SetCursor(0, 0);
407 
408     writer.Printf(L"DEMO: %ls\n", title);
409 
410     // Displays text sample.
411     writer.Print(L"Glyph Sample:\n");
412     writer.MoveCursorX(5);
413     writer.Print(L" !\"#$%&'()*+,-./0123456789:;<=>?\n");
414     writer.Print(L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n");
415     writer.Print(L"`abcdefghijklmnopqrstuvwxyz{|}~\n");
416 
417     glFlush();
418 }
419 
420 }   // Namespace
421 
422 //---------------------------------------------------------------------------
423 //
424 //---------------------------------------------------------------------------
StartDemo()425 void StartDemo()
426 {
427     nn::fs::Initialize();
428 
429     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
430     static char buffer[ROMFS_BUFFER_SIZE];
431     NN_UTIL_PANIC_IF_FAILED(
432         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
433 
434     // Prepare device memory
435     uptr addrDeviceMemory = nn::os::GetDeviceMemoryAddress();
436     s_AppHeap.Initialize(addrDeviceMemory, nDeviceMemorySize );
437     uptr addrDeviceMemoryVideo = reinterpret_cast<uptr>(s_AppHeap.Allocate(nDeviceMemorySizeVideo));
438     s_RenderSystem.Initialize(addrDeviceMemoryVideo, nDeviceMemorySizeVideo);
439 
440     nn::font::PackedFont fontDvdNormal;
441     nn::font::PackedFont fontDvdStream;
442 
443     // Build font
444     {
445         nn::fs::FileReader fileReader(s_FontFilePath);
446 
447         fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
448 #ifndef NN_BUILD_RELEASE
449         const bool bSuccess =
450 #endif // NN_BUILD_RELEASE
451         InitFont(&fontDvdNormal, &fileReader, DEMO_LOAD_GROUPS, DEMO_CACHE_RATE);
452         NN_ASSERTMSG(bSuccess, "Failed to load PackedFont by default.");
453 
454         fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
455 #ifndef NN_BUILD_RELEASE
456         const bool bSuccessStream =
457 #endif // NN_BUILD_RELEASE
458         InitFontStreaming(&fontDvdStream, &fileReader, DEMO_LOAD_GROUPS, DEMO_CACHE_RATE);
459         NN_ASSERTMSG(bSuccessStream, "Failed to load PackedFont by streaming.");
460     }
461 
462     // Build the render resource
463     nn::font::TextWriterResource textWriterResource;
464     InitShaders(&textWriterResource);
465 
466     textWriterResource.ActiveGlProgram();
467 
468     InitDraw();
469 
470     // After this, the application itself handles sleep
471     TransitionHandler::EnableSleep();
472 
473     // Display font data
474     volatile bool loop = true;
475     while (loop)
476     {
477         // Display font data
478         s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
479         SetupTextCamera(textWriterResource, NN_GX_DISPLAY0_HEIGHT, NN_GX_DISPLAY0_WIDTH);
480         DrawAscii(&fontDvdNormal, &textWriterResource, L"PackedFont - Construct");
481         s_RenderSystem.SwapBuffers();
482 
483         s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
484         SetupTextCamera(textWriterResource, NN_GX_DISPLAY1_HEIGHT, NN_GX_DISPLAY1_WIDTH);
485         DrawAscii(&fontDvdStream, &textWriterResource, L"PackedFont - StreamingConstruct");
486         s_RenderSystem.SwapBuffers();
487 
488         s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
489 
490         // Run sleep, HOME Menu, and POWER Menu transitions.
491         TransitionHandler::Process();
492         // Determine whether there has been an exit notification.
493         if (TransitionHandler::IsExitRequired())
494         {
495             break;
496         }
497     }
498 
499     // Destroy font
500     CleanupFont(&fontDvdStream);
501     CleanupFont(&fontDvdNormal);
502     s_AppHeap.Free(reinterpret_cast<void*>(addrDeviceMemoryVideo));
503 
504     s_AppHeap.Finalize();
505 }
506 
507 //---------------------------------------------------------------------------
508 //
509 //---------------------------------------------------------------------------
nnMain()510 void nnMain()
511 {
512     NN_LOG("Demo Start\n");
513 
514     // Initialize via the applet.
515     // Sleep Mode is rejected automatically until TransitionHandler::EnableSleep is called.
516     TransitionHandler::Initialize();
517     // Here we need to check for exit notifications.
518     if (!TransitionHandler::IsExitRequired())
519     {
520         StartDemo();
521     }
522     // Finalize via the applet.
523     TransitionHandler::Finalize();
524 
525     NN_LOG("Demo End\n");
526 
527     // Finalize the application. The call to nn::applet::CloseApplication does not return.
528     nn::applet::CloseApplication();
529 }
530