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