How do I load a .sfn font into my kernel?
How do I load a .sfn font into my kernel?
Hi.
I want to use Scalable Screen Font in my kernel, but I don't understand how I can load a .sfn file.
As far as I understand, I should convert it to a .o file using objcopy and find a character there that points to the address of the beginning of characters and pass it to a Scalable Screen Font?
Tell me more.
Thanks.
I want to use Scalable Screen Font in my kernel, but I don't understand how I can load a .sfn file.
As far as I understand, I should convert it to a .o file using objcopy and find a character there that points to the address of the beginning of characters and pass it to a Scalable Screen Font?
Tell me more.
Thanks.
Last edited by mrjbom on Mon Apr 27, 2020 1:57 pm, edited 2 times in total.
Re: How do I load a. sfn font into my kernel?
The same way as you would load any other file. For example you could use your VFS implementation and locate the font in your initrd. Or you can load it from your boot partition using a simple FAT driver etc. You can also embed a font in your kernel. This is up to you.mrjbom wrote:Hi.
I want to use Scalable Screen Font in my kernel, but I don't understand how I can load a .sfn file.
Yes, converting into .o and linking with your kernel is definitely one way to do it. Embedding is the simplest as absolutely no run-time support needed and therefore suits an early kernel console's needs (downside you have to recompile the kernel to replace the font).mrjbom wrote:As far as I understand, I should convert it to a .o file using objcopy and find a character there that points to the address of the beginning of characters and pass it to a Scalable Screen Font?
Tell me more.
Thanks.
Let's say you have a "console.sfn" file. Then you can use the linker for example like this:
Code: Select all
ld -r -b binary -o console.o console.sfn
Code: Select all
readelf -s console.o
Code: Select all
extern unsigned char _binary_console_sfn_start;
/* for the simple renderer */
ssfn_font = &_binary_console_sfn_start;
/* for the userspace renderer */
ssfn_load(&ctx, &_binary_console_sfn_start);
Please note that the simple renderer (which is intended for kernel consoles) can only render unscaled bitmap fonts (converted from X11 Bitmap Fonts or PC Screen Fonts etc.). Its goal was to be simple and small (less than 1k and totally dependency-free). Passing an invalid font in ssfn_font results in UD. The normal userspace renderer requires libc, and in return supports all fonts (bitmap, pixmap, vector), scaling, anti-aliasing etc.
Some linkers do not support the "-b binary" option (like CLang on MacOSX), for those you can use objconv, or you can convert the font into a C header file, like "unsigned char _binary_console_font_start[] = { 0xXX, 0xXX, 0xXX, ... };". A simple awk or perl script can read the file and print out hex bytes to do this (or any other script language that I know, except shell script). In PHP or Python you can use the "unpack" function.
For example Linux uses this C array approach for basic fonts during early boot time, then it switches to console font loaded from the file system.
Cheers,
bzt
Re: How do I load a. sfn font into my kernel?
I have a problem with the layout of the .o file with font.bzt wrote:This object file will contain a label, _binary_console_sfn_start. You can check this withCode: Select all
ld -r -b binary -o console.o console.sfn
I use a cross-compiler for linking .o files.
I do it with this command:
Code: Select all
./i386-elf-4.9.1-Linux-x86_64/bin/i386-elf-gcc -T link.ld -o kernel-0 -ffreestanding ./o/bootloaderasm.o ./o/irqhandlersasm.o ./FreeSans.o ${buildObjectRoutes[@]} -nostdlib -lgcc
Code: Select all
./FreeSans.o: file not recognized
What's wrong?
Last edited by mrjbom on Sat Apr 25, 2020 6:56 am, edited 1 time in total.
Re: How do I load a. sfn font into my kernel?
You forgot to post the error message.
Re: How do I load a. sfn font into my kernel?
The problem was that I used ld that comes as part of the distribution, but I need to use ld that comes as part of the cross-compiler.iansjack wrote:You forgot to post the error message.
Re: How do I load a. sfn font into my kernel?
I have a problem.bzt wrote: Now all you need to do is passing the address of this label to the SSFN renderer:Code: Select all
extern unsigned char _binary_console_sfn_start; /* for the simple renderer */ ssfn_font = &_binary_console_sfn_start; /* for the userspace renderer */ ssfn_load(&ctx, &_binary_console_sfn_start);
The symbol is not drawn, instead I see some garbage on the screen(these bars).
Using ld from the cross compiler, I created .o file as you suggested.
Declared variables in .h file
Code: Select all
unsigned char _binary_FSfont_sfn_start;
unsigned char _binary_FSfont_sfn_end;
unsigned char _binary_FSfont_sfn_size;
Code: Select all
unsigned char _binary_FSfont_sfn_start;
unsigned char _binary_FSfont_sfn_end;
unsigned char _binary_FSfont_sfn_size;
Code: Select all
// set up context by global variables
ssfn_font = (ssfn_font_t*)&_binary_FSfont_sfn_start; // the bitmap font to use
ssfn_dst_ptr = (uint8_t*)lfb_framebuffer_addr; // framebuffer address and bytes per line
ssfn_dst_pitch = 4096;
ssfn_fg = 0xFFFF; // colors, white on black
ssfn_bg = 0;
ssfn_x = 100; // coordinates to draw to
ssfn_y = 200;
// render one glyph directly to the screen and then adjust ssfn_x and ssfn_y
dprintf("code: %i\n", ssfn_putc(0x41));
dprintf("_binary_FSfont_sfn_start = 0x%X\n", &_binary_FSfont_sfn_start);
dprintf("_binary_FSfont_sfn_end = 0x%X\n", &_binary_FSfont_sfn_end);
dprintf("_binary_FSfont_sfn_size = 0x%X\n", &_binary_FSfont_sfn_size);
Code: Select all
code: 0
_binary_FSfont_sfn_start = 0x106000
_binary_FSfont_sfn_end = 0x1610c0
_binary_FSfont_sfn_size = 0x5b0c0
How do I set this variable?
Re: How do I load a. sfn font into my kernel?
You should not declare them. They are provided by the .o file, so in your header you should define them as "extern". Btw, it is only the "_start" that you'll need.mrjbom wrote: Declared them in the .c fileCode: Select all
unsigned char _binary_FSfont_sfn_start; unsigned char _binary_FSfont_sfn_end; unsigned char _binary_FSfont_sfn_size;
I'm not sure what is your intend with this. The "ssfn_putc()" renders directly into the framebuffer, its return value is irrelevant.mrjbom wrote:Code: Select all
dprintf("code: %i\n", ssfn_putc(0x41));
Also I've warned you that "ssfn_putc()" does not check its input, and accepts only bitmap fonts. Is "_binary_FSfont_sfn_start" a bitmap font? I believe not, I think it's a vector font, converted from FreeSerif.ttf. Those can be displayed only by the normal user space renderer (as vector fonts needs rasterization, which depends on malloc to allocate raster lines).
To check if a font contains bitmap glyphs or vector glyphs, you can dump the font with "sfn2asc -d". If the "Fragments" section contains only SSFN_FRAG_BITMAP then you're good. Or, if you prefer GUIs, you can open the font with "sfnedit", and click on one character. If you see curves in the Edit window, then it's a vector glyph. If you see a bitmap image, then it's a bitmap glyph. SSFN files can store mixed glyphs (like all characters has vector contours except emojis are defined by colorful pixelmaps.)
You get it from VESA info / GRUB MultiBoot struct. VESA calls it "scanline", but that's essentially the same thing as the pitch. In short, that's the number of bytes per line (which is not necessarily the same as width times byte per pixel). You must also set the proper define for your selected video mode. SSFN_CONSOLEBITMAP_HICOLOR is for 15 and 16 bit modes.mrjbom wrote:I believe that I incorrectly configured a certain variable, such as ssfn_dst_pitch, how do I configure it correctly?
How do I set this variable?
If you're using 32 bits, then include the console renderer with truecolor, and set the color with 32 bit:
Code: Select all
#define SSFN_CONSOLEBITMAP_TRUECOLOR
ssfn_fg = 0x00FFFFFF;
Cheers,The define selects the destination buffer's pixel format. SSFN_CONSOLEBITMAP_PALETTE selects 1 byte
(indexed), SSFN_CONSOLEBITMAP_HICOLOR selects 2 bytes (5-5-5 or 5-6-5 RGB) and SSFN_CONSOLEBITMAP_TRUECOLOR
selects 4 bytes (8-8-8-8 xRGB). For performance reasons, 3 bytes (24 bit true color) mode is not supported.
The SSFN_CONSOLEBITMAP_CLEARBG can be added to any of the above defines. That will turn transparency off, and
will fill the glyph's background with ssfn_bg.
bzt
Re: How do I load a. sfn font into my kernel?
I understand, but I still have some difficulties in the visualization of the glyph. I am trying to draw a white letter A on a dark background, it is drawn correctly, but in addition to it, extra pixels were drawn at the bottom.bzt wrote:You should not declare them. They are provided by the .o file, so in your header you should define them as "extern". Btw, it is only the "_start" that you'll need.mrjbom wrote: Declared them in the .c fileCode: Select all
unsigned char _binary_FSfont_sfn_start; unsigned char _binary_FSfont_sfn_end; unsigned char _binary_FSfont_sfn_size;
I'm not sure what is your intend with this. The "ssfn_putc()" renders directly into the framebuffer, its return value is irrelevant.mrjbom wrote:Code: Select all
dprintf("code: %i\n", ssfn_putc(0x41));
Also I've warned you that "ssfn_putc()" does not check its input, and accepts only bitmap fonts. Is "_binary_FSfont_sfn_start" a bitmap font? I believe not, I think it's a vector font, converted from FreeSerif.ttf. Those can be displayed only by the normal user space renderer (as vector fonts needs rasterization, which depends on malloc to allocate raster lines).
To check if a font contains bitmap glyphs or vector glyphs, you can dump the font with "sfn2asc -d". If the "Fragments" section contains only SSFN_FRAG_BITMAP then you're good. Or, if you prefer GUIs, you can open the font with "sfnedit", and click on one character. If you see curves in the Edit window, then it's a vector glyph. If you see a bitmap image, then it's a bitmap glyph. SSFN files can store mixed glyphs (like all characters has vector contours except emojis are defined by colorful pixelmaps.)
You get it from VESA info / GRUB MultiBoot struct. VESA calls it "scanline", but that's essentially the same thing as the pitch. In short, that's the number of bytes per line (which is not necessarily the same as width times byte per pixel). You must also set the proper define for your selected video mode. SSFN_CONSOLEBITMAP_HICOLOR is for 15 and 16 bit modes.mrjbom wrote:I believe that I incorrectly configured a certain variable, such as ssfn_dst_pitch, how do I configure it correctly?
How do I set this variable?
If you're using 32 bits, then include the console renderer with truecolor, and set the color with 32 bit:You should read the SSFN API documentation, it explains this all.Code: Select all
#define SSFN_CONSOLEBITMAP_TRUECOLOR ssfn_fg = 0x00FFFFFF;
Cheers,The define selects the destination buffer's pixel format. SSFN_CONSOLEBITMAP_PALETTE selects 1 byte
(indexed), SSFN_CONSOLEBITMAP_HICOLOR selects 2 bytes (5-5-5 or 5-6-5 RGB) and SSFN_CONSOLEBITMAP_TRUECOLOR
selects 4 bytes (8-8-8-8 xRGB). For performance reasons, 3 bytes (24 bit true color) mode is not supported.
The SSFN_CONSOLEBITMAP_CLEARBG can be added to any of the above defines. That will turn transparency off, and
will fill the glyph's background with ssfn_bg.
bzt
Also, the position of the letter does not match the position specified during rendering
This is what the glyph creation code looks like:
Code: Select all
void test_func()
{
ssfn_t ctx; /* the renderer context */
ssfn_glyph_t *glyph; /* the returned rasterized bitmap */
memset(&ctx, 0, sizeof(ssfn_t));
//FreeSans.sfn
ssfn_load(&ctx, (ssfn_font_t*)&_binary_FSfont_sfn_start);
ssfn_select(&ctx,
SSFN_FAMILY_SANS, NULL, /* family */
SSFN_STYLE_REGULAR /*| SSFN_STYLE_UNDERLINE*/, 64, /* style and size */
SSFN_MODE_BITMAP /* rendering mode */
);
glyph = ssfn_render(&ctx, 0x41);
//render gryph
draw_glyph_lfb_mem(glyph, 400, 300, 0xFFFFFF);
/* free resources */
kfree(glyph); /* no special treatment for freeing glyphs */
ssfn_free(&ctx); /* free the renderer context's internal buffers */
}
Code: Select all
void draw_glyph_lfb_mem(ssfn_glyph_t *glyph, int pen_x, int pen_y, uint32_t fgcolor)
{
int x, y, i, m;
/* align glyph properly, we may have received a vertical letter */
if(glyph->adv_y)
pen_x -= glyph->baseline;
else
pen_y -= glyph->baseline;
switch(glyph->mode) {
case SSFN_MODE_OUTLINE:
if(glyph->pitch>1) {
x = glyph->data[0]; y = glyph->data[1];
for(i = 0; i < glyph->pitch; i += 2) {
/* end of a contour? */
if(glyph->data[i] == 255 && glyph->data[i+1] == 255) i += 2;
/* no, connect this point to the previous one. You should provide your own line() */
else draw_line_lfb_mem(pen_x + x, pen_y + y, pen_x + glyph->data[i], pen_y + glyph->data[i+1], fgcolor);
x = glyph->data[i]; y = glyph->data[i+1];
}
}
break;
case SSFN_MODE_BITMAP:
for(y = 0; y < glyph->h; y++)
for(x = 0, i = 0, m = 1; x < glyph->w; x++, m <<= 1) {
if(m > 0x80) { m = 1; i++; }
//SDL_PIXEL = (glyph->data[y * glyph->pitch + i] & m) ? 0xFF000000 | fgcolor : 0;
lfb_framebuffer_addr[y * MBI->framebuffer_pitch / 4 + x] = ((glyph->data[y * glyph->pitch + i] & m) ? 0xFF000000 | fgcolor : 0);
}
break;
/*
case SSFN_MODE_ALPHA:
for(y = 0; y < glyph->h; y++)
for(x = 0; x < glyph->w; x++)
SDL_PIXEL = (uint32_t)((glyph->data[y * glyph->pitch + x] << 24) | fgcolor);
break;
case SSFN_MODE_CMAP:
for(y = 0; y < glyph->h; y++)
for(x = 0; x < glyph->w; x++)
SDL_PIXEL = SSFN_CMAP_TO_ARGB(glyph->data[y * glyph->pitch + x], glyph->cmap, fgcolor);
break;
*/
}
}
Re: How do I load a. sfn font into my kernel?
Good to see you managed to load the font! I see you decided to go on with the user space renderer.
Also you should pass a variable to "draw_glyph_lfb_mem", and then adjust that variable by glyph->adv_x to get the coordinate of the next character.
Read through the SSFN API, it starts with explaining the font metrics. If something is not straigtforward in the doc, please let me know and I'll add more explanations. Glyphs are scaled to their natural sizes. To scale the full glyph's size, use SSFN_STYLE_ABS_SIZE to style parameter (stands for absolute size). Note that with absolute size you'll get odd sized glyphs for "A" and "g" relative to each other, as the overall bounding box will be scaled.
From the picture it looks like your font has incorrect height set (or just as well could be right for 64 pixels, as many fonts has "tails" going beneath the baseline, however looks a bit too high). I'd suggest to print out the glyph's width, height and baseline values to see if they're correct. Not sure what font you're using. Dumping the font is very helpful. It will also do some very through verification, and it will warn you if some metrics are incorrectly set by any chance (like baseline is bigger than height for example). You can tweak those properties using command line options to the converters. Also if you see any problem, then you can fix the font easily: use sfn2asc to convert it into a text file. Then you can edit the font with a plain text editor, and check if you have an extremely high glyph that makes the entire font that high. Then use bit2sfn that will convert the text version back into binary (or use the correct options when converting).
Take a look at the aforementioned sfntest directory, there are many examples there both for simple renderer and user space renderer, and also for bitmap and vector fonts too. The fonts directory has some example fonts. First try those, and only use your own font once your code is working perfectly with the fonts in the repo. This way you can rule out if the problem is with your code or with the font itself.
For example, unifont.sfn.gz and u_vga16.sfn are a bitmap fonts, usable by ssfn_putc and ssfn_render both. FreeSans.sfn.gz is a vector font, converted from FreeSans.otf, known to have correct metrics. You can render this into a bitmap of a certain size using ssfn_render (but ssfn_putc can't use it as its not a bitmap font).
You can use sfntest1.c to see how to use ssfn_putc. sfntest2.c uses the user space renderer. Try to pass your FSfont.sfn font to these on the command line. If there's something wrong with your font metrics, you'll see.
Cheers,
bzt
That's perfectly normal. Characters are drawn at their baseline, you have to take that into account. For example, pen_y is going to be the bottom most pixels for "A", but it is in the middle for "g".mrjbom wrote:Also, the position of the letter does not match the position specified during rendering
Also you should pass a variable to "draw_glyph_lfb_mem", and then adjust that variable by glyph->adv_x to get the coordinate of the next character.
Read through the SSFN API, it starts with explaining the font metrics. If something is not straigtforward in the doc, please let me know and I'll add more explanations. Glyphs are scaled to their natural sizes. To scale the full glyph's size, use SSFN_STYLE_ABS_SIZE to style parameter (stands for absolute size). Note that with absolute size you'll get odd sized glyphs for "A" and "g" relative to each other, as the overall bounding box will be scaled.
Not entirely sure, I need more information to help you. I see you don't use the ALPHA rendering, which is the prefered way (you fill up a box with a desired color, then you simply copy the alpha channel from the glyph, and voilá, you have an anti-aliased pixel map which you can blit as any other image). Just a suggestion, using bitmap is fine too.mrjbom wrote:What am I doing wrong?
From the picture it looks like your font has incorrect height set (or just as well could be right for 64 pixels, as many fonts has "tails" going beneath the baseline, however looks a bit too high). I'd suggest to print out the glyph's width, height and baseline values to see if they're correct. Not sure what font you're using. Dumping the font is very helpful. It will also do some very through verification, and it will warn you if some metrics are incorrectly set by any chance (like baseline is bigger than height for example). You can tweak those properties using command line options to the converters. Also if you see any problem, then you can fix the font easily: use sfn2asc to convert it into a text file. Then you can edit the font with a plain text editor, and check if you have an extremely high glyph that makes the entire font that high. Then use bit2sfn that will convert the text version back into binary (or use the correct options when converting).
Take a look at the aforementioned sfntest directory, there are many examples there both for simple renderer and user space renderer, and also for bitmap and vector fonts too. The fonts directory has some example fonts. First try those, and only use your own font once your code is working perfectly with the fonts in the repo. This way you can rule out if the problem is with your code or with the font itself.
For example, unifont.sfn.gz and u_vga16.sfn are a bitmap fonts, usable by ssfn_putc and ssfn_render both. FreeSans.sfn.gz is a vector font, converted from FreeSans.otf, known to have correct metrics. You can render this into a bitmap of a certain size using ssfn_render (but ssfn_putc can't use it as its not a bitmap font).
You can use sfntest1.c to see how to use ssfn_putc. sfntest2.c uses the user space renderer. Try to pass your FSfont.sfn font to these on the command line. If there's something wrong with your font metrics, you'll see.
Cheers,
bzt
Re: How do I load a. sfn font into my kernel?
bzt wrote:Good to see you managed to load the font! I see you decided to go on with the user space renderer.That's perfectly normal. Characters are drawn at their baseline, you have to take that into account. For example, pen_y is going to be the bottom most pixels for "A", but it is in the middle for "g".mrjbom wrote:Also, the position of the letter does not match the position specified during rendering
Also you should pass a variable to "draw_glyph_lfb_mem", and then adjust that variable by glyph->adv_x to get the coordinate of the next character.
Read through the SSFN API, it starts with explaining the font metrics. If something is not straigtforward in the doc, please let me know and I'll add more explanations. Glyphs are scaled to their natural sizes. To scale the full glyph's size, use SSFN_STYLE_ABS_SIZE to style parameter (stands for absolute size). Note that with absolute size you'll get odd sized glyphs for "A" and "g" relative to each other, as the overall bounding box will be scaled.
Not entirely sure, I need more information to help you. I see you don't use the ALPHA rendering, which is the prefered way (you fill up a box with a desired color, then you simply copy the alpha channel from the glyph, and voilá, you have an anti-aliased pixel map which you can blit as any other image). Just a suggestion, using bitmap is fine too.mrjbom wrote:What am I doing wrong?
From the picture it looks like your font has incorrect height set (or just as well could be right for 64 pixels, as many fonts has "tails" going beneath the baseline, however looks a bit too high). I'd suggest to print out the glyph's width, height and baseline values to see if they're correct. Not sure what font you're using. Dumping the font is very helpful. It will also do some very through verification, and it will warn you if some metrics are incorrectly set by any chance (like baseline is bigger than height for example). You can tweak those properties using command line options to the converters. Also if you see any problem, then you can fix the font easily: use sfn2asc to convert it into a text file. Then you can edit the font with a plain text editor, and check if you have an extremely high glyph that makes the entire font that high. Then use bit2sfn that will convert the text version back into binary (or use the correct options when converting).
Take a look at the aforementioned sfntest directory, there are many examples there both for simple renderer and user space renderer, and also for bitmap and vector fonts too. The fonts directory has some example fonts. First try those, and only use your own font once your code is working perfectly with the fonts in the repo. This way you can rule out if the problem is with your code or with the font itself.
For example, unifont.sfn.gz and u_vga16.sfn are a bitmap fonts, usable by ssfn_putc and ssfn_render both. FreeSans.sfn.gz is a vector font, converted from FreeSans.otf, known to have correct metrics. You can render this into a bitmap of a certain size using ssfn_render (but ssfn_putc can't use it as its not a bitmap font).
You can use sfntest1.c to see how to use ssfn_putc. sfntest2.c uses the user space renderer. Try to pass your FSfont.sfn font to these on the command line. If there's something wrong with your font metrics, you'll see.
Cheers,
bzt
I solved the problem with the fact that my letter was drawn in the wrong position on the axis that I indicated.
But I can't figure out how to align it vertically.
I want the upper-left corner of the letter to be in that pink dot.
This is how I draw the glyph
Code: Select all
void draw_glyph_lfb_mem(ssfn_glyph_t *glyph, int pen_x, int pen_y, uint32_t fgcolor)
{
int x, y, i, m;
/* align glyph properly, we may have received a vertical letter */
if(glyph->adv_y)
pen_x -= glyph->baseline;
else
pen_y -= glyph->baseline;
switch(glyph->mode) {
case SSFN_MODE_OUTLINE:
if(glyph->pitch>1) {
x = glyph->data[0]; y = glyph->data[1];
for(i = 0; i < glyph->pitch; i += 2) {
/* end of a contour? */
if(glyph->data[i] == 255 && glyph->data[i+1] == 255) i += 2;
/* no, connect this point to the previous one. You should provide your own line() */
else draw_line_lfb_mem(pen_x + x, pen_y + y, pen_x + glyph->data[i], pen_y + glyph->data[i+1], fgcolor);
x = glyph->data[i]; y = glyph->data[i+1];
}
}
break;
case SSFN_MODE_BITMAP:
for(y = 0; y < glyph->h; y++)
for(x = 0, i = 0, m = 1; x < glyph->w; x++, m <<= 1) {
if(m > 0x80) { m = 1; i++; }
//SDL_PIXEL = (glyph->data[y * glyph->pitch + i] & m) ? 0xFF000000 | fgcolor : 0;
lfb_framebuffer_addr[(pen_y + y - glyph->baseline) * MBI->framebuffer_pitch / 4 + (pen_x + x)] = ((glyph->data[y * glyph->pitch + i] & m) ? 0xFF000000 | fgcolor : 0);
}
break;
case SSFN_MODE_ALPHA:
for(y = 0; y < glyph->h; y++)
for(x = 0; x < glyph->w; x++)
lfb_framebuffer_addr[(pen_y + y - glyph->baseline) * MBI->framebuffer_pitch / 4 + (pen_x + x)] = (uint32_t)((glyph->data[y * glyph->pitch + x] << 24) | fgcolor);
break;
case SSFN_MODE_CMAP:
for(y = 0; y < glyph->h; y++)
for(x = 0; x < glyph->w; x++)
lfb_framebuffer_addr[(pen_y + y - glyph->baseline) * MBI->framebuffer_pitch / 4 + (pen_x + x)] = SSFN_CMAP_TO_ARGB(glyph->data[y * glyph->pitch + x], glyph->cmap, fgcolor);
break;
}
}
Re: How do I load a .sfn font into my kernel?
Hi,
I can only repeat myself: Try your font with sfntest2, and try your code with one of the shipped fonts. Dump the font (sfn2asc -d) or convert it into a text version and open it in a text editor.
Maybe attach the font here so that I can take a look at it.
Just a sidenote, you don't align Latin letters vertically, you align them on their baseline. Otherwise you can align the generated glyph's bounding box. The ssfn_render function returns a (in your case) bitmap, you're free to place that anywhere on screen. Only ssfn_putc renders to the screen directly.
Cheers,
bzt
I can only repeat myself: Try your font with sfntest2, and try your code with one of the shipped fonts. Dump the font (sfn2asc -d) or convert it into a text version and open it in a text editor.
Maybe attach the font here so that I can take a look at it.
Just a sidenote, you don't align Latin letters vertically, you align them on their baseline. Otherwise you can align the generated glyph's bounding box. The ssfn_render function returns a (in your case) bitmap, you're free to place that anywhere on screen. Only ssfn_putc renders to the screen directly.
Cheers,
bzt
Re: How do I load a .sfn font into my kernel?
This is a font that I took from a folder in your repository.bzt wrote:Hi,
I can only repeat myself: Try your font with sfntest2, and try your code with one of the shipped fonts. Dump the font (sfn2asc -d) or convert it into a text version and open it in a text editor.
Maybe attach the font here so that I can take a look at it.
Tell me if it is normal that the height of the glyph is disproportionately large compared to its width.bzt wrote:Just a sidenote, you don't align Latin letters vertically, you align them on their baseline. Otherwise you can align the generated glyph's bounding box. The ssfn_render function returns a (in your case) bitmap, you're free to place that anywhere on screen. Only ssfn_putc renders to the screen directly.
For example, in my case(and early reports show the code) I get the dimensions of the glyph.
Code: Select all
glyph height: 187
glyph width: 39
gryph baseline: 44
I tried using FreeSerif from your repository, it doesn't solve the problem with glyph height, it's always too big.
Re: How do I load a .sfn font into my kernel?
So your FSfont.sfn file is actually the FreeSans font (converted from TTF). Good to know!mrjbom wrote:This is a font that I took from a folder in your repository.
Yes, it could be. That depends on the glyphs defined. There are many letters which have acutes above and also below, not to mention Asian scripts like Devanagari. However showing "A" at the very top is definitely wrong, because FreeSans also has Latin scripts with accents.mrjbom wrote:Tell me if it is normal that the height of the glyph is disproportionately large compared to its width.
No, you misunderstood. The height can be, and usually is larger than the size. Without absolute size style, the difference of the bearing top and the baseline is the size. So for example if you render a letter "A" in 64 pixels, then the difference between the top and bottom lines which have pixels set in "A" will be 64 pixels. The returned pixel map must be taller, because there must be place for letters like "Á" (more above) and "q" (more below). Use SSFN_STYLE_ABS_SIZE if you want the render to return a pixel map with height of exactly 64 pixels (but then the actual size of "A" will depend on the bounding box, aka the other glyphs defined in the font).mrjbom wrote:For example, in my case(and early reports show the code) I get the dimensions of the glyph.The API Font Metrics specifies that the height of the glyph should not be so large and should not be more than the size of the letter itself and not capture anything extraCode: Select all
glyph height: 187 glyph width: 39 gryph baseline: 44
Anyway, I'll take a look at it, because at first 187 seems too big for 64 pixels size, and the baseline of 44 can't be right.
Cheers,
bzt
Re: How do I load a .sfn font into my kernel?
When this style is added, the height of the glyph actually becomes 64, but the width becomes approximately 10. The letter just gets smaller, but a huge dark space under it remains.bzt wrote:Use SSFN_STYLE_ABS_SIZE if you want the render to return a pixel map with height of exactly 64 pixels (but then the actual size of "A" will depend on the bounding box, aka the other glyphs defined in the font).
I also encountered this problem: some letters come down, their baseline is clearly lower than the rest of the letters.
Code: Select all
//FreeSans.sfn
ssfn_load(&ctx, (ssfn_font_t*)&_binary_FSfont_sfn_start);
ssfn_select(&ctx,
SSFN_FAMILY_SANS, NULL, /* family */
SSFN_STYLE_REGULAR /*| SSFN_STYLE_UNDERLINE*/, 64, /* style and size */
SSFN_MODE_BITMAP /* rendering mode */
);
//render gryph
int x = 400, y = 300;
glyph = ssfn_render(&ctx, 'A');
draw_glyph_lfb_mem(glyph, x, y, 0xFFFFFF);
x += glyph->adv_x;
y += glyph->adv_y;
glyph = ssfn_render(&ctx, 'a');
draw_glyph_lfb_mem(glyph, x, y, 0xFFFFFF);
x += glyph->adv_x;
y += glyph->adv_y;
glyph = ssfn_render(&ctx, 'B');
draw_glyph_lfb_mem(glyph, x, y, 0xFFFFFF);
x += glyph->adv_x;
y += glyph->adv_y;
glyph = ssfn_render(&ctx, 'b');
draw_glyph_lfb_mem(glyph, x, y, 0xFFFFFF);
Re: How do I load a .sfn font into my kernel?
Okay, we have two things here.
First, about the baseline, the problem is definitely in your code. I've quickly modified sfntest8: I've added 64 pixel size as the 7th line, and "AaBb" to the string. As you can see in the attachment it is rendered correctly in all sizes (28, 120 and finally 64).
Second, I can confirm that the rendered bitmap is taller than it should be. I did the math on paper, and with FreeSans using quality 6 (which has bounding box top 284, bottom 737 and baseline at 634), rendering in 64 pixels size should result in 82 pixels, not 187. This means there's an issue when calculating the height, which I'll find and fix.
Thanks for the feedback, I couldn't catch this bug without you! Until the fix arrives, I'd recommend printing characters with transparent background. You can clear the area first, then put the text (not the best solution, I know, but this is just a temporary workaround for the time being).
Cheers,
bzt
First, about the baseline, the problem is definitely in your code. I've quickly modified sfntest8: I've added 64 pixel size as the 7th line, and "AaBb" to the string. As you can see in the attachment it is rendered correctly in all sizes (28, 120 and finally 64).
Second, I can confirm that the rendered bitmap is taller than it should be. I did the math on paper, and with FreeSans using quality 6 (which has bounding box top 284, bottom 737 and baseline at 634), rendering in 64 pixels size should result in 82 pixels, not 187. This means there's an issue when calculating the height, which I'll find and fix.
Thanks for the feedback, I couldn't catch this bug without you! Until the fix arrives, I'd recommend printing characters with transparent background. You can clear the area first, then put the text (not the best solution, I know, but this is just a temporary workaround for the time being).
Cheers,
bzt