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