cowos

custom OS from scratch in C
git clone git://git.daat.foo/cowos.git
Log | Files | Refs | README | LICENSE

framebuffer.c (9992B)


      1 #include <drivers/video/framebuffer.h>
      2 #include <klibc/string.h>
      3 #include <stddef.h>
      4 #include <stdarg.h>
      5 #include <limine_requests.h>
      6 #include <drivers/video/font8x16.h>
      7 
      8 static fb_console_t console;
      9 
     10 void
     11 fb_init(void)
     12 {
     13         if (framebuffer_request.response == NULL || 
     14                 framebuffer_request.response->framebuffer_count < 1) {
     15                 return;
     16         }
     17         
     18         console.fb = framebuffer_request.response->framebuffers[0];
     19         console.fg_color = 0xFFFFFF; // White
     20         console.bg_color = 0x000000; // Black
     21         console.cursor_x = 0;
     22         console.cursor_y = 0;
     23         console.cols = console.fb->width / FB_CHAR_WIDTH;
     24         console.rows = console.fb->height / FB_CHAR_HEIGHT;
     25         
     26         fb_clear();
     27 }
     28 
     29 void
     30 fb_clear(void)
     31 {
     32         if (!console.fb) return;
     33         
     34         uint32_t *fb = (uint32_t *)console.fb->address;
     35         size_t pixels = (console.fb->pitch / 4) * console.fb->height;
     36         
     37         for (size_t i = 0; i < pixels; i++) {
     38                 fb[i] = console.bg_color;
     39         }
     40         
     41         console.cursor_x = 0;
     42         console.cursor_y = 0;
     43 }
     44 
     45 void
     46 fb_draw_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color)
     47 {
     48         if (!console.fb) return;
     49         
     50         uint32_t *fb = (uint32_t *)console.fb->address;
     51         uint32_t pitch_pixels = console.fb->pitch / 4;
     52         
     53         for (uint32_t row = y; row < y + h && row < console.fb->height; row++) {
     54                 for (uint32_t col = x; col < x + w && col < console.fb->width; col++) {
     55                         fb[row * pitch_pixels + col] = color;
     56                 }
     57         }
     58 }
     59 
     60 void
     61 fb_set_color(uint32_t fg, uint32_t bg)
     62 {
     63         console.fg_color = fg;
     64         console.bg_color = bg;
     65 }
     66 
     67 static void
     68 draw_char(uint32_t x, uint32_t y, char c, uint32_t fg_color, uint32_t bg_color)
     69 {
     70         if (!console.fb) return;
     71         
     72         uint32_t *fb = (uint32_t *)console.fb->address;
     73         uint32_t pitch_pixels = console.fb->pitch / 4;
     74         
     75         // Get the font data for this character
     76         const uint8_t *char_data = &IBM_VGA_8x16[c * 16];
     77         
     78         // Draw each row of the character
     79         for (uint32_t row = 0; row < FB_CHAR_HEIGHT; row++) {
     80                 uint8_t font_row = char_data[row];
     81                 
     82                 // Draw each pixel in the row
     83                 for (uint32_t col = 0; col < FB_CHAR_WIDTH; col++) {
     84                         uint32_t px = x + col;
     85                         uint32_t py = y + row;
     86                     
     87                         // Check bounds
     88                         if (px >= console.fb->width || py >= console.fb->height) continue;
     89                         
     90                         // Check if this pixel should be set (bit test)
     91                         if (font_row & (0x80 >> col)) {
     92                                 fb[py * pitch_pixels + px] = fg_color;
     93                         } else {
     94                                 fb[py * pitch_pixels + px] = bg_color;
     95                         }
     96                 }
     97         }
     98 }
     99 
    100 static void
    101 scroll_up(void)
    102 {
    103         if (!console.fb) return;
    104         
    105         uint32_t *fb = (uint32_t *)console.fb->address;
    106         uint32_t pitch_pixels = console.fb->pitch / 4;
    107         
    108         // Move all lines up by one character height
    109         for (uint32_t y = 0; y < console.fb->height - FB_CHAR_HEIGHT; y++) {
    110                 for (uint32_t x = 0; x < console.fb->width; x++) {
    111                         fb[y * pitch_pixels + x] = fb[(y + FB_CHAR_HEIGHT) * pitch_pixels + x];
    112                 }
    113         }
    114         
    115         // Clear the last line
    116         for (uint32_t y = console.fb->height - FB_CHAR_HEIGHT; y < console.fb->height; y++) {
    117                 for (uint32_t x = 0; x < console.fb->width; x++) {
    118                         fb[y * pitch_pixels + x] = console.bg_color;
    119                 }
    120         }
    121 }
    122 
    123 void
    124 fb_putchar(char c)
    125 {
    126         if (!console.fb) return;
    127         
    128         // Handle special characters
    129         switch (c) {
    130                 case '\n':
    131                         console.cursor_x = 0;
    132                         console.cursor_y++;
    133                         break;
    134                 case '\r':
    135                         console.cursor_x = 0;
    136                         break;
    137                 case '\t':
    138                         console.cursor_x = (console.cursor_x + 8) & ~7;
    139                         break;
    140                 case '\b':
    141                         if (console.cursor_x > 0) {
    142                                 console.cursor_x--;
    143                                 draw_char(console.cursor_x * FB_CHAR_WIDTH, 
    144                                           console.cursor_y * FB_CHAR_HEIGHT, 
    145                                           ' ', console.fg_color, console.bg_color);
    146                         }
    147                         break;
    148                 default:
    149                         // Draw the character
    150                         draw_char(console.cursor_x * FB_CHAR_WIDTH, 
    151                                   console.cursor_y * FB_CHAR_HEIGHT, 
    152                                   c, console.fg_color, console.bg_color);
    153                         console.cursor_x++;
    154                         break;
    155         }
    156         
    157         // Handle line wrapping
    158         if (console.cursor_x >= console.cols) {
    159                 console.cursor_x = 0;
    160                 console.cursor_y++;
    161         }
    162         
    163         // Handle scrolling
    164         if (console.cursor_y >= console.rows) {
    165                 scroll_up();
    166                 console.cursor_y = console.rows - 1;
    167         }
    168 }
    169 
    170 void
    171 fb_puts(const char *str)
    172 {
    173         while (*str) {
    174                 fb_putchar(*str++);
    175         }
    176 }
    177 
    178 static void
    179 print_number(unsigned long num, int base, int width, char pad)
    180 {
    181         char digits[] = "0123456789ABCDEF";
    182         char buffer[32];
    183         int pos = 0;
    184         
    185         // Convert number to string (reversed)
    186         if (num == 0) {
    187                 buffer[pos++] = '0';
    188         } else {
    189                 while (num > 0) {
    190                         buffer[pos++] = digits[num % base];
    191                         num /= base;
    192                 }
    193         }
    194         
    195         // Add padding if needed
    196         while (pos < width) {
    197                 buffer[pos++] = pad;
    198         }
    199         
    200         // Print reversed
    201         while (pos > 0) {
    202                 fb_putchar(buffer[--pos]);
    203         }
    204 }
    205 
    206 static void
    207 print_signed(long num, int width, char pad)
    208 {
    209         if (num < 0) {
    210                 fb_putchar('-');
    211                 print_number(-num, 10, width, pad);
    212         } else {
    213                 print_number(num, 10, width, pad);
    214         }
    215 }
    216 
    217 void
    218 fb_printf(const char *fmt, ...)
    219 {
    220         va_list args;
    221         va_start(args, fmt);
    222         
    223         while (*fmt) {
    224                 if (*fmt == '%') {
    225                         fmt++;
    226                         
    227                         // Handle width and padding
    228                         char pad = ' ';
    229                         int width = 0;
    230                         
    231                         if (*fmt == '0') {
    232                                 pad = '0';
    233                                 fmt++;
    234                         }
    235                         
    236                         while (*fmt >= '0' && *fmt <= '9') {
    237                                 width = width * 10 + (*fmt - '0');
    238                                 fmt++;
    239                         }
    240                         
    241                         // Handle format specifiers
    242                         switch (*fmt) {
    243                                 case 'd':
    244                                 case 'i':
    245                                         print_signed(va_arg(args, int), width, pad);
    246                                         break;
    247                                     
    248                                 case 'u':
    249                                         print_number(va_arg(args, unsigned int), 10, width, pad);
    250                                         break;
    251                                     
    252                                 case 'x':
    253                                         print_number(va_arg(args, unsigned int), 16, width, pad);
    254                                         break;
    255                                     
    256                                 case 'X':
    257                                         print_number(va_arg(args, unsigned int), 16, width, pad);
    258                                         break;
    259                                     
    260                                 case 'p':
    261                                         fb_puts("0x");
    262                                         print_number((unsigned long)va_arg(args, void*), 16, 16, '0');
    263                                         break;
    264                                     
    265                                 case 'c':
    266                                         fb_putchar(va_arg(args, int));
    267                                         break;
    268                                     
    269                                 case 's':
    270                                         {
    271                                                 const char *str = va_arg(args, const char*);
    272                                                 if (str) {
    273                                                         fb_puts(str);
    274                                                 } else {
    275                                                         fb_puts("(null)");
    276                                                 }
    277                                         }
    278                                         break;
    279                                     
    280                                 case '%':
    281                                         fb_putchar('%');
    282                                         break;
    283                                     
    284                                 default:
    285                                         fb_putchar('%');
    286                                         fb_putchar(*fmt);
    287                                         break;
    288                         }
    289                 } else {
    290                         fb_putchar(*fmt);
    291                 }
    292                 fmt++;
    293         }
    294         
    295         va_end(args);
    296 }