OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Nov 21, 2018 10:26 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: Font drawing issues
PostPosted: Tue Sep 04, 2018 6:45 pm 
Offline

Joined: Mon Jun 04, 2018 6:37 am
Posts: 4
Hello all, I'm fairly new to OSDevving. I have been trying to draw characters in a video mode set by grub, 1024x768x16. I can write text, and draw and stuff, but my problem is that my font characters have weird color issues. I know it's between my Font Data Lookup Table (that I got from the wiki), and my font drawing function (that I also originally got from the wiki).

The lookup table:
Code:
unsigned int FontDataTable[] = {0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF,
                                0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF,
                                0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF,
                                0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00, 0xFFFFFFFF};

And the function:
Code:
void kernelDrawChar(unsigned int Character, unsigned char Foreground, unsigned char Background) {
  char *Where = &Framebuffer[FramebufferPosition];
  unsigned char RowData;
  unsigned int Mask;
  unsigned char *CharacterBMP = &Font[(Character)*16];

  unsigned int PackedForeground =
      (Foreground << 24) | (Foreground << 16) | (Foreground << 8) | Foreground;
  unsigned int PackedBackground =
      (Background << 24) | (Background << 16) | (Background << 8) | Background;

  for (int Row = 0; Row < FontHeight; Row++) {
    RowData = CharacterBMP[Row];
    Mask = FontDataTable[RowData >> 16] | FontDataTable[RowData & 0x0F];
    *(unsigned int *)Where =
        (PackedForeground & Mask) | (PackedBackground & ~Mask);
    RowData = CharacterBMP[Row] >> 4;
    Mask = FontDataTable[RowData >> 16] | FontDataTable[RowData & 0x0F];
    *(unsigned int *)&Where[4] =
        (PackedForeground & Mask) | (PackedBackground & ~Mask);

    Where += FramebufferPitch;
  }
  FramebufferPosition += FontWidth;
}

There is a screenshot of my kernel running under QEMU attached. The panic shown is just a test.

It's also probably worth noting I'm using the font from Apple's Darwin Kernel. https://github.com/apple/darwin-xnu/blob/master/osfmk/console/iso_font.c

I haven't ever done anything like this, so it's all a very new fun learning experience.
I've been trying to fix this for a while because to me it seems like it would be easy to fix, but I just can't solve it. I apologize if it's something simple or if my code is just all wrong :) .

Thanks in advance!


Attachments:
Screen Shot 2018-09-04 at 7.33.51 PM.png
Screen Shot 2018-09-04 at 7.33.51 PM.png [ 25.13 KiB | Viewed 385 times ]

_________________
"You’re free to praise Microsoft Windows on your own if you want, but please don’t do this in GNU packages." - GNU C Portability Standards
Top
 Profile  
 
 Post subject: Re: Font drawing issues
PostPosted: Tue Sep 04, 2018 8:06 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

OmeletHopper wrote:
Hello all, I'm fairly new to OSDevving. I have been trying to draw characters in a video mode set by grub, 1024x768x16. I can write text, and draw and stuff, but my problem is that my font characters have weird color issues. I know it's between my Font Data Lookup Table (that I got from the wiki), and my font drawing function (that I also originally got from the wiki).


The example code in the wiki is designed for 8 bits per pixel; but you're not using 8 bits per pixel - you're using "1024x768x16".

I'm not entirely sure if you're using "16 colours, 4 bits per pixel" or "65536 colours, 16 bits per pixel". For 16 colour modes the frame buffer is extremely different (arranged as four monochrome planes) and the example code in the wiki wouldn't make sense. For 16 bits per pixel there's a lot that would need to be changed (starting with the function's parameters - "unsigned char" isn't large enough for a 16-bit colour).


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Font drawing issues
PostPosted: Tue Sep 04, 2018 8:31 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi again,

I was looking at the code on the wiki and found a bug (a ">> 16" that should have been a "/ 16" or ">> 4"), but this wouldn't effect your main problem.

Assuming you're using "65536 colour, 16 bits per pixel" the code might look something like:

Code:
uint64_t font_data_lookup_table[16] = {
    0x0000000000000000UL,
    0x000000000000FFFFUL,
    0x00000000FFFF0000UL,
    0x00000000FFFFFFFFUL,
    0x0000FFFF00000000UL,
    0x0000FFFF0000FFFFUL,
    0x0000FFFFFFFF0000UL,
    0x0000FFFFFFFFFFFFUL,
    0xFFFF000000000000UL,
    0xFFFF00000000FFFFUL,
    0xFFFF0000FFFF0000UL,
    0xFFFF0000FFFFFFFFUL,
    0xFFFFFFFF00000000UL,
    0xFFFFFFFF0000FFFFUL,
    0xFFFFFFFFFFFF0000UL,
    0xFFFFFFFFFFFFFFFFUL
}

Code:
void draw_char(uint8_t *where, uint32_t character, uint_fast16_t foreground_colour, uint_fast16_t background_colour) {
    int row;
    uint8_t row_data;
    uint64_t mask1, mask2;
    uint8_t *font_data_for_char = &system_font_data_address[character * 8];
    uint64_t packed_foreground = (foreground << 48) | (foreground << 32) | (foreground << 16) | foreground;
    uint64_t packed_background = (background << 48) | (background << 32) | (background << 16) | background;

    for (row = 0; row < 8; row++) {
        row_data = font_data_for_char[row];
        mask1 = font_data_lookup_table[row_data / 16];
        mask2 = font_data_lookup_table[row_data & 0x0F];
        *(uint64_t *)where = (packed_foreground & mask1) | (packed_background & ~mask1);
        *(uint64_t *)(&where[8]) = (packed_foreground & mask2) | (packed_background & ~mask2);
        where += bytes_per_line;
    }
}



Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: Font drawing issues
PostPosted: Fri Sep 07, 2018 4:52 pm 
Offline

Joined: Mon Jun 04, 2018 6:37 am
Posts: 4
Brendan,

I've got to thank you for your fast reply. The different font lookup table you posted seems too be working great! However, the function you posted I kept having issues with. I made a few modifications to my existing function, and you can see what I've got from the screenshot. Seriously, thanks!

Quote:
I'm not entirely sure if you're using "16 colours, 4 bits per pixel" or "65536 colours, 16 bits per pixel". For 16 colour modes the frame buffer is extremely different (arranged as four monochrome planes) and the example code in the wiki wouldn't make sense.
I honestly don't know which one I'm using. The function only went to a black screen, and after playing around with it I only got garbled colors. I've uploaded a screenshot of this.

Here is my modified function and it's output:
Code:
void kernelDrawChar(unsigned int Character, char Foreground, int Background) {
  char *Where = &Framebuffer[FramebufferPosition];
  unsigned char RowData;
  unsigned int Mask;
  unsigned char *CharacterBMP = &Font[(Character)*16];

  unsigned int PackedForeground =
      (Foreground << 24) | (Foreground << 16) | (Foreground << 8) | Foreground;
  unsigned int PackedBackground =
      (Background << 24) | (Background << 16) | (Background << 8) | Background;

  for (int Row = 0; Row < FontHeight; Row++) {
    RowData = CharacterBMP[Row];
    Mask = FontDataTable[RowData & 0x0F];
    *(unsigned int *)Where =
        (PackedForeground & Mask) | (PackedBackground & ~Mask);
    Mask = FontDataTable[RowData / 16];
    *(unsigned int *)&Where[4] =
        (PackedForeground & Mask) | (PackedBackground & ~Mask);
    Where += FramebufferPitch;
  }
  FramebufferPosition += FontWidth;
}
Attachment:
Screen Shot 2018-09-07 at 5.30.17 PM.png
Screen Shot 2018-09-07 at 5.30.17 PM.png [ 9.99 KiB | Viewed 310 times ]


And here is the modified version of the one you posted and it's output:
Code:
void kernelDrawChar(uint32_t character, uint16_t foreground, uint16_t background) {
    char *where = &Framebuffer[FramebufferPosition];
    int row;
    uint8_t row_data;
    uint64_t mask1, mask2;
    uint8_t *font_data_for_char = &Font[character * 8];
    uint64_t packed_foreground = (foreground << 24) | (foreground << 16) | (foreground << 8) | foreground;
    uint64_t packed_background = (background << 24) | (background << 16) | (background << 8) | background;

    for (row = 0; row < 16; row++) {
        row_data = font_data_for_char[row];
        mask1 = FontDataTable[row_data / 16];
        mask2 = FontDataTable[row_data & 0x0F];
        *(uint64_t *)where = (packed_foreground & mask1) | (packed_background & ~mask1);
        *(uint64_t *)(&where[8]) = (packed_foreground & mask2) | (packed_background & ~mask2);
        where += FramebufferPitch;
    }
    FramebufferPosition += FontWidth;
}
Attachment:
Screen Shot 2018-09-07 at 5.37.54 PM.png
Screen Shot 2018-09-07 at 5.37.54 PM.png [ 38.16 KiB | Viewed 310 times ]


What is causing these other problems with my function? Is it just that yours is the correct one and I'm doing something wrong?
I am aware that I swapped the Mask assignments in mine, this makes it draw the font correctly. Is this part of it?
I will say the new font lookup table you've provided definitely is better.
Thanks!

_________________
"You’re free to praise Microsoft Windows on your own if you want, but please don’t do this in GNU packages." - GNU C Portability Standards


Top
 Profile  
 
 Post subject: Re: Font drawing issues
PostPosted: Fri Sep 07, 2018 7:05 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

OmeletHopper wrote:
I've got to thank you for your fast reply. The different font lookup table you posted seems too be working great! However, the function you posted I kept having issues with. I made a few modifications to my existing function, and you can see what I've got from the screenshot. Seriously, thanks!

Quote:
I'm not entirely sure if you're using "16 colours, 4 bits per pixel" or "65536 colours, 16 bits per pixel". For 16 colour modes the frame buffer is extremely different (arranged as four monochrome planes) and the example code in the wiki wouldn't make sense.
I honestly don't know which one I'm using.


You can't write correct code without knowing how the video card expects a pixel to be represented. How a pixel is represented includes its size (how many bits) it's location in the frame buffer (e.g. planar vs. "packed pixel") and what each bit means (e.g. if it's an index into the palette or if it's a direct RGB value, and if it is a direct RGB value which bits represent what - e.g. if the 16 bits are "rrrrrggggggbbbbb" or "bbbbbggggggrrrrr" or something else).

Trying to work backwards from the pictures, there's a few things that I've noticed.

First; both of the pieces of code you've posted have almost exactly the same calculation controlling where pixel data is stored. Specifically, these lines are identical in both versions:

Code:
void kernelDrawChar(uint32_t character, uint16_t foreground, uint16_t background) {
    char *where = &Framebuffer[FramebufferPosition];

    for (row = 0; row < 16; row++) {

        *(uint64_t *)where = ...

        where += FramebufferPitch;
    }
    FramebufferPosition += FontWidth;
}


However, despite using exactly the same calculation for "where", the screenshots/pictures are showing that both versions are writing data in completely different places on the screen. That doesn't make any sense (unless there's bug/s or differences somewhere else).

Second, for the first picture (I opened it in GIMP and blew it up to take a close look) characters are 5 pixels wide and look like several columns of pixels are being skipped in each character. That indicates something is wrong with the calculation of "where". Maybe "FontWidth" is 5 when it should be 8; and maybe "FontWidth" is 8 but "Framebuffer" is an array of bytes or a pointer to bytes (and not an array of "uint16_t" or pointer to "uint16_t") and you're doing "FramebufferPosition += FontWidth;" when you should be doing "FramebufferPosition += FontWidth * bytes_per_pixel;", and then doing an extra "FramebufferPosition += 2;" somewhere else (in the code that calls your "kernelDrawChar()" function?) to make it add up to 10 bytes (or 5 pixels).

Third; if you are using a "2 bytes per pixel" video mode (either 15 bits per pixel or 16 bits per pixel) there's multiple other things wrong (e.g. the shift counts in "uint64_t packed_foreground = (foreground << 24) | (foreground << 16) | (foreground << 8) | foreground;").

Based on all of this (and that changing the "font_data_lookup_table" to suit 16 bits per pixel got rid of the blue/yellow colours you were getting before); I'd say that it is a 16 bit per pixel video mode, and while you were trying to fix symptoms of the "FramebufferPosition += FontWidth" bug you made everything else wrong for 16 bits per pixel (and "more right" for the 8 bits per pixel code you started with that at least gave you something that vaguely looked like characters before).


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 12 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group