gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > FreeType2 Library [updated 24 April]

#126473 - Lick - Mon Apr 23, 2007 2:45 pm

_________________________
Updated 24 april:

Download FreeType2 library:
FreeType2 core
FreeType2 full (use this one)

The Full version contains all the available modules, except for the GZIP-module and the gzip-dependent PCF-module. I couldn't get it to compile that module, maybe someone else can.

Download demo:
Demo displays Chinese characters with color

_________________________
Original message:

I have successfully ported FreeType2 to the DS. However I have stripped out some of its features. You can examine the source and rebuild the library if you want to.
To rebuild with different options, edit the files in /include/freetype/config/*.h. Also, in the /source/ directory, you have to rename some directories/files removing the "_DISABLED" that I added onto them to prevent compilation.

Anyway, FreeType2 (2.3.4) that *should* support:
- TrueType, OpenType and Windows Fonts.
- Monotone vs Antialiased rendering.

FreeType2 Tutorial

I have only tested the initialization of FreeType2 and loaded a font. That all works, but I haven't tried anything beyond that. I kind of released this in a hurry, since I don't have a lot of time on my hands. I will try to squeeze in a font rendering demo this week.

- Lick

Oh shit! Forgot to include the License
_________________
http://licklick.wordpress.com


Last edited by Lick on Wed Apr 25, 2007 6:22 pm; edited 4 times in total

#126477 - Lick - Mon Apr 23, 2007 4:42 pm

Demo because I couldn't resist it. Extract the files to the root and DLDI patch the binary.

Photoshot #1 (Times)
Photoshot #2 (Matura MT named "times.ttf")

BTW: The fonts have 256 levels of alpha, but in my demo I reduced that to 4 levels (if-elseif-elseif-else). So some fonts may render looking like there's no alpha (antialiasing).
_________________
http://licklick.wordpress.com

#126650 - Stuk - Wed Apr 25, 2007 4:25 pm

Ooo, this looks awesome. Will have to try it out at some point :)

#126655 - Cobalt - Wed Apr 25, 2007 6:06 pm

That's freakin' excellent! I'm looking forward to playing with this...

#126672 - dext3r - Wed Apr 25, 2007 10:13 pm

cool. i was also trying to get this to compile to a library. with the code based from http://svn.navi.cx/misc/trunk/nds/freetype-test/ i was able to compile a working demo with color

Are you doing the 4level color in the Chinese character demo?

Code:
  for (i=width; i; i--) {
    
       uint8 r = *(src++) >> 3;
       uint8 g = *(src++) >> 3;
      uint8 b = *(src++) >> 3;
 
       uint8 rb = ((*dest & 0x1F)) ;
        uint8 gb = ((*dest >> 5) & 0x1F);
       uint8 bb = ((*dest >> 10) & 0x1F);
         
       uint8 input_red = 0xFF >> 3;
       uint8 input_green = 0xFF >> 3;
       uint8 input_blue = 0xFF >> 3;
      
         if(r|g|b)      
       *dest = RGB15((input_red * r/31 + (31 - r) * rb / 31),(input_green * g/31 + (31 - g) * gb / 31),(input_blue * b/31 + (31 - b) *bb / 31) );
   
    dest++;
   }   


thats how i did the color in my test. are you doing it the same?

i will take a look at your stuff so i can learn how to make it into a library, good job and thanks

#126674 - Lick - Wed Apr 25, 2007 10:24 pm

I'm using this code. It's a modified version from the site you mentioned. ;)

It uses wide characters (wchar_t).

Code:
#define FT_FLOOR(x)     (((x) & -64) / 64)
#define FT_CEIL(x)      ((((x) + 63) & -64) / 64)
#define FT_FIXED(x)     ((x) * 64)
u16 *ft_buffer = BG_GFX;
u16 ft_buffer_w = SCREEN_WIDTH;
u16 ft_buffer_h = SCREEN_HEIGHT;
u32 ft_pen_r = 0;
u32 ft_pen_g = 0;
u32 ft_pen_b = 0;

//---------------------------------------------------------------------------------
void ft_print_c(FT_Bitmap *bitmap, s32 x, s32 y)
//---------------------------------------------------------------------------------
{
    u8 *src = bitmap->buffer;
    u16 *dest = &ft_buffer[y*ft_buffer_w + x];
    s32 width = bitmap->width;
    s32 height = bitmap->rows;
    s32 pitch = bitmap->pitch;
   
    s32 j, k;
    u16 *pixel, r, g, b;
   
    if(bitmap->pitch >= 0)
    {
        for(j=0; j<height; j++)
        {
            for(k=0; k<width; k++)
            {
                u8 opaque = src[k];
                if(opaque)
                {
                    pixel = &dest[j*ft_buffer_w + k];
                    r = ((*pixel)&31)*(255-opaque) + ft_pen_r*opaque;
                    g = ((*pixel>>5)&31)*(255-opaque) + ft_pen_g*opaque;
                    b = ((*pixel>>10)&31)*(255-opaque) + ft_pen_b*opaque;
                    r = (r>>8) & 31;
                    g = (g>>8) & 31;
                    b = (b>>8) & 31;
                    *pixel = BIT(15) | RGB15(r,g,b);
                }
            }
            src += pitch;
        }
    }
    else
    {
        for(j=height-1; j>=0; j--)
        {
            for(k=0; k<width; k++)
            {
                u8 opaque = src[k];
                if(opaque)
                {
                    pixel = &dest[j*ft_buffer_w + k];
                    r = ((*pixel)&31)*(255-opaque) + ft_pen_r*opaque;
                    g = ((*pixel>>5)&31)*(255-opaque) + ft_pen_g*opaque;
                    b = ((*pixel>>10)&31)*(255-opaque) + ft_pen_b*opaque;
                    r = (r>>8) & 31;
                    g = (g>>8) & 31;
                    b = (b>>8) & 31;
                    *pixel = BIT(15) | RGB15(r,g,b);
                }
            }
            src += pitch;
        }
    }
}

//---------------------------------------------------------------------------------
void ft_printf(FT_Face face, s32 x, s32 y, const wchar_t *string)
//---------------------------------------------------------------------------------
{
    if(string == 0)
        return;

    int ascent = FT_CEIL(FT_MulFix(face->bbox.yMax, face->size->metrics.y_scale));
    y += ascent;

    u32 i;
    for(i=0; string[i] != 0; i++)
    {
        if(string[i] == L' ')
        {
           x += ascent>>1;
            continue;
        }
        else if(string[i] == L'\n')
        {
            y += ascent;
            continue;
        }
       FT_Load_Char(face, string[i], FT_LOAD_RENDER);

       ft_print_c(&face->glyph->bitmap,
                   x,// + FT_FLOOR(face->glyph->metrics.horiBearingX),
                y - FT_FLOOR(face->glyph->metrics.horiBearingY));

       x += FT_CEIL(face->glyph->metrics.width)+1;
    }
}


As you can see, I haven't implemented the real "printf".
_________________
http://licklick.wordpress.com

#126747 - felix123 - Thu Apr 26, 2007 8:06 am

Can't you choose a more suitable phrase? :)
Does it work with Traditional Chinese?
_________________
Nintendo DS homebrew on Wikipedia

#126766 - Lick - Thu Apr 26, 2007 1:11 pm

As far as I know, GB2312 only contains Simplified Chinese. You can always use Unicode, Big 5, UCS 4. But those fonts are too big to fit in the Main RAM. I'm not sure how well FreeType2 works in the external RAM. Not sure if it will work at all. It should work though, as I just read this from the FreeType API reference:
Quote:
FT_New_Memory_Face

This function calls FT_Open_Face to open a font which has been loaded into memory.

...
...

note

You must not deallocate the memory before calling FT_Done_Face.


So it might work if the font is loaded into External RAM which gives you enough room for fonts of 8MB to 32MB.
_________________
http://licklick.wordpress.com

#127679 - Zarxrax - Fri May 04, 2007 12:55 am

Hmmm... I tried messing around with this, but I'm really not sure how to get started. What all do I need to do in order to get this up and running? Any sample code I could look over?

#127739 - Lick - Fri May 04, 2007 12:17 pm

Code:
// INIT FreeType2
    FT_Library library;
    FT_Error   error;
    FT_Face    face;
   

    error = FT_Init_FreeType(&library);
    if(error)
        return error;

    error = FT_New_Memory_Face(library, arial_ttf_bin, arial_ttf_bin_size, 0, &face);
    if(error)
        return error;

   FT_Set_Pixel_Sizes(face, 0, 14);


// RENDER Text
    const char *string = "Hello universe!";
    int x = 3;
    int y = 3; // at [3, 3]
   
    int ascent = FT_CEIL(FT_MulFix(face.bbox.yMax, face.size->metrics.y_scale));
    y += ascent;      // add ascent to y coordinate


    for(int i=0; string[i] != 0; i++)
    {
        if(string[i] == ' ')
        {
           x += ascent/2;
            continue;
        }
        else if(string[i] == '\n')
        {
            y += ascent;
            continue;
        }
        else
        {
           FT_Load_Char(&face, string[i], FT_LOAD_RENDER | // tell FreeType2 to render internally
                                           FT_LOAD_TARGET_NORMAL); // grayscale 0-255
           
            u8 *src = (u8 *)face.glyph->bitmap;
            u16 *dest = BG_GFX;

            int j, k;
            u16 *pixel, r, g, b;

            if(bitmap->pitch >= 0)
            {
                for(j=0; j<bitmap->rows; j++)
                {
                    for(k=0; k<bitmap->width; k++)
                    {
                        u8 alpha = src[k]; // 0-255
                        if(alpha)
                        {
                            pixel = &dest[j*ft_buffer_w + k];   // original pixel
                           
                            r = ((*pixel)&31)*(255-alpha)     + 255*alpha; // blend algorithm, our color is red
                            g = ((*pixel>>5)&31)*(255-alpha)  + 0*alpha;
                            b = ((*pixel>>10)&31)*(255-alpha) + 0*alpha;
                           
                            r = (r>>8) & 31; // convert to R5G5B5
                            g = (g>>8) & 31;
                            b = (b>>8) & 31;
                            *pixel = BIT(15) | RGB15(r,g,b); // write pixel
                        }
                    }
                    src += pitch;
                }
            }

           x += FT_CEIL(face.glyph->metrics.width) + 1; // add incorrect but cheap letterspacing
       }
    }


This should get you started. It's very linear code that you can cut into smaller functions. I even included my blending code. The biggest time-consumer I found to be FT_Load_Char, which does the internal rendering. Maybe there's a way to bypass it, or optimize it internally with ARM assembly.
_________________
http://licklick.wordpress.com

#136133 - rhaleblian - Sun Jul 29, 2007 3:33 pm

Thanks Lick, this port allowed me to make progress with a DS ebook reader. Looks pretty ok.

http://eris.kicks-ass.net ( see project pages re dslibris)

I tried to use this port on Ubuntu in an effort to move to linux from mingw and encountered problems with functions defined more than once. In comparison, the current distro of freetype builds ok for arm-eabi on Ubuntu but my code fails at runtime when trying to create a new Face.

#140358 - rhaleblian - Sat Sep 15, 2007 4:37 pm

link from above moved

http://rhaleblian.wordpress.com

#140778 - rhaleblian - Wed Sep 19, 2007 7:31 pm

i've been able to compile 2.3.5 --without-zlib and am using it in dslibris. in case anyone wants this version.
_________________
[ http://rhaleblian.wordpress.com ]