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: ArchiveFont
19 //
20 // Overview
21 //   This sample builds and destroys nn::font::ArchiveFont.
22 //   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.
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_RectDrawerShader.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::ArchiveFont::GetRequireBufferSize must be greater than nn::font::ArchiveFont::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 
61 //---------------------------------------------------------------------------
62 //
63 //
64 //
65 //---------------------------------------------------------------------------
66 void*
InitShaders(nn::font::RectDrawer * pDrawer)67 InitShaders(nn::font::RectDrawer* pDrawer)
68 {
69     nn::fs::FileReader shaderReader(s_ShaderBinaryFilePath);
70 
71     const u32 fileSize = (u32)shaderReader.GetSize();
72 
73     void* shaderBinary = s_AppHeap.Allocate(fileSize);
74     NN_NULL_ASSERT(shaderBinary);
75 
76 #ifndef NN_BUILD_RELEASE
77     s32 read =
78 #endif // NN_BUILD_RELEASE
79     shaderReader.Read(shaderBinary, fileSize);
80     NN_ASSERT(read == fileSize);
81 
82     const u32 vtxBufCmdBufSize =
83         nn::font::RectDrawer::GetVertexBufferCommandBufferSize(shaderBinary, fileSize);
84     void *const vtxBufCmdBuf = s_AppHeap.Allocate(vtxBufCmdBufSize);
85     NN_NULL_ASSERT(vtxBufCmdBuf);
86     pDrawer->Initialize(vtxBufCmdBuf, shaderBinary, fileSize);
87 
88     s_AppHeap.Free(shaderBinary);
89 
90     return vtxBufCmdBuf;
91 }
92 
93 /*---------------------------------------------------------------------------*
94 
95  *---------------------------------------------------------------------------*/
96 void
InitGX()97 InitGX()
98 {
99     glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
100 }
101 
102 //---------------------------------------------------------------------------
103 //
104 //
105 //
106 //
107 //---------------------------------------------------------------------------
108 void
InitDraw(int width,int height)109 InitDraw(
110     int     width,
111     int     height
112 )
113 {
114     // Color buffer information
115     // Switches the width and height to match the LCD direction.
116     const nn::font::ColorBufferInfo colBufInfo = { height, width, PICA_DATA_DEPTH24_STENCIL8_EXT };
117 
118     const u32 screenSettingCommands[] =
119     {
120         // Viewport settings
121         NN_FONT_CMD_SET_VIEWPORT( 0, 0, colBufInfo.width, colBufInfo.height ),
122 
123         // Disable scissoring
124         NN_FONT_CMD_SET_DISABLE_SCISSOR( colBufInfo ),
125 
126         // Disable W buffer
127         // Set the depth range
128         // Disable polygon offset
129         NN_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET(
130             0.0f,           // wScale : W buffer is disabled at 0.0
131             0.0f,           // depth range near
132             1.0f,           // depth range far
133             0,              // polygon offset units : polygon offset is disabled with 0.0
134             colBufInfo),
135     };
136 
137     nngxAdd3DCommand(screenSettingCommands, sizeof(screenSettingCommands), true);
138 
139     static const u32 s_InitCommands[] =
140     {
141         // Disable culling
142         NN_FONT_CMD_SET_CULL_FACE( NN_FONT_CMD_CULL_FACE_DISABLE ),
143 
144         // Disable stencil test
145         NN_FONT_CMD_SET_DISABLE_STENCIL_TEST(),
146 
147         // Disable depth test
148         // Make all elements of the color buffer writable
149         NN_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK(
150             false,  // isDepthTestEnabled
151             0,      // depthFunc
152             true,   // depthMask
153             true,   // red
154             true,   // Green
155             true,   // Blue
156             true),  // Alpha
157 
158         // Disable early depth test
159         NN_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST( false ),
160 
161         // Framebuffer access control
162         NN_FONT_CMD_SET_FBACCESS(
163             true,   // colorRead
164             true,   // colorWrite
165             false,  // depthRead
166             false,  // depthWrite
167             false,  // stencilRead
168             false), // stencilWrite
169     };
170 
171     nngxAdd3DCommand(s_InitCommands, sizeof(s_InitCommands), true);
172 }
173 
174 //---------------------------------------------------------------------------
175 //
176 //
177 //
178 //
179 //
180 //
181 //
182 //
183 //---------------------------------------------------------------------------
184 bool
InitFont(nn::font::ArchiveFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups)185 InitFont(
186     nn::font::ArchiveFont*  pFont,
187     nn::fs::FileReader*     pFileReader,
188     const char*             glyphGroups
189 )
190 {
191     bool bSuccess;
192 
193     // Loads all font resource to the memory.
194     const u32 fileSize = (u32)pFileReader->GetSize();
195     if (fileSize <= 0)
196     {
197         return false;
198     }
199 
200 
201     const u32 readBufferSize = fileSize;
202     void* readBuffer = s_AppHeap.Allocate(readBufferSize);
203     if (readBuffer == NULL)
204     {
205         return false;
206     }
207 
208     const int readSize = pFileReader->Read(readBuffer, readBufferSize);
209     if (readSize != readBufferSize)
210     {
211         s_AppHeap.Free(readBuffer);
212         return false;
213     }
214 
215 
216     // Gets the buffer size necessary for building the font, and allocates the buffer.
217     // Specifies the glyph group to load for the second argument of GetRequireBufferSize.
218     const u32 fontBufferSize = nn::font::ArchiveFont::GetRequireBufferSize(
219                                                     readBuffer, glyphGroups);
220     if (fontBufferSize == 0)
221     {
222         s_AppHeap.Free(readBuffer);
223         return false;
224     }
225 
226     void* const fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment);
227     if (fontBuffer == NULL)
228     {
229         s_AppHeap.Free(readBuffer);
230         return false;
231     }
232 
233     // Builds fonts.
234     // Specifies the glyph group to load for the fourth argument of Construct.
235     // Same glyph group used when obtaining the fontBufferSize must be used.
236     bSuccess = pFont->Construct(fontBuffer, fontBufferSize, readBuffer, glyphGroups);
237     NN_ASSERT( bSuccess );
238 
239 
240     //--- Fails if the font is already built or if the resource is invalid.
241     if (! bSuccess)
242     {
243         s_AppHeap.Free(fontBuffer);
244     }
245 
246     // readBuffer will not be used anymore, so it may be released.
247     // fontBuffer must not be released if the build is successful.
248     s_AppHeap.Free(readBuffer);
249 
250     // The size associated with building is reported.
251     NN_LOG("InitFont:\n"
252            "  fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
253            pFileReader->GetSize(), readBufferSize, fontBufferSize );
254 
255     return bSuccess;
256 }
257 
258 //---------------------------------------------------------------------------
259 //
260 //
261 //
262 //
263 //
264 //
265 //
266 //---------------------------------------------------------------------------
267 bool
InitFontStreaming(nn::font::ArchiveFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups)268 InitFontStreaming(
269     nn::font::ArchiveFont*  pFont,
270     nn::fs::FileReader*     pFileReader,
271     const char*             glyphGroups
272 )
273 {
274     s32 readSize;
275     nn::font::ArchiveFont::ConstructContext context;
276     nn::font::ArchiveFont::ConstructResult ret = nn::font::ArchiveFont::CONSTRUCT_ERROR;
277 
278     // Allocates buffer for sequential loading.
279     const u32 readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE;
280 
281     // The size of the buffer specified in nn::font::ArchiveFont::GetRequireBufferSize function must be greater than nn::font::ArchiveFont::HEADER_SIZE.
282     //
283     NN_ASSERT(readBufferSize >= nn::font::ArchiveFont::HEADER_SIZE);
284 
285     void* const readBuffer = s_AppHeap.Allocate(readBufferSize);
286     if (readBuffer == NULL)
287     {
288         NN_LOG("can't alloc %d bytes", readBufferSize);
289         return false;
290     }
291 
292     // Loads the start of the font resource in order to obtain the buffer size required for font building.
293     //
294     readSize = pFileReader->Read(readBuffer, nn::font::ArchiveFont::HEADER_SIZE);
295     if (readSize != nn::font::ArchiveFont::HEADER_SIZE)
296     {
297         s_AppHeap.Free(readBuffer);
298         NN_LOG("Fail to load %d bytes. The BCFNA may be too small.", nn::font::ArchiveFont::HEADER_SIZE);
299         return false;
300     }
301 
302     // Gets the buffer size necessary for building the font, and allocates the buffer.
303     // Specifies the glyph group to load for the second argument of GetRequireBufferSize.
304     const u32 fontBufferSize = nn::font::ArchiveFont::GetRequireBufferSize(
305                                                     readBuffer, glyphGroups);
306     if (fontBufferSize == 0)
307     {
308         s_AppHeap.Free(readBuffer);
309         NN_LOG("ArchiveFont::GetRequireBufferSize failed");
310         return false;
311     }
312 
313     void* fontBuffer = s_AppHeap.Allocate(fontBufferSize, nn::font::GlyphDataAlignment);
314     if (fontBuffer == NULL)
315     {
316         s_AppHeap.Free(readBuffer);
317         NN_WARNING(false, "can't alloc %d bytes", fontBufferSize);
318         return false;
319     }
320 
321 
322     // Starts font building.
323     // Specifies the glyph group to load for the fourth argument of InitStreamingConstruct.
324     // Same glyph group used when obtaining the fontBufferSize must be used.
325     pFont->InitStreamingConstruct(&context, fontBuffer, fontBufferSize, glyphGroups);
326 
327     // Loads resource successively from the file stream, and passes the resource to the StreamingConstruct.
328     while (readSize > 0)
329     {
330         ret = pFont->StreamingConstruct(&context, readBuffer, static_cast<u32>(readSize));
331         if (ret == nn::font::ArchiveFont::CONSTRUCT_ERROR)
332         {
333             s_AppHeap.Free(fontBuffer);
334             s_AppHeap.Free(readBuffer);
335             NN_LOG("ArchiveFont::StreamingConstruct return error");
336             return false;
337         }
338 
339         readSize = pFileReader->Read(readBuffer, readBufferSize);
340     }
341 
342     if (readSize < 0)
343     {
344         // Error
345         s_AppHeap.Free(fontBuffer);
346         s_AppHeap.Free(readBuffer);
347         NN_LOG("readSize(=%d) < 0", readSize);
348         return false;
349     }
350 
351     // Resource load completion / font building should also be completed.
352     NN_ASSERT(ret == nn::font::ArchiveFont::CONSTRUCT_FINISH);
353 
354     // readBuffer will not be used anymore, so it may be released.
355     // fontBuffer must not be released if the build is successful.
356     s_AppHeap.Free(readBuffer);
357 
358     // The size associated with building is reported.
359     NN_LOG("InitFontStreaming:\n"
360            "  fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
361            pFileReader->GetSize(), readBufferSize, fontBufferSize );
362 
363     return true;
364 }
365 
366 //---------------------------------------------------------------------------
367 //
368 //
369 //
370 //---------------------------------------------------------------------------
371 void
CleanupFont(nn::font::ArchiveFont * pFont)372 CleanupFont(nn::font::ArchiveFont* pFont)
373 {
374     // Destroys fonts.
375     void* buffer = pFont->Destroy();
376 
377     // If the font is already built, a pointer to the buffer allocated at the build operation will be returned.
378     if (buffer != NULL)
379     {
380         s_AppHeap.Free(buffer);
381     }
382 
383     // After font data is destroyed, it cannot be used as a font until another Construct.
384 }
385 
386 //---------------------------------------------------------------------------
387 //
388 //
389 //
390 //
391 //
392 //---------------------------------------------------------------------------
393 nn::font::DispStringBuffer*
AllocDispStringBuffer(int charMax)394 AllocDispStringBuffer(int charMax)
395 {
396     const u32 DrawBufferSize = nn::font::CharWriter::GetDispStringBufferSize(charMax);
397     void *const bufMem = s_AppHeap.Allocate(DrawBufferSize);
398     NN_NULL_ASSERT(bufMem);
399 
400     return nn::font::CharWriter::InitDispStringBuffer(bufMem, charMax);
401 }
402 
403 //---------------------------------------------------------------------------
404 //
405 //
406 //
407 //
408 //
409 //---------------------------------------------------------------------------
410 void
SetupTextCamera(nn::font::RectDrawer * pDrawer,int width,int height)411 SetupTextCamera(
412     nn::font::RectDrawer*   pDrawer,
413     int         			width,
414     int         			height
415 )
416 {
417     // Set the projection matrix for an orthogonal projection
418     {
419         // Sets the origin at the upper left, and the Y and Z axes in opposite directions.
420         nn::math::MTX44 proj;
421         f32 znear   =  0.0f;
422         f32 zfar    = -1.0f;
423         f32 t       =  0;
424         f32 b       =  static_cast<f32>(height);
425         f32 l       =  0;
426         f32 r       =  static_cast<f32>(width);
427         nn::math::MTX44OrthoPivot(&proj, l, r, b, t, znear, zfar, nn::math::PIVOT_UPSIDE_TO_TOP);
428         pDrawer->SetProjectionMtx(proj);
429     }
430 
431     // Set the model view matrix as an identity matrix
432     {
433         nn::math::MTX34 mv;
434         nn::math::MTX34Identity(&mv);
435         pDrawer->SetViewMtxForText(mv);
436     }
437 }
438 
439 //---------------------------------------------------------------------------
440 //
441 //
442 //
443 //
444 //
445 //
446 //
447 //
448 //---------------------------------------------------------------------------
449 void
DrawAscii(nn::font::RectDrawer * pDrawer,nn::font::DispStringBuffer * pDrawStringBuf,const nn::font::Font * pFont,int width,int height,const wchar_t * title)450 DrawAscii(
451     nn::font::RectDrawer*           pDrawer,
452     nn::font::DispStringBuffer*     pDrawStringBuf,
453     const nn::font::Font*           pFont,
454     int         			        width,
455     int         			        height,
456     const wchar_t*                  title
457 )
458 {
459     nn::font::WideTextWriter writer;
460     writer.SetDispStringBuffer(pDrawStringBuf);
461     writer.SetFont(pFont);
462 
463     writer.SetCursor(0, 0);
464 
465     writer.StartPrint();
466     writer.Printf(L"DEMO: %ls\n", title);
467 
468 //     Displays text sample.
469     writer.Print(L"Glyph Sample:\n");
470     writer.MoveCursorX(5);
471     writer.Print(L" !\"#$%&'()*+,-./0123456789:;<=>?\n");
472     writer.Print(L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n");
473     writer.Print(L"`abcdefghijklmnopqrstuvwxyz{|}~\n");
474     writer.EndPrint();
475 
476     pDrawer->BuildTextCommand(&writer);
477 
478     pDrawer->DrawBegin();
479 
480         SetupTextCamera(pDrawer, width, height);
481         writer.UseCommandBuffer();
482 
483     pDrawer->DrawEnd();
484 }
485 
486 }   // Namespace
487 
488 //---------------------------------------------------------------------------
489 //
490 //---------------------------------------------------------------------------
StartDemo()491 void StartDemo()
492 {
493     nn::fs::Initialize();
494 
495     const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
496     static char buffer[ROMFS_BUFFER_SIZE];
497     NN_UTIL_PANIC_IF_FAILED(
498         nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
499 
500     // Prepare device memory
501     uptr addrDeviceMemory = nn::os::GetDeviceMemoryAddress();
502     s_AppHeap.Initialize(addrDeviceMemory, nDeviceMemorySize );
503     uptr addrDeviceMemoryVideo = reinterpret_cast<uptr>(s_AppHeap.Allocate(nDeviceMemorySizeVideo));
504     s_RenderSystem.Initialize(addrDeviceMemoryVideo, nDeviceMemorySizeVideo);
505 
506     InitGX();
507 
508     nn::font::ArchiveFont fontNormal;
509     nn::font::ArchiveFont fontStream;
510 
511     // Build font
512     {
513         nn::fs::FileReader fileReader(s_FontFilePath);
514 
515         fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
516 #ifndef NN_BUILD_RELEASE
517         const bool bSuccess =
518 #endif // NN_BUILD_RELEASE
519         InitFont(&fontNormal, &fileReader, DEMO_LOAD_GROUPS);
520         NN_ASSERTMSG(bSuccess, "Fail to load ArchiveFont by default.");
521 
522         fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
523 #ifndef NN_BUILD_RELEASE
524         const bool bSuccessStream =
525 #endif // NN_BUILD_RELEASE
526         InitFontStreaming(&fontStream, &fileReader, DEMO_LOAD_GROUPS);
527         NN_ASSERTMSG(bSuccessStream, "Fail to load ArchiveFont by streaming.");
528     }
529 
530     // Build the render resource
531     nn::font::RectDrawer drawer;
532     void *const drawerBuf = InitShaders(&drawer);
533 
534     // Allocate buffer for render string
535     nn::font::DispStringBuffer *const pDrawStringBuf = AllocDispStringBuffer(512);
536 
537     // After this, the application itself handles sleep
538     TransitionHandler::EnableSleep();
539 
540     // Display font data
541     volatile bool loop = true;
542     while (loop)
543     {
544         s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
545         {
546             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
547 
548             InitDraw(NN_GX_DISPLAY0_HEIGHT, NN_GX_DISPLAY0_WIDTH);
549 
550             DrawAscii(
551                 &drawer,
552                 pDrawStringBuf,
553                 &fontNormal,
554                 NN_GX_DISPLAY0_HEIGHT,
555                 NN_GX_DISPLAY0_WIDTH,
556                 L"ArchiveFont - Construct");
557         }
558         s_RenderSystem.SwapBuffers();
559 
560         s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
561         {
562             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
563 
564             InitDraw(NN_GX_DISPLAY1_HEIGHT, NN_GX_DISPLAY1_WIDTH);
565 
566             DrawAscii(
567                 &drawer,
568                 pDrawStringBuf,
569                 &fontStream,
570                 NN_GX_DISPLAY1_HEIGHT,
571                 NN_GX_DISPLAY1_WIDTH,
572                 L"ArchiveFont - StreamingConstruct");
573         }
574         s_RenderSystem.SwapBuffers();
575 
576         s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
577 
578         // Run sleep, HOME Menu, and POWER Menu transitions.
579         TransitionHandler::Process();
580         // Determine whether there has been an exit notification.
581         if (TransitionHandler::IsExitRequired())
582         {
583             break;
584         }
585     }
586 
587     drawer.Finalize();
588 
589     // Destroy render resource
590     s_AppHeap.Free(drawerBuf);
591 
592     // Destroy font
593     CleanupFont(&fontStream);
594     CleanupFont(&fontNormal);
595 
596     // Free the render string buffer
597     s_AppHeap.Free(pDrawStringBuf);
598     s_AppHeap.Free(reinterpret_cast<void*>(addrDeviceMemoryVideo));
599 
600     s_AppHeap.Finalize();
601 }
602 
603 //---------------------------------------------------------------------------
604 //
605 //---------------------------------------------------------------------------
nnMain()606 void nnMain()
607 {
608     NN_LOG("Demo Start\n");
609 
610     // Initialize via the applet.
611     // Sleep Mode is rejected automatically until TransitionHandler::EnableSleep is called.
612     TransitionHandler::Initialize();
613     // Here we need to check for exit notifications.
614     if (!TransitionHandler::IsExitRequired())
615     {
616         StartDemo();
617     }
618     // Finalize via the applet.
619     TransitionHandler::Finalize();
620 
621     NN_LOG("Demo End\n");
622 
623     // Finalize the application. The call to nn::applet::CloseApplication does not return.
624     nn::applet::CloseApplication();
625 }
626