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 // デモ: ArchiveFont
21 //
22 // 概要
23 // nw::font::ArchiveFont の構築と破棄のサンプルです。
24 // フォントリソースを一旦全てメモリに読み込んで構築する方法と
25 // 逐次読み込みながら構築していく方法の二通りを示します。
26 //
27 // 操作
28 // なし。
29 //
30 //------------------------------------------------------------------
31
32 #include <GLES2/gl2.h>
33 #include <GLES2/gl2ext.h>
34 #include <nn.h>
35 #include <nn/math.h>
36 #include <nn/fs.h>
37 #include <nw/assert.h>
38 #include <nw/font/font_WideTextWriter.h>
39 #include <nw/font/font_ArchiveFont.h>
40 #include <nw/font/font_RectDrawer.h>
41 #include <nw/demo.h>
42
43 #include <algorithm>
44
45 namespace
46 {
47
48 /*
49 順次読み込み用の読み込みバッファサイズ。
50
51 nw::font::ArchiveFont::GetRequireBufferSize() に指定するバッファのサイズは
52 nw::font::ArchiveFont::HEADER_SIZE 以上である必要があります。
53 */
54 const int DEMO_STREAMING_READ_BUFFER_SIZE = 16 * 1024;
55
56 const char DEMO_LOAD_GROUPS[] = "ascii";
57 // ASCII 文字をロードする
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 return nw::demo::SimpleApp::Allocate(size, alignment);
74 }
75
76 //---------------------------------------------------------------------------
77 //! @brief デバイスメモリからメモリを確保します。
78 //!
79 //! @param[in] size 確保するメモリのサイズ。
80 //! @param[in] alignment 確保するメモリのアライメント値。
81 //!
82 //! @return 確保したメモリへのポインタを返します。
83 //---------------------------------------------------------------------------
84 void*
DevMemAlloc(size_t size,u8 alignment=4)85 DevMemAlloc(
86 size_t size,
87 u8 alignment = 4
88 )
89 {
90 return nw::demo::SimpleApp::AllocateDeviceMemory(size, alignment);
91 }
92
93 //---------------------------------------------------------------------------
94 //! @brief メモリを解放します。
95 //!
96 //! @param[in] memory 解放するメモリへのポインタ。
97 //---------------------------------------------------------------------------
98 void
MemFree(void * memory)99 MemFree(void* memory)
100 {
101 nw::demo::SimpleApp::Free(memory);
102 }
103
104 //---------------------------------------------------------------------------
105 //! @brief シェーダの初期化を行います。
106 //!
107 //! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。
108 //---------------------------------------------------------------------------
109 void*
InitShaders(nw::font::RectDrawer * pDrawer)110 InitShaders(nw::font::RectDrawer* pDrawer)
111 {
112 const wchar_t* shaders = NW_DEMO_FILE_PATH( NW_FONT_RECTDRAWER_SHADERBINARY );
113 nn::fs::FileReader shaderReader(shaders);
114
115 const u32 fileSize = (u32)shaderReader.GetSize();
116
117 void* shaderBinary = MemAlloc(fileSize);
118 NN_NULL_ASSERT(shaderBinary);
119
120 s32 read = shaderReader.Read(shaderBinary, fileSize);
121 NN_ASSERT(read == fileSize);
122
123 const u32 vtxBufCmdBufSize =
124 nw::font::RectDrawer::GetVertexBufferCommandBufferSize(shaderBinary, fileSize);
125 void *const vtxBufCmdBuf = DevMemAlloc(vtxBufCmdBufSize);
126 NN_NULL_ASSERT(vtxBufCmdBuf);
127 pDrawer->Initialize(vtxBufCmdBuf, shaderBinary, fileSize);
128
129 MemFree(shaderBinary);
130
131 return vtxBufCmdBuf;
132 }
133
134 //---------------------------------------------------------------------------
135 //! @brief 描画の初期設定を行います。
136 //!
137 //! @param[in] width 画面の幅。
138 //! @param[in] height 画面の高さ。
139 //---------------------------------------------------------------------------
140 void
InitDraw(int width,int height)141 InitDraw(
142 int width,
143 int height
144 )
145 {
146 // カラーバッファ情報
147 // LCDの向きに合わせて、幅と高さを入れ替えています。
148 const nw::font::ColorBufferInfo colBufInfo = { height, width, PICA_DATA_DEPTH24_STENCIL8_EXT };
149
150 const u32 screenSettingCommands[] =
151 {
152 // ビューポートの設定
153 NW_FONT_CMD_SET_VIEWPORT( 0, 0, colBufInfo.width, colBufInfo.height ),
154
155 // シザー処理を無効
156 NW_FONT_CMD_SET_DISABLE_SCISSOR( colBufInfo ),
157
158 // wバッファの無効化
159 // デプスレンジの設定
160 // ポリゴンオフセットの無効化
161 NW_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET(
162 0.0f, // wScale : 0.0 でWバッファが無効
163 0.0f, // depth range near
164 1.0f, // depth range far
165 0, // polygon offset units : 0.0 で ポリゴンオフセットが無効
166 colBufInfo),
167 };
168
169 nngxAdd3DCommand(screenSettingCommands, sizeof(screenSettingCommands), true);
170
171 static const u32 s_InitCommands[] =
172 {
173 // カリングを無効
174 NW_FONT_CMD_SET_CULL_FACE( NW_FONT_CMD_CULL_FACE_DISABLE ),
175
176 // ステンシルテストを無効
177 NW_FONT_CMD_SET_DISABLE_STENCIL_TEST(),
178
179 // デプステストを無効
180 // カラーバッファの全ての成分を書き込み可
181 NW_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK(
182 false, // isDepthTestEnabled
183 0, // depthFunc
184 true, // depthMask
185 true, // red
186 true, // green
187 true, // blue
188 true), // alpha
189
190 // アーリーデプステストを無効
191 NW_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST( false ),
192
193 // フレームバッファアクセス制御
194 NW_FONT_CMD_SET_FBACCESS(
195 true, // colorRead
196 true, // colorWrite
197 false, // depthRead
198 false, // depthWrite
199 false, // stencilRead
200 false), // stencilWrite
201 };
202
203 nngxAdd3DCommand(s_InitCommands, sizeof(s_InitCommands), true);
204 }
205
206 //---------------------------------------------------------------------------
207 //! @brief フォントリソースを一旦メモリに全て読み込んで
208 //! ArchiveFont を構築します。
209 //!
210 //! @param[out] pFont 構築するフォントへのポインタ。
211 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。
212 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。
213 //!
214 //! @return ArchiveFont構築の成否を返します。
215 //---------------------------------------------------------------------------
216 bool
InitFont(nw::font::ArchiveFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups)217 InitFont(
218 nw::font::ArchiveFont* pFont,
219 nn::fs::FileReader* pFileReader,
220 const char* glyphGroups
221 )
222 {
223 bool bSuccess;
224
225 // フォントリソースを全てメモリに読み込みます。
226 const u32 fileSize = (u32)pFileReader->GetSize();
227 if (fileSize <= 0)
228 {
229 return false;
230 }
231
232
233 const u32 readBufferSize = fileSize;
234 void* readBuffer = MemAlloc(readBufferSize);
235 if (readBuffer == NULL)
236 {
237 return false;
238 }
239
240 const int readSize = pFileReader->Read(readBuffer, readBufferSize);
241 if (readSize != readBufferSize)
242 {
243 MemFree(readBuffer);
244 return false;
245 }
246
247
248 // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。
249 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。
250 const u32 fontBufferSize = nw::font::ArchiveFont::GetRequireBufferSize(
251 readBuffer, glyphGroups);
252 if (fontBufferSize == 0)
253 {
254 MemFree(readBuffer);
255 return false;
256 }
257
258 void* const fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment);
259 if (fontBuffer == NULL)
260 {
261 MemFree(readBuffer);
262 return false;
263 }
264
265 // フォントを構築します。
266 // Construct の第4引数にはロードするグリフグループを指定します。
267 // fontBufferSize を求める時に使用したものと同じものを使用しなければなりません。
268 bSuccess = pFont->Construct(fontBuffer, fontBufferSize, readBuffer, glyphGroups);
269 NW_ASSERT( bSuccess );
270
271
272 //--- 既にフォントが構築されているか,リソースが不正な場合に失敗します。
273 if (! bSuccess)
274 {
275 MemFree(fontBuffer);
276 }
277
278 // raedBuffer は以降使用しないので解放する事ができます。
279 // fontBuffer は構築に成功した場合は解放してはいけません。
280 MemFree(readBuffer);
281
282 // 構築に関与するサイズを Report します。
283 NN_LOG("InitFont:\n"
284 " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
285 pFileReader->GetSize(), readBufferSize, fontBufferSize );
286
287 return bSuccess;
288 }
289
290 //---------------------------------------------------------------------------
291 //! @brief フォントリソースを順次読み込みながら ArchiveFont を構築します。
292 //!
293 //! @param[out] pFont 構築するフォントへのポインタ。
294 //! @param[in] pFileReader ロードするフォントリソースを指すファイルストリーム。
295 //! @param[in] glyphGroups メモリ上にロードするグリフグループ。
296 //!
297 //! @return ArchiveFont構築の成否を返します。
298 //---------------------------------------------------------------------------
299 bool
InitFontStreaming(nw::font::ArchiveFont * pFont,nn::fs::FileReader * pFileReader,const char * glyphGroups)300 InitFontStreaming(
301 nw::font::ArchiveFont* pFont,
302 nn::fs::FileReader* pFileReader,
303 const char* glyphGroups
304 )
305 {
306 s32 readSize;
307 nw::font::ArchiveFont::ConstructContext context;
308 nw::font::ArchiveFont::ConstructResult ret = nw::font::ArchiveFont::CONSTRUCT_ERROR;
309
310 // 逐次読み込み用のバッファを確保します。
311 const u32 readBufferSize = DEMO_STREAMING_READ_BUFFER_SIZE;
312
313 // nw::font::ArchiveFont::GetRequireBufferSize() に指定するバッファのサイズは
314 // nw::font::ArchiveFont::HEADER_SIZE 以上である必要があります。
315 NN_ASSERT(readBufferSize >= nw::font::ArchiveFont::HEADER_SIZE);
316
317 void* const readBuffer = MemAlloc(readBufferSize);
318 if (readBuffer == NULL)
319 {
320 NN_LOG("can't alloc %d bytes", readBufferSize);
321 return false;
322 }
323
324 // フォントの構築に必要なバッファサイズを取得するため
325 // フォントリソースの先頭を読み取ります。
326 readSize = pFileReader->Read(readBuffer, nw::font::ArchiveFont::HEADER_SIZE);
327 if (readSize != nw::font::ArchiveFont::HEADER_SIZE)
328 {
329 MemFree(readBuffer);
330 NN_LOG("Fail to load %d bytes. Maybe too small bcfna.", nw::font::ArchiveFont::HEADER_SIZE);
331 return false;
332 }
333
334 // フォントの構築に必要なバッファサイズを取得し、バッファを確保します。
335 // GetRequireBufferSize の第2引数にはロードするグリフグループを指定します。
336 const u32 fontBufferSize = nw::font::ArchiveFont::GetRequireBufferSize(
337 readBuffer, glyphGroups);
338 if (fontBufferSize == 0)
339 {
340 MemFree(readBuffer);
341 NN_LOG("ArchiveFont::GetRequireBufferSize failed");
342 return false;
343 }
344
345 void* fontBuffer = DevMemAlloc(fontBufferSize, nw::font::GlyphDataAlignment);
346 if (fontBuffer == NULL)
347 {
348 MemFree(readBuffer);
349 NW_WARNING(false, "can't alloc %d bytes", fontBufferSize);
350 return false;
351 }
352
353
354 // フォントの構築を開始します。
355 // InitStreamingConstruct の第4引数にはロードするグリフグループを指定します。
356 // fontBufferSize を求める時に使用したものと同じものを使用しなければなりません。
357 pFont->InitStreamingConstruct(&context, fontBuffer, fontBufferSize, glyphGroups);
358
359 // ファイルストリームから逐次リソースを読み取り、StreamingConstruct に渡していきます。
360 while (readSize > 0)
361 {
362 ret = pFont->StreamingConstruct(&context, readBuffer, static_cast<u32>(readSize));
363 if (ret == nw::font::ArchiveFont::CONSTRUCT_ERROR)
364 {
365 MemFree(fontBuffer);
366 MemFree(readBuffer);
367 NN_LOG("ArchiveFont::StreamingConstruct return error");
368 return false;
369 }
370
371 readSize = pFileReader->Read(readBuffer, readBufferSize);
372 }
373
374 if (readSize < 0)
375 {
376 // エラー
377 MemFree(fontBuffer);
378 MemFree(readBuffer);
379 NN_LOG("readSize(=%d) < 0", readSize);
380 return false;
381 }
382
383 // リソース読み込み完了 / フォント構築も完了しているはず
384 NW_ASSERT(ret == nw::font::ArchiveFont::CONSTRUCT_FINISH);
385
386 // raedBuffer は以降使用しないので解放する事ができます。
387 // fontBuffer は構築に成功した場合は解放してはいけません。
388 MemFree(readBuffer);
389
390 // 構築に関与するサイズを Report します。
391 NN_LOG("InitFontStreaming:\n"
392 " fileSize=%7lld readBufferSize=%7d fontBufferSize=%7d\n",
393 pFileReader->GetSize(), readBufferSize, fontBufferSize );
394
395 return true;
396 }
397
398 //---------------------------------------------------------------------------
399 //! @brief ArchiveFontを破棄します。
400 //!
401 //! @param[in] pFont 破棄するフォントへのポインタ。
402 //---------------------------------------------------------------------------
403 void
CleanupFont(nw::font::ArchiveFont * pFont)404 CleanupFont(nw::font::ArchiveFont* pFont)
405 {
406 // フォントを破棄します。
407 void* buffer = pFont->Destroy();
408
409 // 構築済みフォントであれば構築時に割り当てたバッファへのポインタが返ってきます。
410 if (buffer != NULL)
411 {
412 MemFree(buffer);
413 }
414
415 // Destroy 後は再度 Construct するまでフォントとして使用できません。
416 }
417
418 //---------------------------------------------------------------------------
419 //! @brief 表示文字列用バッファを確保します。
420 //!
421 //! @param[in] charMax 表示する文字列の最大文字数。
422 //!
423 //! @return 確保した表示文字列用バッファへのポインタを返します。
424 //---------------------------------------------------------------------------
425 nw::font::DispStringBuffer*
AllocDispStringBuffer(int charMax)426 AllocDispStringBuffer(int charMax)
427 {
428 const u32 DrawBufferSize = nw::font::CharWriter::GetDispStringBufferSize(charMax);
429 void *const bufMem = MemAlloc(DrawBufferSize);
430 NN_NULL_ASSERT(bufMem);
431
432 return nw::font::CharWriter::InitDispStringBuffer(bufMem, charMax);
433 }
434
435 //---------------------------------------------------------------------------
436 //! @brief 文字列表示用にモデルビュー行列と射影行列を設定します。
437 //!
438 //! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。
439 //! @param[in] width 画面の幅。
440 //! @param[in] height 画面の高さ。
441 //---------------------------------------------------------------------------
442 void
SetupTextCamera(nw::font::RectDrawer * pDrawer,int width,int height)443 SetupTextCamera(
444 nw::font::RectDrawer* pDrawer,
445 int width,
446 int height
447 )
448 {
449 // 射影行列を正射影に設定
450 {
451 // 左上原点とし、Y軸とZ軸の向きが逆になるように設定します。
452 nn::math::MTX44 proj;
453 f32 znear = 0.0f;
454 f32 zfar = -1.0f;
455 f32 t = 0;
456 f32 b = static_cast<f32>(height);
457 f32 l = 0;
458 f32 r = static_cast<f32>(width);
459 nn::math::MTX44OrthoPivot(&proj, l, r, b, t, znear, zfar, nn::math::PIVOT_UPSIDE_TO_TOP);
460 pDrawer->SetProjectionMtx(proj);
461 }
462
463 // モデルビュー行列を単位行列に設定
464 {
465 nn::math::MTX34 mv;
466 nn::math::MTX34Identity(&mv);
467 pDrawer->SetViewMtxForText(mv);
468 }
469 }
470
471 //---------------------------------------------------------------------------
472 //! @brief ASCII文字列を描画します。
473 //!
474 //! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。
475 //! @param[in] pDrawStringBuf DispStringBufferオブジェクトへのポインタ。
476 //! @param[in] pFont フォントへのポインタ。
477 //! @param[in] width 画面の幅。
478 //! @param[in] height 画面の高さ。
479 //! @param[in] title フォントオブジェクトの種類をあらわす文字列。
480 //---------------------------------------------------------------------------
481 void
DrawAscii(nw::font::RectDrawer * pDrawer,nw::font::DispStringBuffer * pDrawStringBuf,const nw::font::Font * pFont,int width,int height,const wchar_t * title)482 DrawAscii(
483 nw::font::RectDrawer* pDrawer,
484 nw::font::DispStringBuffer* pDrawStringBuf,
485 const nw::font::Font* pFont,
486 int width,
487 int height,
488 const wchar_t* title
489 )
490 {
491 nw::font::WideTextWriter writer;
492 writer.SetDispStringBuffer(pDrawStringBuf);
493 writer.SetFont(pFont);
494
495 writer.SetCursor(0, 0);
496
497 writer.StartPrint();
498 writer.Printf(L"DEMO: %ls\n", title);
499
500 // 文字見本を表示
501 writer.Print(L"Glyph Sample:\n");
502 writer.MoveCursorX(5);
503 writer.Print(L" !\"#$%&'()*+,-./0123456789:;<=>?\n");
504 writer.Print(L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n");
505 writer.Print(L"`abcdefghijklmnopqrstuvwxyz{|}~\n");
506 writer.EndPrint();
507
508 pDrawer->BuildTextCommand(&writer);
509
510 pDrawer->DrawBegin();
511
512 SetupTextCamera(pDrawer, width, height);
513 writer.UseCommandBuffer();
514
515 pDrawer->DrawEnd();
516 }
517
518 } // namespace
519
520 //---------------------------------------------------------------------------
521 //! @brief サンプルのメイン関数です。
522 //---------------------------------------------------------------------------
523 void
nnMain()524 nnMain()
525 {
526 // os の初期化
527 nn::os::Initialize();
528
529 // fs の初期化
530 nn::fs::Initialize();
531
532 nw::demo::SimpleApp& demoApp = nw::demo::SimpleApp::GetInstance();
533
534 demoApp.Initialize();
535
536 nw::font::ArchiveFont fontNormal;
537 nw::font::ArchiveFont fontStream;
538
539 // フォントの構築
540 {
541 nn::fs::FileReader fileReader(NW_DEMO_FILE_PATH(L"tahoma.bcfna"));
542
543 fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
544 const bool bSuccess = InitFont(&fontNormal, &fileReader, DEMO_LOAD_GROUPS);
545 NW_ASSERTMSG(bSuccess, "Fail to load ArchiveFont by default.");
546
547 fileReader.Seek(0, nn::fs::POSITION_BASE_BEGIN);
548 const bool bSuccessStream = InitFontStreaming(&fontStream, &fileReader, DEMO_LOAD_GROUPS);
549 NW_ASSERTMSG(bSuccessStream, "Fail to load ArchiveFont by streaming.");
550 }
551
552 // 描画リソースの構築
553 nw::font::RectDrawer drawer;
554
555 void *const drawerBuf = InitShaders(&drawer);
556
557 // 描画文字列用バッファの確保
558 nw::font::DispStringBuffer *const pDrawStringBuf = AllocDispStringBuffer(512);
559
560 const nw::ut::FloatColor clearColor(0.3f, 0.3f, 0.3f, 1.0f);
561 const f32 clearDepth = 0.0f;
562
563 // フォント情報の表示
564 volatile bool loop = true;
565 while (loop)
566 {
567 demoApp.SetRenderingTarget(demoApp.DISPLAY0);
568 {
569 demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth);
570
571 InitDraw(demoApp.DISPLAY0_WIDTH, demoApp.DISPLAY0_HEIGHT);
572
573 DrawAscii(
574 &drawer,
575 pDrawStringBuf,
576 &fontNormal,
577 demoApp.DISPLAY0_WIDTH,
578 demoApp.DISPLAY0_HEIGHT,
579 L"ArchiveFont - Construct");
580 }
581
582 demoApp.SetRenderingTarget(demoApp.DISPLAY1);
583 {
584 demoApp.GetFrameBufferObject().ClearBuffer(clearColor, clearDepth);
585
586 InitDraw(demoApp.DISPLAY1_WIDTH, demoApp.DISPLAY1_HEIGHT);
587
588 DrawAscii(
589 &drawer,
590 pDrawStringBuf,
591 &fontStream,
592 demoApp.DISPLAY1_WIDTH,
593 demoApp.DISPLAY1_HEIGHT,
594 L"ArchiveFont - StreamingConstruct");
595 }
596
597 demoApp.SwapBuffer(demoApp.DISPLAY_BOTH);
598 }
599
600 // 描画文字列用バッファの解放
601 MemFree(pDrawStringBuf);
602
603 drawer.Finalize();
604
605 MemFree(drawerBuf);
606
607 // フォントの破棄
608 CleanupFont(&fontStream);
609 CleanupFont(&fontNormal);
610 }
611