/*---------------------------------------------------------------------------* Project: font demo program File: fntdemo1.c Copyright 2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: fntdemo1.c,v $ Revision 1.1 2006/10/18 02:52:17 nishida_yasunari Initial check in. $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include /*----------------------------------------------------------------------------- Constants -----------------------------------------------------------------------------*/ static const char* FONT_FILE_PATH_1 = "/fonts/wbf1.brfna"; static const char* FONT_FILE_PATH_2 = "/fonts/wbf2.brfna"; static const int TEXTURE_COODINATE_FRACTION_BITS = 15; static const u32 TEXTURE_COODINATE_ONE = (1 << TEXTURE_COODINATE_FRACTION_BITS); /*----------------------------------------------------------------------------- Name: SetupTextCamera Description: Sets up text camera. Arguments: None. Returns: None. -----------------------------------------------------------------------------*/ static void SetupTextCamera( void ) { { Mtx44 p; f32 znear = 0.0F; f32 zfar = 1.0F; f32 t = 0; f32 b = 480; f32 l = 0; f32 r = 640; MTXOrtho(p, t, b, l, r, znear, zfar); GXSetProjection(p, GX_ORTHOGRAPHIC); } { Mtx mv; MTXIdentity(mv); GXLoadPosMtxImm(mv, GX_PNMTX0); GXSetCurrentMtx(GX_PNMTX0); } } /*----------------------------------------------------------------------------- Name: SetupTextGX Description: Sets up text GX. Arguments: None. Returns: None. -----------------------------------------------------------------------------*/ static void SetupTextGX( void ) { GXSetNumChans(1); GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); GXSetChanCtrl(GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); GXSetNumTexGens(1); GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); GXSetNumTevStages(1); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_RASC, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetNumIndStages(0); GXSetTevDirect(GX_TEVSTAGE0); GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS , GX_POS_XYZ, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST , GX_U16, TEXTURE_COODINATE_FRACTION_BITS); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS , GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetChanMatColor(GX_COLOR0A0, (GXColor){255, 255, 255, 255 }); } /*----------------------------------------------------------------------------- Name: DrawChar Description: Draws one character. Arguments: x, y, z Coordinates tex Pointer to a font texture scaleX Horizontal scale scaleY Vertical scale lastImage Pointer to a pointer to the texture image that was last loaded Returns: None. -----------------------------------------------------------------------------*/ static void DrawChar( f32 x, f32 y, f32 z, const FNTTexture* tex, f32 scaleX, f32 scaleY, void** lastImage ) { f32 posLeft = x + tex->left * scaleX; f32 posTop = y; f32 posRight = posLeft + tex->glyphWidth * scaleX; f32 posBottom = posTop + tex->charHeight * scaleY; u16 texLeft = (u16)(tex->cellX * TEXTURE_COODINATE_ONE / tex->texWidth); u16 texTop = (u16)(tex->cellY * TEXTURE_COODINATE_ONE / tex->texHeight); u16 texRight = (u16)((tex->cellX + tex->glyphWidth) * TEXTURE_COODINATE_ONE / tex->texWidth); u16 texBottom = (u16)((tex->cellY + tex->charHeight) * TEXTURE_COODINATE_ONE / tex->texHeight); if (tex->image != *lastImage) { GXTexObj tobj; GXTexFilter filter = GX_LINEAR; GXInitTexObj(&tobj, tex->image, tex->texWidth, tex->texHeight, tex->texFormat, GX_CLAMP, GX_CLAMP, GX_FALSE); GXInitTexObjLOD(&tobj, filter, filter, 0, 0, 0, GX_DISABLE, GX_DISABLE, GX_ANISO_1); GXLoadTexObj(&tobj, GX_TEXMAP0); *lastImage = tex->image; } GXBegin(GX_QUADS, GX_VTXFMT0, 4); { GXPosition3f32(posLeft, posTop, z); GXTexCoord2u16(texLeft, texTop); GXPosition3f32(posRight, posTop, z); GXTexCoord2u16(texRight, texTop); GXPosition3f32(posRight, posBottom, z); GXTexCoord2u16(texRight, texBottom); GXPosition3f32(posLeft, posBottom, z); GXTexCoord2u16(texLeft, texBottom); } GXEnd(); } /*----------------------------------------------------------------------------- Name: DrawString Description: Draws a string. Arguments: font Pointer to font header x, y, z Coordinates string String scaleX Horizontal scale scaleY Vertical scale fixedWidth fixed width (proportional if 0 is specified) lastImage Pointer to a pointer to the texture image that was last loaded Returns: Total string width in pixels. -----------------------------------------------------------------------------*/ static f32 DrawString( const FNTHeader* font, f32 x, f32 y, f32 z, const char* string, f32 scaleX, f32 scaleY, f32 fixedWidth, void** lastImage ) { f32 startX = x; BOOL utf16 = (FNTGetEncoding(font) == FNT_ENCODING_UTF16); while (*string || (utf16 && *(string + 1))) { FNTTexture tex; f32 scaleWd, margin; string = FNTGetTexture(font, string, &tex); scaleWd = tex.charWidth * scaleX; margin = (fixedWidth > 0.0F) ? (fixedWidth - scaleWd) / 2.0F : 0.0F; DrawChar(x + margin, y, z, &tex, scaleX, scaleY, lastImage); x += (fixedWidth > 0.0F) ? fixedWidth : scaleWd; } return (x - startX); } /*----------------------------------------------------------------------------- Name: GetStringWidth Description: Gets string width. Arguments: font Pointer to font header string String scaleX Horizontal scale Returns: Total string width in pixels. -----------------------------------------------------------------------------*/ static f32 GetStringWidth( const FNTHeader* font, const char* string, f32 scaleX ) { f32 totalWidth; BOOL utf16 = (FNTGetEncoding(font) == FNT_ENCODING_UTF16); totalWidth = 0.0F; while (*string || (utf16 && *(string + 1))) { s32 width; string = FNTGetWidth(font, string, &width); totalWidth += width * scaleX; } return totalWidth; } /*----------------------------------------------------------------------------- Name: DrawSample Description: Draws a sample. Arguments: font Pointer to font header x, y, z Coordinates Returns: Y coordinate of next line. -----------------------------------------------------------------------------*/ static f32 DrawSample( const FNTHeader* font, f32 x, f32 y, f32 z ) { f32 scaleX = 1.F; f32 scaleY = 1.F; FNTMetrics metrics; void* lastImage = NULL; f32 drawW, getW; const char* str0 = " !\"#$%&'()*+,-./0123456789:;<=>?"; const char* str1 = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; const char* str2 = "`abcdefghijklmnopqrstuvwxyz{|}~"; const char* str3 = "Wii"; const char* str4 = "\xca\xdd\xb6\xb8\x20\x82\xa9\x82\xc8\x20\x8a\xbf\x8e\x9a"; // Half-width Kana Kanji f32 startX = x; // Get metrics FNTGetMetrics(font, &metrics); // Draw proportional string drawW = DrawString(font, x, y, z, str0, scaleX, scaleY, 0.F, &lastImage); y += metrics.leading * scaleY; drawW = DrawString(font, x, y, z, str1, scaleX, scaleY, 0.F, &lastImage); y += metrics.leading * scaleY; drawW = DrawString(font, x, y, z, str2, scaleX, scaleY, 0.F, &lastImage); y += metrics.leading * scaleY; scaleX = scaleY = 1.5F; // Change scale drawW = DrawString(font, x, y, z, str3, scaleX, scaleY, 0.F, &lastImage); x += drawW + metrics.width * scaleX; // Get width test getW = GetStringWidth(font, str3, scaleX); OSReport("Width Test: %f %f\n", drawW, getW); // Draw fixed-width string drawW = DrawString(font, x, y, z, str3, scaleX, scaleY, metrics.width * scaleX, &lastImage); x = startX; y += metrics.leading * scaleY; scaleX = scaleY = 1.F; // Restore scale // Draw SJIS string if (FNTGetEncoding(font) == FNT_ENCODING_SJIS) { drawW = DrawString(font, x, y, z, str4, scaleX, scaleY, 0.F, &lastImage); y += metrics.leading * scaleY; } return y; } /*---------------------------------------------------------------------------* Name: ReadFileAll Description: Reads an entire file. Arguments: ppBuffer Pointer to a pointer to the read buffer filePath File path Returns: TRUE if successful, FALSE otherwise. *---------------------------------------------------------------------------*/ static BOOL ReadFileAll( void** ppBuffer, const char* filePath ) { DVDFileInfo fi; u32 fileSize; u32 readBufferSize; s32 readSize; if (!DVDOpen(filePath, &fi)) { return FALSE; } fileSize = DVDGetLength(&fi); if (fileSize == 0) { return FALSE; } readBufferSize = OSRoundUp32B(fileSize); *ppBuffer = OSAlloc(readBufferSize); readSize = DVDRead(&fi, *ppBuffer, (s32)readBufferSize, 0); DVDClose(&fi); if (readSize != readBufferSize) { return FALSE; } return TRUE; } /*----------------------------------------------------------------------------- Name: InitFont Description: Reads a font file entirely to memory and constructs the font data. Arguments: ppFont Pointer to a pointer to the font header filePath Font file path Returns: TRUE if successful, FALSE otherwise. -----------------------------------------------------------------------------*/ static BOOL InitFont( FNTHeader** ppFont, const char* filePath ) { void* readBuffer; u32 dataSize; // Init memory readBuffer = NULL; *ppFont = NULL; // Read the entire font file if (!ReadFileAll(&readBuffer, filePath)) { OSReport("Failed to read file: %s\n", filePath); goto ErrorHandle; } // Get font data size & alloc font data buffer dataSize = FNTGetDataSize(readBuffer); if (dataSize == 0) { OSReport("Failed to get font data size: %s\n", filePath); goto ErrorHandle; } *ppFont = (FNTHeader*)OSAlloc(dataSize); // construct OSReport("Constructing: %s: %7d\n", filePath, dataSize); if (!FNTConstruct(*ppFont, readBuffer)) { OSReport("Failed to construct font: %s\n", filePath); goto ErrorHandle; } // Free memory OSFree(readBuffer); return TRUE; ErrorHandle: if (readBuffer != NULL) { OSFree(readBuffer); readBuffer = NULL; } if (*ppFont != NULL) { OSFree(*ppFont); *ppFont = NULL; } return FALSE; } /*----------------------------------------------------------------------------- Name: InitFontStreaming Description: Construct the font while reading a font file sequentially. Arguments: ppFont Pointer to a pointer to the font header filePath Font file path Returns: TRUE if successful, FALSE otherwise. -----------------------------------------------------------------------------*/ static BOOL InitFontStreaming( FNTHeader** ppFont, const char* filePath ) { DVDFileInfo fi; BOOL fileOpenFlag = FALSE; u32 fileSize; u32 readBufferSize; void* readBuffer; s32 readOfs; s32 readSizeIn; s32 readSize; u32 dataSize; FNTConstructResult ret; // Init memory readBuffer = NULL; *ppFont = NULL; // Open file if (!DVDOpen(filePath, &fi)) { OSReport("Failed to open file: %s\n", filePath); goto ErrorHandle; } fileOpenFlag = TRUE; // Get file length fileSize = DVDGetLength(&fi); if (fileSize == 0) { OSReport("Failed to get file length: %s\n", filePath); goto ErrorHandle; } // Allocate the read buffer readBufferSize = FNT_RESOURCE_HEADER_SIZE; readBuffer = OSAlloc(readBufferSize); // Read file header to get font data size readSizeIn = (readBufferSize <= fileSize) ? (s32)readBufferSize : (s32)OSRoundUp32B(fileSize); readOfs = 0; readSize = DVDRead(&fi, readBuffer, readSizeIn, readOfs); readOfs += readSize; if (readSize != readSizeIn) { OSReport("Failed to read file: %s\n", filePath); goto ErrorHandle; } // Get font data size & alloc font data buffer dataSize = FNTGetDataSize(readBuffer); if (dataSize == 0) { OSReport("Failed to get font data size: %s\n", filePath); goto ErrorHandle; } *ppFont = (FNTHeader*)OSAlloc(dataSize); // init streaming construct OSReport("Streaming constructing: %s: %7d\n", filePath, dataSize); FNTInitStreamingConstruct(*ppFont, dataSize); // Read a font file sequentially & construct while (readSize > 0) { ret = FNTStreamingConstruct(*ppFont, readBuffer, (u32)readSize); if (ret == FNT_CONSTRUCT_ERROR) { OSReport("Failed to construct font: %s\n", filePath); goto ErrorHandle; } if (readOfs >= fileSize) { break; } readSizeIn = (readOfs + readBufferSize <= fileSize) ? (s32)readBufferSize : (s32)OSRoundUp32B(fileSize - readOfs); readSize = DVDRead(&fi, readBuffer, readSizeIn, readOfs); readOfs += readSize; if (readSize != readSizeIn) { OSReport("Failed to read file: %s\n", filePath); goto ErrorHandle; } } ASSERT(ret == FNT_CONSTRUCT_FINISH); // Close file DVDClose(&fi); // Free memory OSFree(readBuffer); return TRUE; ErrorHandle: if (fileOpenFlag) { DVDClose(&fi); } if (readBuffer != NULL) { OSFree(readBuffer); readBuffer = NULL; } if (*ppFont != NULL) { OSFree(*ppFont); *ppFont = NULL; } return FALSE; } /*----------------------------------------------------------------------------- Name: main Description: Main function. Arguments: None. Returns: None. -----------------------------------------------------------------------------*/ void main( void ) { FNTHeader* font0; FNTHeader* font1; FNTEncoding encoding; OSTime timeStart; // init DEMOInit(NULL); // Init font timeStart = OSGetTime(); if (!InitFont(&font0, FONT_FILE_PATH_1)) { OSHalt("Stopped"); } if (!InitFontStreaming(&font1, FONT_FILE_PATH_2)) { OSHalt("Stopped"); } OSReport("Initialization Time: %.3f [sec]\n", (OSGetTime() - timeStart) / (f32)OS_TIMER_CLOCK); encoding = (SCGetLanguage() == SC_LANG_JAPANESE) ? FNT_ENCODING_SJIS : FNT_ENCODING_CP1252; FNTSetEncoding(font0, encoding); FNTSetEncoding(font1, encoding); // Draw DEMOBeforeRender(); { f32 curX = 16.F; f32 curY = 20.F; f32 curZ = 0.F; SetupTextCamera(); SetupTextGX(); curY = DrawSample(font0, curX, curY, curZ); curY += 16.F; curY = DrawSample(font1, curX, curY, curZ); } DEMODoneRender(); // end OSFree(font0); OSFree(font1); }