SYS_GetFontTexture & SYS_GetFontTexel
SYS_GetFontTexture & SYS_GetFontTexel
Hi,
in my projects, I want to be able to easily display text in various font size but still want to rely on the IPL font only (and do no want to use libfreetype or any embedded PNG fonts)
The best way to do it seems to read/decode the font from the Boot ROM (which we are already doing fine) then render a textured quad from each char, based on the font data.
I came across those two little undocumented functions (SYS_GetFontTexture & SYS_GetFontTexel) in system.c and was wondering if some libogc authors could help me:
1/ to understand how to use these functions (what are the arguments passed in,...)
2/ to know what I should do first to be able to use them (is SYS_InitFont enough, why passing a fontheader in argument ?)
Thank you
in my projects, I want to be able to easily display text in various font size but still want to rely on the IPL font only (and do no want to use libfreetype or any embedded PNG fonts)
The best way to do it seems to read/decode the font from the Boot ROM (which we are already doing fine) then render a textured quad from each char, based on the font data.
I came across those two little undocumented functions (SYS_GetFontTexture & SYS_GetFontTexel) in system.c and was wondering if some libogc authors could help me:
1/ to understand how to use these functions (what are the arguments passed in,...)
2/ to know what I should do first to be able to use them (is SYS_InitFont enough, why passing a fontheader in argument ?)
Thank you
Re: SYS_GetFontTexture & SYS_GetFontTexel
Based on yagcd the font is a compressed I4 texture. And looking at libogc/system.c I'd say SYS_InitFont decompresses the font and fills in the font header with the information how to render text.
SYS_GetFontTexture seems to just return the texture address and glyph position, if you want to render it using the existing texture, SYS_GetFontTexel copies the glyph into your own texture.
Trying to use this is on my TODO list, but so far I didn't have the time. Let me know if you get anything working.
By the way, would it be worth overriding the font encoding instead of selecting it automatically? Both the PAL and NTSC firmware seem to have the font at the same position, so an application could use whatever encoding it wants.
SYS_GetFontTexture seems to just return the texture address and glyph position, if you want to render it using the existing texture, SYS_GetFontTexel copies the glyph into your own texture.
Trying to use this is on my TODO list, but so far I didn't have the time. Let me know if you get anything working.
By the way, would it be worth overriding the font encoding instead of selecting it automatically? Both the PAL and NTSC firmware seem to have the font at the same position, so an application could use whatever encoding it wants.
Re: SYS_GetFontTexture & SYS_GetFontTexel
seems like I don't get it working but at least this lead me trying to figure how the stuff was workingSamson wrote:Based on yagcd the font is a compressed I4 texture. And looking at libogc/system.c I'd say SYS_InitFont decompresses the font and fills in the font header with the information how to render text.
SYS_GetFontTexture seems to just return the texture address and glyph position, if you want to render it using the existing texture, SYS_GetFontTexel copies the glyph into your own texture.
Trying to use this is on my TODO list, but so far I didn't have the time. Let me know if you get anything working.
By the way, would it be worth overriding the font encoding instead of selecting it automatically? Both the PAL and NTSC firmware seem to have the font at the same position, so an application could use whatever encoding it wants.
now there are some things confusing me, here is what I figured so far (would have been easier if the code had been commented btw ) :
1/ beside the wellknown YaY0 font compression, the original texture data is also in compressed format: 1 byte represents 4 pixels, so each pixel is coded as a 2-bytes value (0-3) and represent an index into a 4-entry color lookup table stored at the end of the font header (c0,c1,c2,c3 in libogc definition). Each LUT entry is one byte, with a 4bits color intensity value most probably duplicated in LSB and MSB...
2/ the compressed texture data is "expanded" to a I4 texture (1 byte = 2 pixels, each 4-bits nibble representing pixel color intensity) by SYS_InitFont and the original compresssed data is overwritten by I4 texture data:
Code: Select all
sys_fontimage = (u8*)((((u32)unpacked_data+sys_fontdata->sheet_image)+31)&~31);
__expand_font(unpacked_data+sys_fontdata->sheet_image,sys_fontimage);
3/ SYS_GetFontTexture returns a pointer to the decompressed texture data (I4 format) and horizontal/vertical offsets (in pixels) to the cell containing the character. It's up to you to read the texture data correctly (all texture are generally stored in 32 bytes block, which means 8x8 texels blocks are stored consecutively in memory)
Code: Select all
*image = [b]sys_fontimage[/b]+(sys_fontdata->sheet_size*sheets);
Code: Select all
img_start = (u8*)[b]sys_fontdata+sys_fontdata->sheet_image[/b]+(sys_fontdata->sheet_size*sheets);
Then, it seems there are two errors in this function, regarding the byte offset calculation in the destination texture:
Code: Select all
ptr2 = image+((ypos/8)*(((stride<<2)/8)<<5));
ptr2 = ptr2+(((xpos+pos)/8)<<5);
ptr2 = ptr2+(((xpos+pos)%8)/2);
- "stride" generally means the width in bytes of the texture image, so to get the base offset for a given line, it should be:
vertical offset in number of 8x8 texels blocks = line / 8
horizontal offset in number of 8x8 texels blocks = (stride * 2) / 8
offset in bytes = (line /8) * (stride * 2 / * 32
so
Code: Select all
ptr2 = image+((ypos/8)*(((stride<<1)/8)<<5));
Code: Select all
ptr2 = image+((ypos/8)*(((stride<<2)/8)<<5));
- a final vertical offset is missing, the offset within the 8x8 block. The following line should be added :
Code: Select all
ptr2 = ptr2+((ypos%8)<<2);
Hope that helps..
Re: SYS_GetFontTexture & SYS_GetFontTexel
ok, let's continue on this one (maybe it could be useful to someone else)
after fixing the "SYS_GetFontTexel," function, I found out that this was still not working: got a blank texture
the strange thing is: if I replace the two "while" nested loop by two "for" loops, this is now working
works but
doesn't !
can some C guru explain me why ?
after fixing the "SYS_GetFontTexel," function, I found out that this was still not working: got a blank texture
the strange thing is: if I replace the two "while" nested loop by two "for" loops, this is now working
Code: Select all
for(ypos = 0;ypos<sys_fontdata->cell_height;ypos++) {
for(xpos = 0;xpos<sys_fontdata->cell_width;xpos++) {
ptr1 = img_start+((((sys_fontdata->sheet_width/8)<<5)/2)*((ypos+yoff)/8));
ptr1 = ptr1+(((xpos+xoff)/8)<<4);
ptr1 = ptr1+(((ypos+yoff)%8)<<1);
ptr1 = ptr1+(((xpos+xoff)%8)/4);
ptr2 = image+((ypos/8)*(((stride<<1)/8)<<5));
ptr2 = ptr2+(((xpos+pos)/8)<<5);
ptr2 = ptr2+(((xpos+pos)%8)/2);
ptr2 = ptr2+(((ypos+yoff)%8)<<2);
idx = (*ptr1>>(6-(((xpos+pos)%4)<<1)))&0x03;
val = data[idx];
if(((xpos+pos)%2)) mask = 0x0f;
else mask = 0xf0;
*ptr2 = *ptr2|(val&mask);
}
}
Code: Select all
while(ypos<sys_fontdata->cell_height) {
while(xpos<sys_fontdata->cell_width) {
ptr1 = img_start+((((sys_fontdata->sheet_width/8)<<5)/2)*((ypos+yoff)/8));
ptr1 = ptr1+(((xpos+xoff)/8)<<4);
ptr1 = ptr1+(((ypos+yoff)%8)<<1);
ptr1 = ptr1+(((xpos+xoff)%8)/4);
ptr2 = image+((ypos/8)*(((stride<<1)/8)<<5));
ptr2 = ptr2+(((xpos+pos)/8)<<5);
ptr2 = ptr2+(((xpos+pos)%8)/2);
ptr2 = ptr2+(((ypos+yoff)%8)<<2);
idx = (*ptr1>>(6-(((xpos+pos)%4)<<1)))&0x03;
val = data[idx];
if(((xpos+pos)%2)) mask = 0x0f;
else mask = 0xf0;
*ptr2 = *ptr2|(val&mask);
xpos++;
}
ypos++;
}
can some C guru explain me why ?
Re: SYS_GetFontTexture & SYS_GetFontTexel
Maybe because xpos is not reset to 0 for each row? I assume ypos is initialised to 0.
Re: SYS_GetFontTexture & SYS_GetFontTexel
exactly, I figured this a little later
ANother thing I figured out: the SYS_InitFont crashes the system
indeed, the _expand_font (which expand compressed I4 texture data to normal I4 texture data) requires at least twice the size of the original FONT.
but (let's take the ANSI example):
-YAYO compressed font is 12288 bytes read in BOOTROM
-uncompressed font is 65808 bytes (according to the YAY0 header)
-libogc allocates 131072+288 bytes for the FONT buffer
-YAY0 font is stored at the end of the buffer (exactly buffer_address+131072+288-12288)
-It is then decompresssed at buffer_address+288
This only leaves (131072+288)-288-65808=65264 bytes after the raw texture data
However, decompressed texture data is 131072 bytes (512*512 pixels), which means that the raw one is half that size (65536 bytes) and that he "expand" function requires at least the same size after the end of the raw texture data.
As you can see, there is some memory space missing, which results in memory overflow and program crash
The solution is to decompress the YAY0 compressed font at the start of the allocated buffer (and NOT at buffer_address+288 as SYS_InitFont is doing)
ANother thing I figured out: the SYS_InitFont crashes the system
indeed, the _expand_font (which expand compressed I4 texture data to normal I4 texture data) requires at least twice the size of the original FONT.
but (let's take the ANSI example):
-YAYO compressed font is 12288 bytes read in BOOTROM
-uncompressed font is 65808 bytes (according to the YAY0 header)
-libogc allocates 131072+288 bytes for the FONT buffer
-YAY0 font is stored at the end of the buffer (exactly buffer_address+131072+288-12288)
-It is then decompresssed at buffer_address+288
This only leaves (131072+288)-288-65808=65264 bytes after the raw texture data
However, decompressed texture data is 131072 bytes (512*512 pixels), which means that the raw one is half that size (65536 bytes) and that he "expand" function requires at least the same size after the end of the raw texture data.
As you can see, there is some memory space missing, which results in memory overflow and program crash
The solution is to decompress the YAY0 compressed font at the start of the allocated buffer (and NOT at buffer_address+288 as SYS_InitFont is doing)
Re: SYS_GetFontTexture & SYS_GetFontTexel
Hi,
first of all: Thanks for pointing this out.
To the Yay0 decompression: this 288byte offset is needed because if there's a "link" in the compressed data the offset may become negative.
And while the destination buffer is used to read out from that offset to write it to the current position in the dest buffer you need to have this 288B offset.
Therefor it's probably better to double the 288B extension rather than to start from 0 in the dest buffer for decompression.
regards
shagkur
first of all: Thanks for pointing this out.
To the Yay0 decompression: this 288byte offset is needed because if there's a "link" in the compressed data the offset may become negative.
And while the destination buffer is used to read out from that offset to write it to the current position in the dest buffer you need to have this 288B offset.
Therefor it's probably better to double the 288B extension rather than to start from 0 in the dest buffer for decompression.
regards
shagkur
Re: SYS_GetFontTexture & SYS_GetFontTexel
Oh, I see.. I'll leave the correction to you then
Anyway, i finally get working IPL font rendering using GX texture
Just to let you know, I had to modify the SYS_InitFont function to return a pointer a sys_fontheader structure:
instead of simply doing this:
because it didn't seems to return correct header information
I also fixed the SYS_GetFontTexel function:
- removed redundant font expanding (as it is already done during initialization)
- fixed source pointer calculation (as source texture is already expanded and now take twice memory as before)
- fixed destination pointer calculation (stride parameter was not handled properly and line offset within the 8x8 tile was missing)
- fixed character clamping (first and last character were considered as invalid, now uses font header informations)
- fixed nested loops indexes initialization (xpos was not reinitialized before the loop)
Anyway, i finally get working IPL font rendering using GX texture
Just to let you know, I had to modify the SYS_InitFont function to return a pointer a sys_fontheader structure:
Code: Select all
return sys_fontdata;
Code: Select all
*font_header = *sys_fontdata;
I also fixed the SYS_GetFontTexel function:
- removed redundant font expanding (as it is already done during initialization)
- fixed source pointer calculation (as source texture is already expanded and now take twice memory as before)
- fixed destination pointer calculation (stride parameter was not handled properly and line offset within the 8x8 tile was missing)
- fixed character clamping (first and last character were considered as invalid, now uses font header informations)
- fixed nested loops indexes initialization (xpos was not reinitialized before the loop)
Code: Select all
void SYS_GetFontTexel(s32 c,void *image,s32 pos,s32 stride,s32 *width)
{
u32 sheets,rem;
u32 xoff,yoff;
u32 xpos,ypos;
u8 *img_start;
u8 *ptr1,*ptr2;
if(!sys_fontwidthtab || ! sys_fontimage) return;
if(c<sys_fontdata->first_char || c>sys_fontdata->last_char) c = sys_fontdata->inval_char;
else c -= sys_fontdata->first_char;
sheets = c/sys_fontcharsinsheet;
rem = c%sys_fontcharsinsheet;
xoff = (rem%sys_fontdata->sheet_column)*sys_fontdata->cell_width;
yoff = (rem/sys_fontdata->sheet_column)*sys_fontdata->cell_height;
img_start = sys_fontimage+(sys_fontdata->sheet_size*sheets);
xpos = 0; ypos = 0;
while(ypos<sys_fontdata->cell_height) {
xpos = 0;
while(xpos<sys_fontdata->cell_width) {
ptr1 = img_start+(((sys_fontdata->sheet_width/8)<<5)*((ypos+yoff)/8));
ptr1 = ptr1+(((xpos+xoff)/8)<<5);
ptr1 = ptr1+(((ypos+yoff)%8)<<2);
ptr1 = ptr1+(((xpos+xoff)%8)/2);
ptr2 = image+((ypos/8)*(((stride<<1)/8)<<5));
ptr2 = ptr2+(((xpos+pos)/8)<<5);
ptr2 = ptr2+((ypos%8)<<2);
ptr2 = ptr2+(((xpos+pos)%8)/2);
*ptr2 = *ptr1;
xpos++;
}
ypos++;
}
*width = sys_fontwidthtab[c];
}
Re: SYS_GetFontTexture & SYS_GetFontTexel
Hi,
well, apologize for all the hassle you got with that.
Also i've taken again a deeper look into the yay0 decompression and you was right with removing the 288B offset.
Dunno where this comes from, but probably from the old cube days.
So i now decompress, as proposed by you, directly into the beginning of the buffer.
Hmm....quite strange that "*font_header = *sys_fontheader" doesnt work. should use the builtin memcpy.
Could you do a manual memcpy at this line for a test? (I'm not able to test this right now - currently i'm in the office)
Also i'd like to thank you for fixing the other function. I'll immediately take this into the SVN
kind regards
shagkur
well, apologize for all the hassle you got with that.
Also i've taken again a deeper look into the yay0 decompression and you was right with removing the 288B offset.
Dunno where this comes from, but probably from the old cube days.
So i now decompress, as proposed by you, directly into the beginning of the buffer.
Hmm....quite strange that "*font_header = *sys_fontheader" doesnt work. should use the builtin memcpy.
Could you do a manual memcpy at this line for a test? (I'm not able to test this right now - currently i'm in the office)
Also i'd like to thank you for fixing the other function. I'll immediately take this into the SVN
kind regards
shagkur
Re: SYS_GetFontTexture & SYS_GetFontTexel
No problem, I actually found some fun in understanding how stuff work at a lower level ...
about that pointer issue, memcpy does not work either. The two following implementations work though:
About the "SYS_GetFontTexel" function, here is a better (faster) implementation. The second loop should be something like this (xpos+=2 instead of xpos++):
about that pointer issue, memcpy does not work either. The two following implementations work though:
Code: Select all
u32 SYS_InitFont(sys_fontheader **font_header)
{
/*if(!font_header) return 0;
memset(font_header,0,sizeof(sys_fontheader));*/
...
*font_header = sys_fontdata;
}
Code: Select all
sys_fontheader *SYS_InitFont()
{
...
return sys_fontdata;
}
About the "SYS_GetFontTexel" function, here is a better (faster) implementation. The second loop should be something like this (xpos+=2 instead of xpos++):
Code: Select all
while(xpos<sys_fontdata->cell_width) {
ptr1 = img_start+(((sys_fontdata->sheet_width/8)<<5)*((ypos+yoff)/8));
ptr1 = ptr1+(((xpos+xoff)/8)<<5);
ptr1 = ptr1+(((ypos+yoff)%8)<<2);
ptr1 = ptr1+(((xpos+xoff)%8)/2);
ptr2 = image+((ypos/8)*(((stride<<1)/8)<<5));
ptr2 = ptr2+(((xpos+pos)/8)<<5);
ptr2 = ptr2+((ypos%8)<<2);
ptr2 = ptr2+(((xpos+pos)%8)/2);
*ptr2 = *ptr1;
xpos+=2;
}
Who is online
Users browsing this forum: Google [Bot] and 1 guest