In this post i have add information how to add freetype library support to the GRRLIB 4.2.X library
GRRLIB_free_print.h
void GRRLIB_InitFreetype();
void GRRLIB_initTexture(void);
void GRRLIB_Printf2( int x,
int y,
const char *string,
unsigned int fontSize,
int color);
GRRLIB_texImg* GRRLIB_GetTexture(void);
GRRLIB_free_print.c
#include <malloc.h>
#include <stdarg.h>
#include <stdio.h>
#include <grrlib.h>
#include <ft2build.h> /* I presume you have freetype for the Wii installed */
#include FT_FREETYPE_H
#include "font_ttf.h"
static FT_Library ftLibrary;
static FT_Face ftFace;
void *fontTempLayer=NULL;
void *fontTexture=NULL;
GRRLIB_texImg image;
extern Mtx GXmodelView2D;
/* Static function prototypes */
static void BitmapTo4x4RGBA(const unsigned char *src, void *dst, const unsigned int width, const unsigned int height);
static bool BlitGlyph(FT_Bitmap *bitmap, int offset, int top, int color) ;
void GRRLIB_InitFreetype(void)
{
unsigned int error = FT_Init_FreeType(&ftLibrary);
if (error)
{
exit(0);
}
error = FT_New_Memory_Face(ftLibrary, font_ttf, font_ttf_size, 0, &ftFace);
if (error == FT_Err_Unknown_File_Format)
{
exit(0);
}
else if (error)
{
/* Some other error */
exit(0);
}
}
void GRRLIB_initTexture(void)
{
// Clear previous video frame buffer
if (fontTexture!=NULL) free(fontTexture);
fontTempLayer = (void*) calloc(1, 640 * 528 * 4);
if (fontTempLayer == NULL)
{
/* Oops! Something went wrong! */
exit(0);
}
}
void GRRLIB_Printf2(int x, int y, const char *string, unsigned int fontSize, int color)
{
unsigned int error = 0;
int penX = 0;
int penY = fontSize;
FT_GlyphSlot slot = ftFace->glyph;
FT_UInt glyphIndex = 0;
FT_UInt previousGlyph = 0;
FT_Bool hasKerning = FT_HAS_KERNING(ftFace);
error = FT_Set_Pixel_Sizes(ftFace, 0, fontSize);
if (error)
{
/* Failed to set the font size to the requested size.
* You probably should set a default size or something.
* I'll leave that up to the reader. */
FT_Set_Pixel_Sizes(ftFace, 0, 12);
}
/* Convert the string to UTF32 */
size_t length = strlen(string);
wchar_t *utf32 = (wchar_t*)malloc(length * sizeof(wchar_t));
length = mbstowcs(utf32, string, length);
/* Loop over each character, drawing it on to the 4, until the
* end of the string is reached, or until the pixel width is too wide */
unsigned int loop = 0;
for (loop = 0; loop < length; ++loop)
{
glyphIndex = FT_Get_Char_Index(ftFace, utf32[ loop ]);
/* To the best of my knowledge, none of the other freetype
* implementations use kerning, so my method ends up looking
* slightly better :) */
if (hasKerning && previousGlyph && glyphIndex)
{
FT_Vector delta;
FT_Get_Kerning(ftFace, previousGlyph, glyphIndex, FT_KERNING_DEFAULT, &delta);
penX += delta.x >> 6;
}
error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_RENDER);
if (error)
{
/* Whoops, something went wrong trying to load the glyph
* for this character... you should handle this better */
continue;
}
if (BlitGlyph(&slot->bitmap, penX + slot->bitmap_left+x, penY - slot->bitmap_top+y, color) == true)
{
/* The glyph was successfully blitted to the buffer, move the pen forwards */
penX += slot->advance.x >> 6;
previousGlyph = glyphIndex;
}
else
{
/* BlitGlyph returned false, the line must be full */
free(utf32);
return;
}
}
free(utf32);
}
/* Returns true if the character was draw on to the buffer, false if otherwise */
bool BlitGlyph(FT_Bitmap *bitmap, int offset, int top, int color)
{
int bitmapWidth = bitmap->width;
int bitmapHeight = bitmap->rows;
if (offset + bitmapWidth > 640)
{
/* Drawing this character would over run the buffer, so don't draw it */
return false;
}
/* Draw the glyph onto the buffer, blitting from the bottom up */
/* CREDIT: Derived from a function by DragonMinded */
unsigned char *p = fontTempLayer;
unsigned int y = 0;
for (y = 0; y < bitmapHeight; ++y)
{
int sywidth = y * bitmapWidth;
int dywidth = (y + top) * 640;
unsigned int column = 0;
for (column = 0; column < bitmapWidth; ++column)
{
unsigned int srcloc = column + sywidth;
unsigned int dstloc = ((column + offset) + dywidth) << 2;
/* Copy the alpha value for this pixel into the texture buffer */
p[ dstloc + 0 ] = (color & 0xff);
p[ dstloc + 1 ] = ((color >> 8) & 0xff);
p[ dstloc + 2 ] = ((color >> 16) & 0xff);
p[ dstloc + 3 ] = (bitmap->buffer[ srcloc ]);
}
}
return true;
}
/* Render the text string to a 4x4RGBA texture, return a pointer to this texture */
GRRLIB_texImg* GRRLIB_GetTexture(void)
{
/* Create a new buffer, this time to hold the final texture
* in a format suitable for the Wii */
fontTexture = memalign(32, 640 * 528 * 4);
/* Convert the RGBA temp buffer to a format usuable by GX */
BitmapTo4x4RGBA(fontTempLayer, fontTexture, 640, 528);
DCFlushRange(fontTexture, 640 * 528 * 4);
/* The temp buffer is no longer required */
free(fontTempLayer);
image.data=fontTexture;
image.w=640;
image.h=528;
return ℑ
}
void BitmapTo4x4RGBA(const unsigned char *src, void *dst, const unsigned int width, const unsigned int height)
{
unsigned int block = 0;
unsigned int i = 0;
unsigned int c = 0;
unsigned int ar = 0;
unsigned int gb = 0;
unsigned char *p = (unsigned char*)dst;
for (block = 0; block < height; block += 4) {
for (i = 0; i < width; i += 4) {
/* Alpha and Red */
for (c = 0; c < 4; ++c) {
for (ar = 0; ar < 4; ++ar) {
/* Alpha pixels */
*p++ = src[(((i + ar) + ((block + c) * width)) * 4) + 3];
/* Red pixels */
*p++ = src[((i + ar) + ((block + c) * width)) * 4];
}
}
/* Green and Blue */
for (c = 0; c < 4; ++c) {
for (gb = 0; gb < 4; ++gb) {
/* Green pixels */
*p++ = src[(((i + gb) + ((block + c) * width)) * 4) + 1];
/* Blue pixels */
*p++ = src[(((i + gb) + ((block + c) * width)) * 4) + 2];
}
}
} /* i */
} /* block */
}