You are not logged in.

#1 2008-11-25 10:03:40


GRRLIB with freetype support

Here's a basic implementation of GRRLIB with libfreetype. I've included a sample program to test it with, and have commented where I've added new code to grrlib.c and grrlib.h.   You will need libfreetype installed in your libogc directory if you want to compile it yourself.  The included font is Bitstream Vera Sans.  Enjoy!


EDIT: Now that I look through the comments again, they are riddled with spelling mistakes - oh well, I was in a hurry big_smile

Last edited by DrTwox (2008-11-30 01:42:48)



#2 2008-11-25 22:27:16


Re: GRRLIB with freetype support

Very very good work DrTwox !!!

From the start of the GRRLIB project you are the only one that understand how we can grow quickly.
provide your change with a little sample code is more than i expected wink

If other people could follow your way, we will be able to quickly get a lot of new function, then i will be able to merge all your contribution to get each time a new grrlib release !!!

one time again, congrats !!!!!!!!!!

NoNameNo !



#3 2008-11-27 23:52:03

Bad Mother Fucker

Re: GRRLIB with freetype support

Hi, thanks for the code, I think I'll use it inside my game. I just want to mention a small thing.

Since the code is incorporated in a graphic library all the functions should be optimized to the maximum because they are always called.
For example BlitGlyph:
* srcloc and dstloc were use once, so no need to use a variable.
* column and y were initialize two time, once in the for loop and outside at initialization.
* if you declare sywidth, dywidth and column outside the loop I think you are saving one instruction call per declaration (so 1 x 3 x bitmapHeight).

Maybe the optimization occurs automatically at compilation, but just in case I think it's better to change the function.
If you think I'm wrong don't hesitate to tell me, if you like the changes in this function and you want me to take a look at the rest of the code, no problem.


/* Returns true if the character was draw on to the buffer, false if otherwise */
static bool BlitGlyph(FT_Bitmap *bitmap, int offset, int top, void *buffer) {
    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 = buffer;
    unsigned int y;
    int sywidth;
    int dywidth;
    unsigned int column;
    for (y = 0; y < bitmapHeight; ++y) {
        sywidth = y * bitmapWidth;
        dywidth = (y + top) * 640;

        for (column = 0; column < bitmapWidth; ++column) {
            /* Copy the alpha value for this pixel into the texture buffer */
            p[ (((column + offset) + dywidth) << 2) + 3 ] = bitmap->buffer[ (column + sywidth) ];
    return true;



#4 2008-11-28 08:02:24


Re: GRRLIB with freetype support

Thanks for the feedback!  As a newbie C coder I tend to write the code first, then optimize it later if there are performance issues in a certain function. Feel free to look over the other functions and see what can be improved.  I'll put any improvements  you make (with credit) into the .zip file on WiiBrew so others can benefit from your work too.



#5 2008-12-06 06:15:03

Bad Mother Fucker

Re: GRRLIB with freetype support

Hi, I needed the size in pixel of the string generated for the texture to centre the text in a button. So I added an extra parameter to the GRRLIB_TextToTexture function. So now you could call it like that:


int TextWidth;
button_font = GRRLIB_TextToTexture("Hello!", 12, 0x0, &TextWidth);
// or
button_font = GRRLIB_TextToTexture("Hello!", 12, 0x0, NULL);

So I modified your code with:


void *GRRLIB_TextToTexture(const char *, unsigned int, unsigned int, int *);

And in GRRLIB_TextToTexture I do:


void *GRRLIB_TextToTexture(const char *string, unsigned int fontSize, unsigned int fontColour, int *textwidth) {
    DrawText(string, fontSize, tempTextureBuffer, textwidth);

And in DrawText:


static void DrawText(const char *string, unsigned int fontSize, void *buffer, int *textwidth) {
//at the end of the function
    if(textwidth != NULL)
        *textwidth = penX;

And of course DrawText is declared:


static void DrawText(const char *string, unsigned int fontSize, void *buffer, int *);

The other way of doing that would be to add a static variable in the GRRLIB.c file and add a function like GRRLIB_GetTextWidth()

Instead of adding an extra parameter to DrawText, the function could return the Width, it's another way of doing it.

I hope you like the idea.



#6 2008-12-07 01:59:16


Re: GRRLIB with freetype support

Thanks for the contribution; others will benefit from your improvements!
My original code in libwiigfx actually does something like this already smile It's quite a bit more sophisticated than standard GRRLIB, in that all functions create, return or work with a structure called SPRITE.  The pixelWidth of the text is one of the values stored in this structure, to achieve something similar to what you've created.  A better solution, which I haven't got working yet, is to render the text onto a texture that is only as wide as it needs to be, so there is no wasted space.

Here's a screenshot of the Home Menu from WiiMP (my project that is eating my life!)  What you can't see in a screenshot is the way textured objects can move about the screen or fade in or out (or both at the same time) and it takes very little effort from the user to achieve these basic effects... it's by no means a full sprite handling library (not even close!), but it does simplify the creation of 2d interfaces.

I have 4 weeks holiday coming up soon, and depending how much time I can spare, I plan on fully sharing all my modifications to GRRLIB for people to play with (and hopfully improve upon!).

Last edited by DrTwox (2008-12-07 02:02:10)



#7 2008-12-08 21:14:38

Bad Mother Fucker

Re: GRRLIB with freetype support

I had the same idea for the use of a structure like SPRITE. I sent an email in august to NoNameNo with the idea of using a simple structure like this one:


typedef struct
    void *texture;
    u32 Width;
    u32 Height;

Instead of GRRLIB_LoadTexture we would have:


GRRLIB_IMAGE GRRLIB_LoadImage (const unsigned char my_png[])
    PNGUPROP imgProp;
    IMGCTX ctx;
    GRRLIB_IMAGE my_image;

      ctx = PNGU_SelectImageFromBuffer (my_png);
      if(ctx && PNGU_GetImageProperties (ctx, &imgProp) == PNGU_OK)
        my_image.texture = memalign (32, imgProp.imgWidth * imgProp.imgHeight * 4);
        PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, my_image.texture, 255);
        PNGU_ReleaseImageContext (ctx);
        DCFlushRange (my_image.texture, imgProp.imgWidth * imgProp.imgHeight * 4);

        my_image.Width = imgProp.imgWidth;
        my_image.Height = imgProp.imgHeight;
    return my_image;

Of course something to clean the memory:


void GRRLIB_DestroyImage (GRRLIB_IMAGE my_image)
    my_image.Width = 0;
    my_image.Height = 0;
    free (my_image.texture);
    my_image.texture = NULL;

With all the rest that goes with it:


void GRRLIB_Textout (f32 xpos, f32 ypos, GRRLIB_IMAGE image, u32 color, f32 zoom, char *text, ...)
    int i, size;
    char tmp[1024];

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

    GXColor col = GRRLIB_Splitu32(color);
    for(i=0; i<size; i++)
        u8 c = tmp[i];
        GRRLIB_DrawChar(xpos+i * font_width * zoom, ypos, my_image.Width, my_image.Height, my_image.texture, 0, zoom, zoom, c, col );


inline void GRRLIB_DrawChar(f32 xpos, f32 ypos, u16 width, u16 height, u8 data[], float degrees, float scaleX, f32 scaleY, u8 frame, GXColor c )
    GXTexObj texObj;
    f32 s1= ((frame    %16))    /16.0;
    f32 s2= ((frame    %16)+1)    /16.0;
    f32 t1= ((frame    /16))    /16.0;
    f32 t2= ((frame    /16)+1)    /16.0;

    GX_InitTexObj(&texObj, data, width*16,height*16, 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_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);

    Mtx m,m1,m2,mv;
    width *=.5;

    guMtxIdentity (m1);
    Vector axis =(Vector) {0,0,1};
    guMtxRotAxisDeg (m2, &axis, degrees);
    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_TexCoord2f32(s1, t1);

    GX_Position3f32(width, -height,  0);
    GX_TexCoord2f32(s2, t1);

    GX_Position3f32(width, height,  0);
    GX_TexCoord2f32(s2, t2);

    GX_Position3f32(-width, height,  0);
    GX_TexCoord2f32(s1, t2);


    GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0);
    GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);

PS: I think I never tested the code smile



Board footer

Powered by FluxBB