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.

Coding > display character size...(quite urgent..)

#134256 - mk2007 - Thu Jul 12, 2007 2:24 am

Hi friends,

i have a function in my program to dispaly the character with color whatever i put..

the code is following..


void printfC(u32 address, u8 x, u8 y, char *str, enum COLOUR colour)

//address - destination address (i.e.: map address)
//x, y - co-ordinate determines location in array

// (0,0) = 0; (1,0) = 1; ... (29,0) = 29; (30,0) = 30; (31,0) = 31;
// (0,1) = 32; (1,1) = 33; ... (29,1) = 61; (30,1) = 62; (31,1) = 63;
// (0,2) = 64; (1,2) = 65; ... (29,2) = 93; (30,2) = 94; (31,2) = 95;
// (0,3) = 96; (1,3) = 97; ... (29,3) = 125; (30,3) = 126; (31,3) = 127;
// so (x,y) = (x + (y * 32));
{
if (strlen(str) == 0)
return;


u16 *pDst;
pDst = (u16*)address;

u16 location;

location = (x + (y * 32));

u16 len = strlen(str) + location;
u8 value;

for (u16 i = location; i < len; i++)
{
if (*str == 32)
value = (*str - 32);
else if (((*str) >= 48) && ((*str) <= 57))
{
value = *str;

switch (colour)
{
case GREEN:
value += 73; //121 - 48
break;
case RED:
value += 109;
break;
case BLUE:
value += 145;
break;
}
}
else
{
value = *str;

switch (colour)
{
case GREEN:
value += 30; //95 - 65
break;
case RED:
value += 66;
break;
case BLUE:
value += 102;
break;
}
}
pDst[i] = value;
str++;
}

}

i am using this in my game boy program..

by this function i can display the character with color..

but i want to display my character as big size..how to i display my character in the screen as big size then now..

is there any function to make character big to display..

is there any formula to display the character as big then now.??


please if u have any example coding or any information regarding this..

please forward me..

this is quite urgent..

waiting for your valuable reply..


with regarding,
kar..

#134310 - gmiller - Thu Jul 12, 2007 1:00 pm

Typically in the bitmap modes the character would be "described" by a font that gives pixel layout that you can use to turn your pixes to the color you built. Depending how the font information is built you just need to iterate over the rows and columns to "paint" the character. There are many ways to store the font so I will not say one is right or wrong. For my 8x8 fonts I use a bit for each pixel so the font information is one byte per column (8 bits) and since there are 8 rows the total size is 8 bytes per character in the font.

The code is pretty simple to implement with a set of loops, one for the number of rows, and the inner loop looping for the number of columns. If the bit is on in the font then turn the pixel on or turn the pixel off.

Tile modes are a little trickier and need a set of "tiles" with the characters in it and then change the map to reference the tile.

Of course there may be easier ways to do this so I suggest looking at some of the libraries that are out there to see how they did it.

#134448 - mk2007 - Fri Jul 13, 2007 6:33 am

Hi gmiller,

Thanks for your reply..

i am really greatful to you if send me example coding..

because i am new gameboy and c programming..

so can u please??

because i am reallly in deadline..

waiting for your reply..

with regards,
mk

#134473 - Cearn - Fri Jul 13, 2007 10:00 am

This forum has [code] tags with which you can preserve the formatting of code, making it easier to read. For example:
Code:
void printfC(u32 address, u8 x, u8 y, char *str, enum COLOUR colour)
{
    if (strlen(str) == 0)
        return;

    u16 *pDst;
    pDst = (u16*)address;
   
    u16 location;
   
    location = (x + (y * 32));
   
    u16 len = strlen(str) + location;
    u8 value;
   
    for (u16 i = location; i < len; i++)
    {
        if (*str == 32)
            value = (*str - 32);
        else if (((*str) >= 48) && ((*str) <= 57))
        {
            value = *str;
           
            switch (colour)
            {
            case GREEN:
                value += 73; //121 - 48
                break;
            case RED:
                value += 109;
                break;
            case BLUE:
                value += 145;
                break;
            }
        }
        else
        {
            value = *str;
           
            switch (colour)
            {
            case GREEN:
                value += 30; //95 - 65
                break;
            case RED:
                value += 66;
                break;
            case BLUE:
                value += 102;
                break;
            }
        }
        pDst[i] = value;
        str++;
    }
}


There are a few ways in which this code can be cleaned up. I'd like you to consider this (comments on what I did are indicated with "//#'):
Code:
// Font data: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

// Font base tiles
#define ALPHA_TID    95
#define DIGIT_TID   (ALPHA_TID+26)

void printfC(u16 *dst,  //# Use pointers, not raw addresses.
    int x,              //# Native datatype is better. int/u32
    int y,              //#    when you can, others only when you have to.
    const char *str,    //# 'const' if you're not gonna change the data
    enum COLOUR colour)
{
    int ch;             //# Again, ints (or u32 for unsigneds)
    u32 value;

    dst += y*32 + x;    // Adjust destination for location

    //# There is no need for strlen
    while( (ch=*str++) != '\0')
    {
        // Switch between space/digits/letters, and apply colour.

        //# See text
        if(ch == ' ')                   // Space
            value= 0;
        else if(ch>='0' && ch <= '9')   // Digits
            value= ch-'0' + DIGIT_TID + colour*36;
        else                            // Letters
            value= ch-'A' + ALPHA_TID + colour*36;

        *dst++ = value;
    }
}

I have assumed here that you are have three sets of letters and digits, starting at tile 95 and arranged like [A-Z][0-9]. That would be where GREEN, followed by letters/digits in RED and then BLUE, both at offsets of 26+10 = 36. If I'm incorrect in this, the code will have to be modified a little. Points to note:
  • Addresses are often meaningless; C works with pointers, so pass a pointer, not an address.
  • CPUs have a 'native' datatype, usually represented by 'int'. They are better equipped to deal with that datatype and others can cost a little more work to deal with. ARM chips are 32-bit; 8-bit and 16-bit datatypes can cost between 0% and 100% extra work for the processor, depending on use. Unless you have a compelling reason not to, use int.
  • The const keyword is a way of saying that the data of that parameter will not be modified. It is recommended (but by no means required) that you use const for pointers parameters - it gives the programmer and the compiler extra information about how the function used that parameter. It also means that you don't have to cast things when passing const items to them. It pretty much is required to have graphics/string and other data as const, because otherwise they go into internal work RAM (32kb) instead of ROM where they belong.
  • The strlen routine goes through the whole string, looking for the null-character ('\0') when you have to go through the whole string yourself anyway, it's better to search for '\0' yourself.
  • Magic numbers are bad, mkay? If you hadn't added the "// 95-65" comments, the code would have been a mystery. It's recommended to use "named literals" using "#define" or "static const int ...". In this case, I've used ALPHA_TID (Tile InDex) to indicate the place where the letters start and DIGIT_TID where the digits start. I've also used character constants ' ', '0', '9' and 'A', as this is clearer than the raw ascii numbers.
  • When you have if-else-statements or switch-blocks that don't are virtually the same except for a single number or character, they can usually be replaced by arithmetic expressions. The latter are shorter in code, easier to read and faster as well. If it can't be done by arithmetic, it can be done by look-up tables.


I should also note that instead of using three sets of characters, you could use one set and switch colors by using palette-swapping, as done here). This saves you an extra 72 tiles.

This is also useful if you want larger characters, say 16x16 instead of 8x8 (if this wasn't what you were after, you have to be clearer in what you mean by 'big size'. If the answer to that does not include multiples of 8, the code will be tricky). With a 16x16 font, you're using 4 tiles/character, so 4*36=144 for a full set, and 432 for all three colors. Unless you use palette swapping.

For a 16x16 version of what you have now, make the scaled font and convert the bitmap as if they were 16x16 sprites. For any character, the base tile-index will be 'base= ALPHA_BIG_TID + (ch-typeoffset)*4'. Then you have to place base, base+1, base+2, base+3 in the map at dst, dst+1, dst+32 and dst+32+1. Example code:
Code:

#define COLOUR_PITCH    (36*4)      //# For pal-swaps, use 0x1000 here
#define ALPHA_BIG_TID    ???        //# This will have to change
#define DIGIT_BIG_TID   (ALPHA_TID+26*4)

void printfC16(u16 *dst, int x,  int y,  const char *str, enum COLOUR colour)
{
    int ch;
    u32 base;

    dst += y*32 + x;    // Adjust destination for location

    while( (ch=*str++) != '\0')
    {
        // Switch between space/nums/chars, and apply colour.

        if(ch == ' ')                           // Space
        {
            dst[ 0]= 0;     dst[ 1]= 0;
            dst[32]= 0;     dst[33]= 0;
        }
        else
        {
            base= ch + colour*COLOUR_PITCH;
            if(ch >= '0' && ch <= '9')            // Numbers
                base= ch-'0' + DIGIT_BIG_TID;
            else                                // Letters
                base= ch-'A' + ALPHA_BIG_TID;

            dst[ 0]= base;      dst[ 1]= base+1;
            dst[32]= base+2;    dst[33]= base+3;
        }

        // Move ahead 2 screen entries
        dst += 2;
    }
}

#134714 - mk2007 - Mon Jul 16, 2007 3:14 am

Hi Cearn,

i am really greatful to you for your quick reply..
and youf time spent for me..

now i need to display 16*16 size..
bcoz i need to display bigger size character in the screen..

i think your function is quite useful..

then one more think is that how to cretae the
caled font and convert the bitmap?? this one i dn't know..if u have already this bitmap..please post to me(we need to convert the bitmap to header file am i right?)).


waiting for your value reply..

advance thanks fro your kindness and help..

wit regards,
kar..