aboutsummaryrefslogtreecommitdiff
path: root/drivers/gfx.c
blob: 53d6686e9d38dc34b18f716e4b1a743fcc64a24d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gfx_font.h"
#include "log.h"
#include "multiboot.h"
#include "panic.h"
#include "gfx.h"

static uint8_t *framebuffer = NULL;
static uint16_t fb_width;
static uint16_t fb_height;

/* this is BYTES per pixel */
static uint8_t  fb_bpp;
const uint8_t *gfx_bpp = &fb_bpp;

const uint16_t *gfx_width = &fb_width;
const uint16_t *gfx_height = &fb_height;

static int cursor_x, cursor_y;
static uint32_t fgcol, bgcol;

void gfx_drawpixel(int x, int y, uint32_t col)
{
    ((uint32_t*)framebuffer)[y * fb_width + x] = col;
}

void gfx_clear(uint32_t col)
{
    uint8_t *p = framebuffer;
    uint8_t *stop = framebuffer + fb_width * fb_height * fb_bpp;
    while(p < stop)
    {
        *(uint32_t*)p = col;
        p += fb_bpp;
    }
}

void gfx_reset(void)
{
    gfx_clear(VGA_RGBPACK(0, 0, 0));
    cursor_y = 0;
    cursor_x = 0;
    fgcol = VGA_RGBPACK(0xff, 0xff, 0xff);
    bgcol = VGA_RGBPACK(0, 0, 0);
}

void gfx_drawchar(int x, int y, char c, uint32_t fg, uint32_t bg)
{
    int stride = fb_bpp * fb_width;
    uint8_t *line_addr = framebuffer + (x * fb_bpp) + (y * stride);
    for(int i = 0; i < FONT_HEIGHT; ++i)
    {
        uint32_t line_buf[8] = {bg};
        uint8_t mask = 0x80;
        for(int j = 0; j < 8; ++j, mask >>= 1)
        {
            if(gfx_font[(int)c][i] & mask)
                line_buf[j] = fg;
        }
        memcpy(line_addr, line_buf, sizeof(line_buf));
        line_addr += stride;
    }
}

void gfx_putchar(char ch)
{
    if(ch != '\n')
    {
        gfx_drawchar(cursor_x, cursor_y, ch, fgcol, bgcol);
        cursor_x += FONT_WIDTH;
        if(cursor_x >= fb_width)
        {
            cursor_x = 0;
            cursor_y += FONT_HEIGHT;
            if(cursor_y >= fb_height)
            {
                gfx_clear(bgcol);
                cursor_y = 0;
            }
        }
    }
    else
    {
        cursor_x = 0;
        cursor_y += FONT_HEIGHT;
        if(cursor_y >= fb_height)
        {
            gfx_clear(bgcol);
            cursor_y = 0;
        }
    }
}

void gfx_puts(const char* str)
{
    while(*str)
    {
        gfx_putchar(*str++);
    }
}

bool gfx_init(struct vbe_info_t *vbe_mode_info)
{
    framebuffer = (uint8_t*)vbe_mode_info->physbase;
    fb_width = vbe_mode_info->Xres;
    fb_height = vbe_mode_info->Yres;
    fb_bpp = vbe_mode_info->bpp / 8;
    if(fb_bpp != 4)
    {
        printf("WARNING: BPP != 32, falling back to text mode...\n");
        return false;
    }
    gfx_reset();
    set_putchar(gfx_putchar);
    set_puts(gfx_puts);

    return true;
}