1 /*---------------------------------------------------------------------------*
2   Project:  font demo program
3   File:     fntdemo1.c
4 
5   Copyright 2006 Nintendo. 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   $Log: fntdemo1.c,v $
14   Revision 1.1  2006/10/18 02:52:17  nishida_yasunari
15   Initial check in.
16 
17   $NoKeywords: $
18  *---------------------------------------------------------------------------*/
19 
20 #include <demo.h>
21 #include <revolution/sc.h>
22 #include <revolution/fnt.h>
23 
24 /*-----------------------------------------------------------------------------
25     Constants
26   -----------------------------------------------------------------------------*/
27 static const char* FONT_FILE_PATH_1 = "/fonts/wbf1.brfna";
28 static const char* FONT_FILE_PATH_2 = "/fonts/wbf2.brfna";
29 
30 static const int TEXTURE_COODINATE_FRACTION_BITS = 15;
31 static const u32 TEXTURE_COODINATE_ONE = (1 << TEXTURE_COODINATE_FRACTION_BITS);
32 
33 /*-----------------------------------------------------------------------------
34   Name:         SetupTextCamera
35 
36   Description:  Sets up text camera.
37 
38   Arguments:    None.
39 
40   Returns:      None.
41   -----------------------------------------------------------------------------*/
SetupTextCamera(void)42 static void SetupTextCamera( void )
43 {
44     {
45         Mtx44 p;
46         f32 znear   = 0.0F;
47         f32 zfar    = 1.0F;
48         f32 t       = 0;
49         f32 b       = 480;
50         f32 l       = 0;
51         f32 r       = 640;
52 
53         MTXOrtho(p, t, b, l, r, znear, zfar);
54         GXSetProjection(p, GX_ORTHOGRAPHIC);
55     }
56 
57     {
58         Mtx mv;
59         MTXIdentity(mv);
60         GXLoadPosMtxImm(mv, GX_PNMTX0);
61         GXSetCurrentMtx(GX_PNMTX0);
62     }
63 }
64 
65 /*-----------------------------------------------------------------------------
66   Name:         SetupTextGX
67 
68   Description:  Sets up text GX.
69 
70   Arguments:    None.
71 
72   Returns:      None.
73   -----------------------------------------------------------------------------*/
SetupTextGX(void)74 static void SetupTextGX( void )
75 {
76     GXSetNumChans(1);
77     GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
78     GXSetChanCtrl(GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
79     GXSetNumTexGens(1);
80     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
81     GXSetNumTevStages(1);
82     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
83     GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_RASC, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO);
84     GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
85     GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
86     GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
87     GXSetNumIndStages(0);
88     GXSetTevDirect(GX_TEVSTAGE0);
89     GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET);
90 
91     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS , GX_POS_XYZ, GX_F32, 0);
92     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST , GX_U16, TEXTURE_COODINATE_FRACTION_BITS);
93     GXClearVtxDesc();
94     GXSetVtxDesc(GX_VA_POS , GX_DIRECT);
95     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
96 
97     GXSetChanMatColor(GX_COLOR0A0, (GXColor){255, 255, 255, 255 });
98 }
99 
100 /*-----------------------------------------------------------------------------
101   Name:         DrawChar
102 
103   Description:  Draws one character.
104 
105   Arguments:    x, y, z     Coordinates
106                 tex         Pointer to a font texture
107                 scaleX      Horizontal scale
108                 scaleY      Vertical scale
109                 lastImage   Pointer to a pointer to the texture image that was last loaded
110 
111   Returns:      None.
112   -----------------------------------------------------------------------------*/
DrawChar(f32 x,f32 y,f32 z,const FNTTexture * tex,f32 scaleX,f32 scaleY,void ** lastImage)113 static void DrawChar(
114     f32 x, f32 y, f32 z,
115     const FNTTexture* tex,
116     f32 scaleX, f32 scaleY,
117     void** lastImage )
118 {
119     f32 posLeft   = x       + tex->left       * scaleX;
120     f32 posTop    = y;
121     f32 posRight  = posLeft + tex->glyphWidth * scaleX;
122     f32 posBottom = posTop  + tex->charHeight * scaleY;
123 
124     u16 texLeft   = (u16)(tex->cellX
125                     * TEXTURE_COODINATE_ONE / tex->texWidth);
126     u16 texTop    = (u16)(tex->cellY
127                     * TEXTURE_COODINATE_ONE / tex->texHeight);
128     u16 texRight  = (u16)((tex->cellX + tex->glyphWidth)
129                     * TEXTURE_COODINATE_ONE / tex->texWidth);
130     u16 texBottom = (u16)((tex->cellY + tex->charHeight)
131                     * TEXTURE_COODINATE_ONE / tex->texHeight);
132 
133     if (tex->image != *lastImage)
134     {
135         GXTexObj tobj;
136         GXTexFilter filter = GX_LINEAR;
137         GXInitTexObj(&tobj, tex->image, tex->texWidth, tex->texHeight,
138             tex->texFormat, GX_CLAMP, GX_CLAMP, GX_FALSE);
139         GXInitTexObjLOD(&tobj, filter, filter, 0, 0, 0,
140                 GX_DISABLE, GX_DISABLE, GX_ANISO_1);
141         GXLoadTexObj(&tobj, GX_TEXMAP0);
142         *lastImage = tex->image;
143     }
144 
145     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
146     {
147         GXPosition3f32(posLeft, posTop, z);
148         GXTexCoord2u16(texLeft, texTop);
149 
150         GXPosition3f32(posRight, posTop, z);
151         GXTexCoord2u16(texRight, texTop);
152 
153         GXPosition3f32(posRight, posBottom, z);
154         GXTexCoord2u16(texRight, texBottom);
155 
156         GXPosition3f32(posLeft, posBottom, z);
157         GXTexCoord2u16(texLeft, texBottom);
158     }
159     GXEnd();
160 }
161 
162 /*-----------------------------------------------------------------------------
163   Name:         DrawString
164 
165   Description:  Draws a string.
166 
167   Arguments:    font        Pointer to font header
168                 x, y, z     Coordinates
169                 string      String
170                 scaleX      Horizontal scale
171                 scaleY      Vertical scale
172                 fixedWidth  fixed width (proportional if 0 is specified)
173                 lastImage   Pointer to a pointer to the texture image that was last loaded
174 
175   Returns:      Total string width in pixels.
176   -----------------------------------------------------------------------------*/
DrawString(const FNTHeader * font,f32 x,f32 y,f32 z,const char * string,f32 scaleX,f32 scaleY,f32 fixedWidth,void ** lastImage)177 static f32 DrawString(
178     const FNTHeader* font,
179     f32 x, f32 y, f32 z,
180     const char* string,
181     f32 scaleX, f32 scaleY,
182     f32 fixedWidth,
183     void** lastImage )
184 {
185     f32 startX = x;
186     BOOL utf16 = (FNTGetEncoding(font) == FNT_ENCODING_UTF16);
187 
188     while (*string || (utf16 && *(string + 1)))
189     {
190         FNTTexture tex;
191         f32 scaleWd, margin;
192         string = FNTGetTexture(font, string, &tex);
193         scaleWd = tex.charWidth * scaleX;
194         margin = (fixedWidth > 0.0F) ? (fixedWidth - scaleWd) / 2.0F : 0.0F;
195         DrawChar(x + margin, y, z, &tex, scaleX, scaleY, lastImage);
196         x += (fixedWidth > 0.0F) ? fixedWidth : scaleWd;
197     }
198 
199     return (x - startX);
200 }
201 
202 /*-----------------------------------------------------------------------------
203   Name:         GetStringWidth
204 
205   Description:  Gets string width.
206 
207   Arguments:    font        Pointer to font header
208                 string      String
209                 scaleX      Horizontal scale
210 
211   Returns:      Total string width in pixels.
212   -----------------------------------------------------------------------------*/
GetStringWidth(const FNTHeader * font,const char * string,f32 scaleX)213 static f32 GetStringWidth(
214     const FNTHeader* font,
215     const char* string,
216     f32 scaleX )
217 {
218     f32 totalWidth;
219     BOOL utf16 = (FNTGetEncoding(font) == FNT_ENCODING_UTF16);
220 
221     totalWidth = 0.0F;
222     while (*string || (utf16 && *(string + 1)))
223     {
224         s32 width;
225         string = FNTGetWidth(font, string, &width);
226         totalWidth += width * scaleX;
227     }
228 
229     return totalWidth;
230 }
231 
232 /*-----------------------------------------------------------------------------
233   Name:         DrawSample
234 
235   Description:  Draws a sample.
236 
237   Arguments:    font        Pointer to font header
238                 x, y, z     Coordinates
239 
240   Returns:      Y coordinate of next line.
241   -----------------------------------------------------------------------------*/
DrawSample(const FNTHeader * font,f32 x,f32 y,f32 z)242 static f32 DrawSample(
243     const FNTHeader* font,
244     f32 x, f32 y, f32 z )
245 {
246     f32 scaleX = 1.F;
247     f32 scaleY = 1.F;
248     FNTMetrics metrics;
249     void* lastImage = NULL;
250     f32 drawW, getW;
251     const char* str0 = " !\"#$%&'()*+,-./0123456789:;<=>?";
252     const char* str1 = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
253     const char* str2 = "`abcdefghijklmnopqrstuvwxyz{|}~";
254     const char* str3 = "Wii";
255     const char* str4 = "\xca\xdd\xb6\xb8\x20\x82\xa9\x82\xc8\x20\x8a\xbf\x8e\x9a"; // Half-width   Kana   Kanji
256     f32 startX = x;
257 
258     // Get metrics
259     FNTGetMetrics(font, &metrics);
260 
261     // Draw proportional string
262     drawW = DrawString(font, x, y, z, str0, scaleX, scaleY, 0.F, &lastImage);
263     y += metrics.leading * scaleY;
264     drawW = DrawString(font, x, y, z, str1, scaleX, scaleY, 0.F, &lastImage);
265     y += metrics.leading * scaleY;
266     drawW = DrawString(font, x, y, z, str2, scaleX, scaleY, 0.F, &lastImage);
267     y += metrics.leading * scaleY;
268 
269     scaleX = scaleY = 1.5F; // Change scale
270     drawW = DrawString(font, x, y, z, str3, scaleX, scaleY, 0.F, &lastImage);
271     x += drawW + metrics.width * scaleX;
272 
273     // Get width test
274     getW = GetStringWidth(font, str3, scaleX);
275     OSReport("Width Test: %f %f\n", drawW, getW);
276 
277     // Draw fixed-width string
278     drawW = DrawString(font, x, y, z, str3, scaleX, scaleY,
279                        metrics.width * scaleX, &lastImage);
280     x = startX;
281     y += metrics.leading * scaleY;
282     scaleX = scaleY = 1.F; // Restore scale
283 
284     // Draw SJIS string
285     if (FNTGetEncoding(font) == FNT_ENCODING_SJIS)
286     {
287         drawW = DrawString(font, x, y, z, str4, scaleX, scaleY, 0.F, &lastImage);
288         y += metrics.leading * scaleY;
289     }
290 
291     return y;
292 }
293 
294 /*---------------------------------------------------------------------------*
295   Name:         ReadFileAll
296 
297   Description:  Reads an entire file.
298 
299   Arguments:    ppBuffer    Pointer to a pointer to the read buffer
300                 filePath    File path
301 
302   Returns:      TRUE if successful, FALSE otherwise.
303  *---------------------------------------------------------------------------*/
ReadFileAll(void ** ppBuffer,const char * filePath)304 static BOOL ReadFileAll( void** ppBuffer, const char* filePath )
305 {
306     DVDFileInfo fi;
307     u32 fileSize;
308     u32 readBufferSize;
309     s32 readSize;
310 
311     if (!DVDOpen(filePath, &fi))
312     {
313         return FALSE;
314     }
315 
316     fileSize = DVDGetLength(&fi);
317     if (fileSize == 0)
318     {
319         return FALSE;
320     }
321 
322     readBufferSize = OSRoundUp32B(fileSize);
323     *ppBuffer = OSAlloc(readBufferSize);
324 
325     readSize = DVDRead(&fi, *ppBuffer, (s32)readBufferSize, 0);
326     DVDClose(&fi);
327     if (readSize != readBufferSize)
328     {
329         return FALSE;
330     }
331 
332     return TRUE;
333 }
334 
335 /*-----------------------------------------------------------------------------
336   Name:         InitFont
337 
338   Description:  Reads a font file entirely to memory and constructs the font data.
339 
340   Arguments:    ppFont      Pointer to a pointer to the font header
341                 filePath    Font file path
342 
343   Returns:      TRUE if successful, FALSE otherwise.
344   -----------------------------------------------------------------------------*/
InitFont(FNTHeader ** ppFont,const char * filePath)345 static BOOL InitFont( FNTHeader** ppFont, const char* filePath )
346 {
347     void* readBuffer;
348     u32 dataSize;
349 
350     // Init memory
351     readBuffer = NULL;
352     *ppFont = NULL;
353 
354     // Read the entire font file
355     if (!ReadFileAll(&readBuffer, filePath))
356     {
357         OSReport("Failed to read file: %s\n", filePath);
358         goto ErrorHandle;
359     }
360 
361     // Get font data size & alloc font data buffer
362     dataSize = FNTGetDataSize(readBuffer);
363     if (dataSize == 0)
364     {
365         OSReport("Failed to get font data size: %s\n", filePath);
366         goto ErrorHandle;
367     }
368     *ppFont = (FNTHeader*)OSAlloc(dataSize);
369 
370     // construct
371     OSReport("Constructing: %s: %7d\n", filePath, dataSize);
372     if (!FNTConstruct(*ppFont, readBuffer))
373     {
374         OSReport("Failed to construct font: %s\n", filePath);
375         goto ErrorHandle;
376     }
377 
378     // Free memory
379     OSFree(readBuffer);
380 
381     return TRUE;
382 
383 ErrorHandle:
384     if (readBuffer != NULL)
385     {
386         OSFree(readBuffer);
387         readBuffer = NULL;
388     }
389     if (*ppFont != NULL)
390     {
391         OSFree(*ppFont);
392         *ppFont = NULL;
393     }
394     return FALSE;
395 }
396 
397 /*-----------------------------------------------------------------------------
398   Name:         InitFontStreaming
399 
400   Description:  Construct the font while reading a font file sequentially.
401 
402   Arguments:    ppFont      Pointer to a pointer to the font header
403                 filePath    Font file path
404 
405   Returns:      TRUE if successful, FALSE otherwise.
406   -----------------------------------------------------------------------------*/
InitFontStreaming(FNTHeader ** ppFont,const char * filePath)407 static BOOL InitFontStreaming( FNTHeader** ppFont, const char* filePath )
408 {
409     DVDFileInfo fi;
410     BOOL fileOpenFlag = FALSE;
411     u32 fileSize;
412     u32 readBufferSize;
413     void* readBuffer;
414     s32 readOfs;
415     s32 readSizeIn;
416     s32 readSize;
417     u32 dataSize;
418     FNTConstructResult ret;
419 
420     // Init memory
421     readBuffer = NULL;
422     *ppFont = NULL;
423 
424     // Open file
425     if (!DVDOpen(filePath, &fi))
426     {
427         OSReport("Failed to open file: %s\n", filePath);
428         goto ErrorHandle;
429     }
430     fileOpenFlag = TRUE;
431 
432     // Get file length
433     fileSize = DVDGetLength(&fi);
434     if (fileSize == 0)
435     {
436         OSReport("Failed to get file length: %s\n", filePath);
437         goto ErrorHandle;
438     }
439 
440     // Allocate the read buffer
441     readBufferSize = FNT_RESOURCE_HEADER_SIZE;
442     readBuffer = OSAlloc(readBufferSize);
443 
444     // Read file header to get font data size
445     readSizeIn = (readBufferSize <= fileSize) ?
446         (s32)readBufferSize : (s32)OSRoundUp32B(fileSize);
447     readOfs = 0;
448     readSize = DVDRead(&fi, readBuffer, readSizeIn, readOfs);
449     readOfs += readSize;
450     if (readSize != readSizeIn)
451     {
452         OSReport("Failed to read file: %s\n", filePath);
453         goto ErrorHandle;
454     }
455 
456     // Get font data size & alloc font data buffer
457     dataSize = FNTGetDataSize(readBuffer);
458     if (dataSize == 0)
459     {
460         OSReport("Failed to get font data size: %s\n", filePath);
461         goto ErrorHandle;
462     }
463     *ppFont = (FNTHeader*)OSAlloc(dataSize);
464 
465     // init streaming construct
466     OSReport("Streaming constructing: %s: %7d\n", filePath, dataSize);
467     FNTInitStreamingConstruct(*ppFont, dataSize);
468 
469     // Read a font file sequentially & construct
470     while (readSize > 0)
471     {
472         ret = FNTStreamingConstruct(*ppFont, readBuffer, (u32)readSize);
473         if (ret == FNT_CONSTRUCT_ERROR)
474         {
475             OSReport("Failed to construct font: %s\n", filePath);
476             goto ErrorHandle;
477         }
478         if (readOfs >= fileSize)
479         {
480             break;
481         }
482         readSizeIn = (readOfs + readBufferSize <= fileSize) ?
483             (s32)readBufferSize : (s32)OSRoundUp32B(fileSize - readOfs);
484         readSize = DVDRead(&fi, readBuffer, readSizeIn, readOfs);
485         readOfs += readSize;
486         if (readSize != readSizeIn)
487         {
488             OSReport("Failed to read file: %s\n", filePath);
489             goto ErrorHandle;
490         }
491     }
492     ASSERT(ret == FNT_CONSTRUCT_FINISH);
493 
494     // Close file
495     DVDClose(&fi);
496 
497     // Free memory
498     OSFree(readBuffer);
499 
500     return TRUE;
501 
502 ErrorHandle:
503     if (fileOpenFlag)
504     {
505         DVDClose(&fi);
506     }
507     if (readBuffer != NULL)
508     {
509         OSFree(readBuffer);
510         readBuffer = NULL;
511     }
512     if (*ppFont != NULL)
513     {
514         OSFree(*ppFont);
515         *ppFont = NULL;
516     }
517     return FALSE;
518 }
519 
520 /*-----------------------------------------------------------------------------
521   Name:         main
522 
523   Description:  Main function.
524 
525   Arguments:    None.
526 
527   Returns:      None.
528   -----------------------------------------------------------------------------*/
main(void)529 void main( void )
530 {
531     FNTHeader* font0;
532     FNTHeader* font1;
533     FNTEncoding encoding;
534     OSTime timeStart;
535 
536     // init
537     DEMOInit(NULL);
538 
539     // Init font
540     timeStart = OSGetTime();
541     if (!InitFont(&font0, FONT_FILE_PATH_1))
542     {
543         OSHalt("Stopped");
544     }
545     if (!InitFontStreaming(&font1, FONT_FILE_PATH_2))
546     {
547         OSHalt("Stopped");
548     }
549     OSReport("Initialization Time: %.3f [sec]\n", (OSGetTime() - timeStart) / (f32)OS_TIMER_CLOCK);
550 
551     encoding = (SCGetLanguage() == SC_LANG_JAPANESE) ?
552         FNT_ENCODING_SJIS : FNT_ENCODING_CP1252;
553     FNTSetEncoding(font0, encoding);
554     FNTSetEncoding(font1, encoding);
555 
556     // Draw
557     DEMOBeforeRender();
558     {
559         f32 curX = 16.F;
560         f32 curY = 20.F;
561         f32 curZ = 0.F;
562 
563         SetupTextCamera();
564         SetupTextGX();
565 
566         curY = DrawSample(font0, curX, curY, curZ);
567         curY += 16.F;
568         curY = DrawSample(font1, curX, curY, curZ);
569     }
570     DEMODoneRender();
571 
572     // end
573     OSFree(font0);
574     OSFree(font1);
575 }
576