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