1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: main.cpp
4
5 Copyright (C)2009-2010 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: 24605 $
14 *---------------------------------------------------------------------------*/
15
16
17 //------------------------------------------------------------------
18 // デモ: PackedFont
19 //
20 // 概要
21 // nw::font::PackedFont の構築と破棄のサンプルです。
22 // フォントリソースを一旦全てメモリに読み込んで構築する方法と
23 // 逐次読み込みながら構築していく方法の二通りを示します。
24 //
25 // 操作
26 // なし。
27 //
28 //------------------------------------------------------------------
29
30
31 #include <GLES2/gl2.h>
32 #include <GLES2/gl2ext.h>
33 #include <nn.h>
34 #include <nn/math.h>
35 #include <nn/fs.h>
36 #include <nw/assert.h>
37 #include <nw/font/font_WideTextWriter.h>
38 #include <nw/font/font_PackedFont.h>
39 #include <nw/demo.h>
40
41 #include <algorithm>
42
43 namespace
44 {
45
46 /*
47 順次読み込み用の読み込みバッファサイズ。
48
49 nw::font::PackedFont::GetRequireBufferSize() に指定するバッファのサイズは
50 nw::font::PackedFont::HEADER_SIZE 以上である必要があります。
51 */
52 const int DEMO_STREAMING_READ_BUFFER_SIZE = 16 * 1024;
53
54 const char DEMO_LOAD_GROUPS[] = "ascii";
55 // ASCII 文字をロードする
56 const f32 DEMO_CACHE_RATE = 0.3f;
57 // ロードするシートの 30 % 分のキャッシュを確保する
58
59 //---------------------------------------------------------------------------
60 //! @brief メモリを確保します。
61 //!
62 //! @param[in] size 確保するメモリのサイズ。
63 //! @param[in] alignment 確保するメモリのアライメント値。
64 //!
65 //! @return 確保したメモリへのポインタを返します。
66 //---------------------------------------------------------------------------
67 void*
MemAlloc(size_t size,u8 alignment=4)68 MemAlloc(
69 size_t size,
70 u8 alignment = 4
71 )
72 {
73 #if defined(NW_PLATFORM_CTR)
74 return nw::demo::SimpleApp::Allocate(size, alignment);
75 #else
76 return nw::demo::Alloc(size, alignment);
77 #endif
78 }
79
80 //---------------------------------------------------------------------------
81 //! @brief デバイスメモリからメモリを確保します。
82 //!
83 //! @param[in] size 確保するメモリのサイズ。
84 //! @param[in] alignment 確保するメモリのアライメント値。
85 //!
86 //! @return 確保したメモリへのポインタを返します。
87 //---------------------------------------------------------------------------
88 void*
DevMemAlloc(size_t size,u8 alignment=4)89 DevMemAlloc(
90 size_t size,
91 u8 alignment = 4
92 )
93 {
94 #if defined(NW_PLATFORM_CTR)
95 return nw::demo::SimpleApp::AllocateDeviceMemory(size, alignment);
96 #else
97 return nw::demo::Alloc(size, alignment);
98 #endif
99 }
100
101 //---------------------------------------------------------------------------
102 //! @brief メモリを解放します。
103 //!
104 //! @param[in] memory 解放するメモリへのポインタ。
105 //---------------------------------------------------------------------------
106 void
MemFree(void * memory)107 MemFree(void* memory)
108 {
109 #if defined(NW_PLATFORM_CTR)
110 nw::demo::SimpleApp::Free(memory);
111 #else
112 nw::demo::Free(memory);
113 #endif
114 }
115
116 //---------------------------------------------------------------------------
117 //! @brief シェーダの初期化を行います。
118 //!
119 //! @param[in,out] pResource 描画用リソースを管理するオブジェクトへのポインタ。
120 //---------------------------------------------------------------------------
121 void
InitShaders(nw::font::TextWriterResource * pResource)122 InitShaders(nw::font::TextWriterResource* pResource)
123 {
124 const wchar_t* shaders = NW_DEMO_FILE_PATH( NW_FONT_SHADERBINARY );
125 nn::fs::FileReader shaderReader(shaders);
126
127 const u32 fileSize = (u32)shaderReader.GetSize();
128
129 void* shaderBinary = MemAlloc(fileSize);
130
131 s32 read = shaderReader.Read(shaderBinary, fileSize);
132 NN_ASSERT(read == fileSize);
133
134 pResource->InitResource(shaderBinary, fileSize);
135
136 MemFree(shaderBinary);
137 }
138
139 //---------------------------------------------------------------------------
140 //! @brief 描画の初期設定を行います。
141 //---------------------------------------------------------------------------
142 void
InitDraw()143 InitDraw()
144 {
145 glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
146
147 glDisable(GL_CULL_FACE); // カリングを無効
148 glDisable(GL_SCISSOR_TEST); // シザー処理を無効
149 glDisable(GL_POLYGON_OFFSET_FILL); // ポリゴンオフセットを無効
150 #if defined(NW_PLATFORM_CTR)
151 glDisable(GL_EARLY_DEPTH_TEST_DMP); // アーリーデプステストを無効
152 #endif
153 glDisable(GL_DEPTH_TEST); // デプステストを無効
154 glDisable(GL_STENCIL_TEST); // ステンシルテストを無効
155
156 // カラーバッファの全ての成分を書き込み可
157 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
158 }
159
160 //---------------------------------------------------------------------------
161 //! @brief フォントリソースを一旦メモリに全て読み込んで
162 //! PackedFont を構築します。
163 //!
164 //! @param[out] pFont 構築するフォントへのポインタ。
165 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。
166 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。
167 //! @param[in] rate 確保するシートキャッシュの割合。
168 //!
169 //! @return PackedFont構築の成否を返します。
170 //---------------------------------------------------------------------------
171 bool
InitFont(nw::font::PackedFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups,f32 rate)172 InitFont(
173 nw::font::PackedFont* pFont,
174 nn::fs::FileReader* pFileReader,
175 const char* glyphGroups,
176 f32 rate
177 )
178 {
179 bool bSuccess;
180
181 // フォントリソースを全てメモリに読み込みます。
182 const u32 fileSize = (u32)pFileReader->GetSize();
183 if( fileSize <= 0 )
184 {
185 NN_LOG("fail to get FileStream size.");
186 return false;
187 }
188
189 const u32 readBufferSize = fileSize;
190 void* readBuffer = MemAlloc(readBufferSize);
191 if (readBuffer == NULL)
192 {
193 NN_LOG("fail to allocate memory for resource buffer(%d byte).", readBufferSize);
194 return false;
195 }
196
197 const int readSize = pFileReader->Read(readBuffer, readBufferSize);
198 if (readSize != readBufferSize)
199 {
200 MemFree(readBuffer);
201 NN_LOG("fail to read resource file.");
202 return false;
203 }
204
205
206 // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。
207 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。
208 // GetRequireBufferSize の第3引数には展開したシートをキャッシュする領域の割合を指定します。
209 // 割合は 0.0 ~ 1.0 の間で指定します。割合を小さくすれば必要なメモリ量は減りますが
210 // 多くの文字を描画する場合のパフォーマンスが悪化します。
211 // 割合を大きくすればその逆となります。
212 const u32 fontBufferSize = nw::font::PackedFont::GetRequireBufferSize(
213 readBuffer, glyphGroups, rate);
214 if (fontBufferSize == 0)
215 {
216 MemFree(readBuffer);
217 NN_LOG("fail to GetRequireBufferSize.");
218 return false;
219 }
220
221 void* const fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment);
222 if (fontBuffer == NULL)
223 {
224 MemFree(readBuffer);
225 NW_WARNING(false, "fail to allocate memory for font buffer(%d byte).", fontBufferSize);
226 return false;
227 }
228
229 // フォントを構築します。
230 // Construct の第4引数にはロードするグリフグループを指定します。
231 // fontBufferSize を求める時に使用したものと同じものを使用しなければなりません。
232 bSuccess = pFont->Construct(fontBuffer, fontBufferSize, readBuffer, glyphGroups);
233 NW_ASSERT(bSuccess);
234
235
236 //--- 既にフォントが構築されているか,リソースが不正な場合に失敗します。
237 if( ! bSuccess )
238 {
239 NN_LOG("fail to Construct.");
240 MemFree(fontBuffer);
241 }
242
243 // raedBuffer は以降使用しないので解放する事ができます。
244 // fontBuffer は構築に成功した場合は解放してはいけません。
245 MemFree(readBuffer);
246
247 // 構築に関与するサイズを Report します。
248 NN_LOG("InitFont:\n"
249 " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
250 pFileReader->GetSize(), readBufferSize, fontBufferSize);
251
252 return bSuccess;
253 }
254
255 //---------------------------------------------------------------------------
256 //! @brief フォントリソースを順次読み込みながら PackedFont を構築します。
257 //!
258 //! @param[out] pFont 構築するフォントへのポインタ。
259 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。
260 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。
261 //! @param[in] rate 確保するシートキャッシュの割合。
262 //!
263 //! @return PackedFont構築の成否を返します。
264 //---------------------------------------------------------------------------
265 bool
InitFontStreaming(nw::font::PackedFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups,f32 rate)266 InitFontStreaming(
267 nw::font::PackedFont* pFont,
268 nn::fs::FileReader* pFileReader,
269 const char* glyphGroups,
270 f32 rate
271 )
272 {
273 s32 readSize;
274 nw::font::PackedFont::ConstructContext context;
275 nw::font::PackedFont::ConstructResult ret = nw::font::PackedFont::CONSTRUCT_ERROR;
276
277 // 逐次読み込み用のバッファを確保します。
278 const u32 readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE;
279
280 // nw::font::PackedFont::GetRequireBufferSize() に指定するバッファのサイズは
281 // nw::font::PackedFont::HEADER_SIZE 以上である必要があります。
282 NN_ASSERT(readBufferSize >= nw::font::PackedFont::HEADER_SIZE);
283
284 void* const readBuffer = MemAlloc(readBufferSize);
285 if (readBuffer == NULL)
286 {
287 NW_WARNING(false, "fail to allocate read buffer(%d byte).", readBufferSize);
288 return false;
289 }
290
291 // フォントの構築に必要なバッファサイズを取得するため
292 // フォントリソースの先頭を読み取ります。
293 readSize = pFileReader->Read(readBuffer, nw::font::PackedFont::HEADER_SIZE);
294 if (readSize != nw::font::PackedFont::HEADER_SIZE)
295 {
296 MemFree(readBuffer);
297 NN_LOG("Fail to load %d bytes. Maybe too small bcfna.", nw::font::PackedFont::HEADER_SIZE);
298 return false;
299 }
300
301
302 // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。
303 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。
304 // GetRequireBufferSize の第3引数には展開したシートをキャッシュする領域の割合を指定します。
305 // 割合は 0.0 ~ 1.0 の間で指定します。割合を小さくすれば必要なメモリ量は減りますが
306 // 多くの文字を描画する場合のパフォーマンスが悪化します。
307 // 割合を大きくすればその逆となります。
308 const u32 fontBufferSize = nw::font::PackedFont::GetRequireBufferSize(
309 readBuffer, glyphGroups, rate);
310 if (fontBufferSize == 0)
311 {
312 MemFree(readBuffer);
313 NN_LOG("fail to GetRequireBufferSize.");
314 return false;
315 }
316
317 void* fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment);
318 if (fontBuffer == NULL)
319 {
320 MemFree(readBuffer);
321 NN_LOG("fail to allocate memory for font buffer(%d byte).", fontBufferSize);
322 return false;
323 }
324
325
326 // フォントの構築を開始します。
327 // InitStreamingConstruct の第4引数にはロードするグリフグループを指定します。
328 // fontBufferSize を求める時に使用したものと同じものを使用しなければなりません。
329 pFont->InitStreamingConstruct(&context, fontBuffer, fontBufferSize, glyphGroups);
330
331 // ファイルストリームから逐次リソースを読み取り、StreamingConstruct に渡していきます。
332 while (readSize > 0)
333 {
334 ret = pFont->StreamingConstruct(&context, readBuffer, static_cast<u32>(readSize));
335 if (ret == nw::font::PackedFont::CONSTRUCT_ERROR)
336 {
337 MemFree(fontBuffer);
338 MemFree(readBuffer);
339 NN_LOG("fail to StreamingConstruct.");
340 return false;
341 }
342
343 readSize = pFileReader->Read(readBuffer, readBufferSize);
344 }
345
346 if (readSize < 0)
347 {
348 // エラー
349 MemFree(fontBuffer);
350 MemFree(readBuffer);
351 NN_LOG("fail to read resource.");
352 return false;
353 }
354
355 // リソース読み込み完了 / フォント構築も完了しているはず
356 NW_ASSERT(ret == nw::font::PackedFont::CONSTRUCT_FINISH);
357
358 // raedBuffer は以降使用しないので解放する事ができます。
359 // fontBuffer は構築に成功した場合は解放してはいけません。
360 MemFree(readBuffer);
361
362 // 構築に関与するサイズを Report します。
363 NN_LOG("InitFontStreaming:\n"
364 " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
365 pFileReader->GetSize(), readBufferSize, fontBufferSize);
366
367 return true;
368 }
369
370 //---------------------------------------------------------------------------
371 //! @brief PackedFontを破棄します。
372 //!
373 //! @param[in] pFont 破棄するフォントへのポインタ。
374 //---------------------------------------------------------------------------
375 void
CleanupFont(nw::font::PackedFont * pFont)376 CleanupFont(nw::font::PackedFont* pFont)
377 {
378 // フォントを破棄します。
379 void* buffer = pFont->Destroy();
380
381 // 構築済みフォントであれば構築時に割り当てたバッファへのポインタが返ってきます。
382 if( buffer != NULL )
383 {
384 MemFree(buffer);
385 }
386
387 // Destroy 後は再度 Construct するまでフォントとして使用できません。
388 }
389
390 //---------------------------------------------------------------------------
391 //! @brief 文字列表示用にモデルビュー行列と射影行列を設定します。
392 //!
393 //! @param[in] textWriterResource TextWriterResourceオブジェクトへの参照。
394 //! @param[in] width 画面の幅。
395 //! @param[in] height 画面の高さ。
396 //---------------------------------------------------------------------------
397 void
SetupTextCamera(const nw::font::TextWriterResource & textWriterResource,int width,int height)398 SetupTextCamera(
399 const nw::font::TextWriterResource&
400 textWriterResource,
401 int width,
402 int height
403 )
404 {
405 #if defined(NW_PLATFORM_CTR)
406 const GLsizei lcdWidth = height;
407 const GLsizei lcdHeight = width;
408 #else
409 const GLsizei lcdWidth = width;
410 const GLsizei lcdHeight = height;
411 #endif
412 glViewport(0, 0, lcdWidth, lcdHeight);
413
414 // 射影行列を正射影に設定
415 {
416 // 左上原点とし、Y軸とZ軸の向きが逆になるように設定します。
417 nn::math::MTX44 proj;
418 f32 znear = 0.0f;
419 f32 zfar = -1.0f;
420 f32 t = 0;
421 f32 b = static_cast<f32>(height);
422 f32 l = 0;
423 f32 r = static_cast<f32>(width);
424 nn::math::MTX44OrthoPivot(&proj, l, r, b, t, znear, zfar, nn::math::PIVOT_UPSIDE_TO_TOP);
425 textWriterResource.SetProjectionMtx(proj);
426 }
427
428 // モデルビュー行列を単位行列に設定
429 {
430 nn::math::MTX34 mv;
431 nn::math::MTX34Identity(&mv);
432 textWriterResource.SetViewMtx(mv);
433 }
434 }
435
436 //---------------------------------------------------------------------------
437 //! @brief ASCII文字列を描画します。
438 //!
439 //! @param[in] pFont フォントへのポインタ。
440 //! @param[in] textWriterResource TextWriterResourceオブジェクトへの参照。
441 //! @param[in] title フォントオブジェクトの種類をあらわす文字列。
442 //---------------------------------------------------------------------------
443 void
DrawAscii(const nw::font::Font * pFont,nw::font::TextWriterResource * pTextWriterResource,const wchar_t * title)444 DrawAscii(
445 const nw::font::Font* pFont,
446 nw::font::TextWriterResource* pTextWriterResource,
447 const wchar_t* title
448 )
449 {
450 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
451
452 nw::font::WideTextWriter writer;
453
454 writer.SetFont(pFont);
455 writer.SetTextWriterResource(pTextWriterResource);
456 writer.SetupGX();
457 writer.SetCursor(0, 0);
458
459 writer.Printf(L"DEMO: %ls\n", title);
460
461 // 文字見本を表示
462 writer.Print(L"Glyph Sample:\n");
463 writer.MoveCursorX(5);
464 writer.Print(L" !\"#$%&'()*+,-./0123456789:;<=>?\n");
465 writer.Print(L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n");
466 writer.Print(L"`abcdefghijklmnopqrstuvwxyz{|}~\n");
467
468 glFlush();
469 }
470
471 } // namespace
472
473 //---------------------------------------------------------------------------
474 //! @brief サンプルのメイン関数です。
475 //---------------------------------------------------------------------------
476 void
nnMain()477 nnMain()
478 {
479 // os の初期化
480 nn::os::Initialize();
481
482 // fs の初期化
483 nn::fs::Initialize();
484
485 nw::demo::SimpleApp& demoApp = nw::demo::SimpleApp::GetInstance();
486
487 demoApp.Initialize();
488
489 nw::font::PackedFont fontNormal;
490 nw::font::PackedFont fontStream;
491
492 // フォントの構築
493 {
494 nn::fs::FileReader fileReader(NW_DEMO_FILE_PATH(L"tahoma.bcfna"));
495
496 fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
497 const bool bSuccess = InitFont(&fontNormal, &fileReader, DEMO_LOAD_GROUPS, DEMO_CACHE_RATE);
498 NW_ASSERTMSG(bSuccess, "Fail to load PackedFont by default.");
499
500 fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
501 const bool bSuccessStream = InitFontStreaming(&fontStream, &fileReader, DEMO_LOAD_GROUPS, DEMO_CACHE_RATE);
502 NW_ASSERTMSG(bSuccessStream, "Fail to load PackedFont by streaming.");
503 }
504
505 // 描画リソースの構築
506 nw::font::TextWriterResource textWriterResource;
507 InitShaders(&textWriterResource);
508
509 textWriterResource.ActiveGlProgram();
510
511 InitDraw();
512
513 // フォント情報の表示
514 volatile bool loop = true;
515 while (loop)
516 {
517 demoApp.SetRenderingTarget(demoApp.DISPLAY0);
518 {
519 glBindFramebuffer(GL_FRAMEBUFFER, demoApp.GetFrameBufferObject());
520 SetupTextCamera(textWriterResource, demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT);
521 DrawAscii(&fontNormal, &textWriterResource, L"PackedFont - Construct");
522 }
523
524 demoApp.SetRenderingTarget(demoApp.DISPLAY1);
525 {
526 glBindFramebuffer(GL_FRAMEBUFFER, demoApp.GetFrameBufferObject());
527 SetupTextCamera(textWriterResource, demoApp.DISPLAY1_WIDTH, demoApp.DISPLAY1_HEIGHT);
528 DrawAscii(&fontStream, &textWriterResource, L"PackedFont - StreamingConstruct");
529 }
530
531 demoApp.SwapBuffer(demoApp.DISPLAY_BOTH);
532 }
533
534 // フォントの破棄
535 CleanupFont(&fontStream);
536 CleanupFont(&fontNormal);
537 }
538