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