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