You are not logged in.

  • Index
  •  » General Help
  •  » Freetype and GRRLIB. My own implementation - not working. Suggestions?

#1 2009-06-20 00:24:54

pinecone
Member

Freetype and GRRLIB. My own implementation - not working. Suggestions?

GRRLIB and True Type fonts are like water and oil - they don't seem to mix. I've had a go at making a fully functional printf function combining the work of wplaat and Dr Twox, and allowing the passing of extra arguments (formatting integers, etc. I'm not sure what this is called).

As you may have gathered from the title, I have failed. Could anyone offer some insight as to why and how?

Code:

#include <ft2build.h> /* I presume you have freetype for the Wii installed */
#include FT_FREETYPE_H
#include "fonts/ttf_font.h"

static FT_Library ftLibrary;
static FT_Face ftFace;

void *fontTempLayer=NULL;
void *fontTexture=NULL;

/* 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) ;

extern void GRRLIB_InitFreetype(void) 
{
    unsigned int error = FT_Init_FreeType(&ftLibrary);
    if (error) 
    {
        exit(0);
    }
    
    error = FT_New_Memory_Face(ftLibrary, MYFONT, MYFONT_SIZE, 0, &ftFace);
    if (error == FT_Err_Unknown_File_Format) 
    {
        exit(0);
    } 
    else if (error) 
    {
        /* Some other error */
        exit(0);
    }
}

extern void GRRLIB_initTexture(void)
{
    // Clear previous video frame buffer
    if (fontTexture!=NULL) free(fontTexture);
    
    fontTempLayer = (void*) calloc(1, 640 * 480 * 4);
    
    if (fontTempLayer == NULL) 
    {
        /* Oops! Something went wrong! */
        exit(0);
    }
}

extern void GRRLIB_Printf2(int x, int y, unsigned int fontSize, int color, const char *text, ...) 
{
    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);
    }

    char string[1024];
    int size=0;
    
    va_list argp;
    va_start(argp, text);
    vsprintf(string, text, argp);
    va_end(argp);
    
    size = strlen(string);
    
    /* 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 */
static 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 */
extern void* 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 * 480 * 4);
    
    /* Convert the RGBA temp buffer to a format usuable by GX */
    BitmapTo4x4RGBA(fontTempLayer, fontTexture, 640, 480);
    DCFlushRange(fontTexture, 640 * 480 * 4);
    
    /* The temp buffer is no longer required */
    free(fontTempLayer);
    
    return fontTexture;
}

static 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 */
}

inline void GRRLIB_DrawImg2(f32 xpos, f32 ypos, u8 data[], float degrees, float scaleX, f32 scaleY, u8 alpha )
{
    GXTexObj texObj;
    u16 width=640;
    u16 height=480;
    
    GX_InitTexObj(&texObj, data, width, height, GX_TF_RGBA8,GX_CLAMP, GX_CLAMP,GX_FALSE);
    //GX_InitTexObjLOD(&texObj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
    GX_LoadTexObj(&texObj, GX_TEXMAP0);
    
    GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
      GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
    
    Mtx m,m1,m2, mv;
    width *=.5;
    height*=.5;
    guMtxIdentity (m1);
    guMtxScaleApply(m1,m1,scaleX,scaleY,1.0);
    Vector axis =(Vector) {0 , 0, 1 };
    guMtxRotAxisDeg (m2, &axis, degrees);
    guMtxConcat(m2,m1,m);
    
    guMtxTransApply(m,m, xpos+width,ypos+height,0);
    guMtxConcat (GXmodelView2D, m, mv);
    GX_LoadPosMtxImm (mv, GX_PNMTX0);
    
    GX_Begin(GX_QUADS, GX_VTXFMT0,4);
      GX_Position3f32(-width, -height,  0);
      GX_Color4u8(0xFF,0xFF,0xFF,alpha);
      GX_TexCoord2f32(0, 0);
    
      GX_Position3f32(width, -height,  0);
     GX_Color4u8(0xFF,0xFF,0xFF,alpha);
      GX_TexCoord2f32(1, 0);
    
      GX_Position3f32(width, height,  0);
    GX_Color4u8(0xFF,0xFF,0xFF,alpha);
      GX_TexCoord2f32(1, 1);
    
      GX_Position3f32(-width, height,  0);
    GX_Color4u8(0xFF,0xFF,0xFF,alpha);
      GX_TexCoord2f32(0, 1);
    GX_End();
    GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0);
    
    GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
      GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);
    
}

Last edited by Crayon (2009-06-20 00:27:12)

Offline

 

#2 2009-06-20 00:29:02

Crayon
Bad Mother Fucker

Re: Freetype and GRRLIB. My own implementation - not working. Suggestions?

Hi, I don't know if it could help, but I'm using FreeType in my game. Source code could be downloaded from this Web page: http://wiibrew.org/wiki/Wii-Tac-Toe

Offline

 

#3 2009-06-20 00:36:08

pinecone
Member

Re: Freetype and GRRLIB. My own implementation - not working. Suggestions?

I think I used a function like the one you used as the basis of my one printed above. I want to be able to print the score in my game with freetype, so I need a function that can take "%d" type arguments (again, I'm sure there's a technical name for this). This produces a code dump whenever I call the printf2() function.

Offline

 

#4 2009-06-20 04:19:15

Crayon
Bad Mother Fucker

Re: Freetype and GRRLIB. My own implementation - not working. Suggestions?

In my code I use:

Code:

        char TempText[100];
        sprintf(TempText, "Programmer: %s", "Crayon");
        GRRLIB_Printf2(50, 310, TempText, 11, 0xFFFFFF);

Another way around would be to used those lines in your print function (taken from GRRLIB_Printf):

Code:

    char tmp[1024];

    va_list argp;
    va_start(argp, text);
    size = vsprintf(tmp, text, argp);
    va_end(argp);

But you are already doing that. So could you paste the code where you call GRRLIB_Printf2.

Offline

 

#5 2009-06-20 20:12:13

pinecone
Member

Re: Freetype and GRRLIB. My own implementation - not working. Suggestions?

I like the first method you had there. Hadn't thought of that.

Here's my alternative Printf2 function (as you said, based on the GRRLIB_Printf() function):

Code:

extern void GRRLIB_Printf2(int x, int y, unsigned int fontSize, int color, const char *text, ...) 
{
    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);
    }

    char string[1024];
    int size=0;
    
    va_list argp;
    va_start(argp, text);
    vsprintf(string, text, argp);
    va_end(argp);
    
    size = strlen(string);
    
    /* 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);
}

Last edited by pinecone (2009-06-20 20:14:56)

Offline

 

#6 2009-06-20 21:20:40

Crayon
Bad Mother Fucker

Re: Freetype and GRRLIB. My own implementation - not working. Suggestions?

I noticed you are using this code:

Code:

char string[1024];

string is not a good name because in C++ it's a type when using this code:

Code:

#include <string>
using namespace std;

Are you sure what you are sending to the function is not longer than 1024 characters? If yes you might have a buffer overflow problem.

Offline

 

#7 2009-06-20 21:32:48

pinecone
Member

Re: Freetype and GRRLIB. My own implementation - not working. Suggestions?

Crayon wrote:

Are you sure what you are sending to the function is not longer than 1024 characters? If yes you might have a buffer overflow problem.

Yes. It's literally "Score: %d",score

Thanks for the heads-up on the string namespace - but it shouldn't be an issue for me as the whole thing is in C.

Offline

 

#8 2009-06-21 23:53:18

DrTwox
Member

Re: Freetype and GRRLIB. My own implementation - not working. Suggestions?

What you are looking for is the <stdarg.h> header. There is an explanation and code example available here.

I have something like this:

Code:

#define MAX_STRING_LENGTH 2048
extern gfxTexture_t *GFX_TextToTexture( const gfxFont_t *font, const u32 fontSize, const char *fmt, ... ) {
    va_list args;
    va_start( args, fmt );
    char string[ MAX_STRING_LENGTH ];
    vsnprintf( string, MAX_STRING_LENGTH, fmt, args );
    va_end( args );

    /* Do stuff with 'string' */
}

/* Elsewhere */

gfxTexture_t *message = GFX_TextToTexture( bold, 32, "time = %d, fps = %d", time_integer, fps_integer );

Offline

 
  • Index
  •  » General Help
  •  » Freetype and GRRLIB. My own implementation - not working. Suggestions?

Board footer

Powered by FluxBB