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