mirror of
https://github.com/encounter/osdev.git
synced 2026-07-10 12:18:43 -07:00
Working RGB VGA output, RGB text console & bitmap fonts
This commit is contained in:
@@ -35,6 +35,7 @@ set(SOURCE_FILES
|
||||
dwarf
|
||||
stdio_impl
|
||||
bmp
|
||||
psf
|
||||
arch/x86/mmu
|
||||
drivers/ports
|
||||
drivers/timer
|
||||
|
||||
+22
-45
@@ -1,63 +1,40 @@
|
||||
#include "bmp.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
|
||||
uint8_t *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader) {
|
||||
FILE *filePtr; //our file pointer
|
||||
BITMAPFILEHEADER bitmapFileHeader; //our bitmap file header
|
||||
unsigned char *bitmapImage; //store image data
|
||||
// int imageIdx = 0; //image index counter
|
||||
// unsigned char tempRGB; //our swap variable
|
||||
uint8_t *bmp_read_image(const char *filename, bmp_info_header_t *bmp_info_header) {
|
||||
FILE *bmp_file;
|
||||
bmp_file_header_t header;
|
||||
uint8_t *img_data;
|
||||
|
||||
//open filename in read binary mode
|
||||
filePtr = fopen(filename, "r");
|
||||
if (ferror(filePtr))
|
||||
bmp_file = fopen(filename, "r");
|
||||
if (ferror(bmp_file))
|
||||
return NULL;
|
||||
|
||||
//read the bitmap file header
|
||||
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
|
||||
|
||||
//verify that this is a bmp file by check bitmap id
|
||||
if (bitmapFileHeader.bfType != 0x4D42) {
|
||||
fclose(filePtr);
|
||||
fread(&header, sizeof(bmp_file_header_t), 1, bmp_file);
|
||||
if (ferror(bmp_file) || header.type != 0x4D42) {
|
||||
fclose(bmp_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//read the bitmap info header
|
||||
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
|
||||
fread(bmp_info_header, sizeof(bmp_info_header_t), 1, bmp_file);
|
||||
fseek(bmp_file, header.img_data_offset, SEEK_SET);
|
||||
|
||||
//move file point to the begging of bitmap data
|
||||
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
|
||||
|
||||
printf("Image size: %Xh, offset: %Xh\n", bitmapInfoHeader->biSizeImage, bitmapFileHeader.bfOffBits);
|
||||
|
||||
//allocate enough memory for the bitmap image data
|
||||
bitmapImage = (unsigned char *) malloc(bitmapInfoHeader->biSizeImage);
|
||||
|
||||
//verify memory allocation
|
||||
if (!bitmapImage) {
|
||||
free(bitmapImage);
|
||||
fclose(filePtr);
|
||||
img_data = malloc(bmp_info_header->img_data_size);
|
||||
if (img_data == NULL) {
|
||||
errno = ENOMEM;
|
||||
free(img_data);
|
||||
fclose(bmp_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//read in the bitmap image data
|
||||
fread(bitmapImage, bitmapInfoHeader->biSizeImage, 1, filePtr);
|
||||
|
||||
//make sure bitmap image data was read
|
||||
if (ferror(filePtr)) {
|
||||
fclose(filePtr);
|
||||
fread(img_data, bmp_info_header->img_data_size, 1, bmp_file);
|
||||
if (ferror(bmp_file)) {
|
||||
fclose(bmp_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//swap the r and b values to get RGB (bitmap is BGR)
|
||||
// for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) {
|
||||
// tempRGB = bitmapImage[imageIdx];
|
||||
// bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
|
||||
// bitmapImage[imageIdx + 2] = tempRGB;
|
||||
// }
|
||||
|
||||
//close file and return bitmap iamge data
|
||||
fclose(filePtr);
|
||||
return bitmapImage;
|
||||
fclose(bmp_file);
|
||||
return img_data;
|
||||
}
|
||||
|
||||
+20
-27
@@ -2,32 +2,25 @@
|
||||
|
||||
#include <common.h>
|
||||
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t WORD;
|
||||
typedef uint32_t DWORD;
|
||||
typedef uint64_t QWORD;
|
||||
typedef long _LONG;
|
||||
typedef struct _packed bmp_file_header {
|
||||
uint16_t type; //specifies the file type
|
||||
uint32_t size; //specifies the size in bytes of the bitmap file
|
||||
uint32_t reserved;
|
||||
uint32_t img_data_offset; //species the offset in bytes from the bitmapfileheader to the bitmap bits
|
||||
} bmp_file_header_t;
|
||||
|
||||
typedef struct _packed tagBITMAPFILEHEADER {
|
||||
WORD bfType; //specifies the file type
|
||||
DWORD bfSize; //specifies the size in bytes of the bitmap file
|
||||
WORD bfReserved1; //reserved; must be 0
|
||||
WORD bfReserved2; //reserved; must be 0
|
||||
DWORD bfOffBits; //species the offset in bytes from the bitmapfileheader to the bitmap bits
|
||||
} BITMAPFILEHEADER;
|
||||
typedef struct _packed bmp_info_header {
|
||||
uint32_t header_size; //specifies the number of bytes required by the struct
|
||||
uint32_t width; //specifies width in pixels
|
||||
uint32_t height; //species height in pixels
|
||||
uint16_t planes; //specifies the number of color planes, must be 1
|
||||
uint16_t bit_count; //specifies the number of bit per pixel
|
||||
uint32_t compression;//spcifies the type of compression
|
||||
uint32_t img_data_size; //size of image in bytes
|
||||
uint32_t x_per_meter; //number of pixels per meter in x axis
|
||||
uint32_t y_per_meter; //number of pixels per meter in y axis
|
||||
uint32_t num_colors_used; //number of colors used by th ebitmap
|
||||
uint32_t num_colors_important; //number of colors that are important
|
||||
} bmp_info_header_t;
|
||||
|
||||
typedef struct _packed tagBITMAPINFOHEADER {
|
||||
DWORD biSize; //specifies the number of bytes required by the struct
|
||||
_LONG biWidth; //specifies width in pixels
|
||||
_LONG biHeight; //species height in pixels
|
||||
WORD biPlanes; //specifies the number of color planes, must be 1
|
||||
WORD biBitCount; //specifies the number of bit per pixel
|
||||
DWORD biCompression;//spcifies the type of compression
|
||||
DWORD biSizeImage; //size of image in bytes
|
||||
_LONG biXPelsPerMeter; //number of pixels per meter in x axis
|
||||
_LONG biYPelsPerMeter; //number of pixels per meter in y axis
|
||||
DWORD biClrUsed; //number of colors used by th ebitmap
|
||||
DWORD biClrImportant; //number of colors that are important
|
||||
} BITMAPINFOHEADER;
|
||||
|
||||
uint8_t *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader);
|
||||
uint8_t *bmp_read_image(const char *filename, bmp_info_header_t *bmp_info_header);
|
||||
+2
-7
@@ -31,14 +31,9 @@ void console_set_serial_enabled(bool enabled) {
|
||||
*/
|
||||
static void knprint(const char *str, size_t len, uint8_t vga_color) {
|
||||
if (vga_enabled) {
|
||||
int offset = vga_get_cursor_offset();
|
||||
int row = vga_get_offset_row(offset);
|
||||
int col = vga_get_offset_col(offset);
|
||||
|
||||
int offset = -1;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
offset = vga_print_char(str[i], col, row, vga_color);
|
||||
row = vga_get_offset_row(offset);
|
||||
col = vga_get_offset_col(offset);
|
||||
offset = vga_print_char(str[i], offset, vga_color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+191
-51
@@ -1,16 +1,38 @@
|
||||
#include "vga.h"
|
||||
#include "ports.h"
|
||||
#include "../arch/x86/mmu.h"
|
||||
#include "../psf.h"
|
||||
#include "../console.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
|
||||
// EGA text console
|
||||
uint16_t *console_fb_addr = NULL;
|
||||
|
||||
// RGB text console
|
||||
void *rgb_fb_addr = NULL;
|
||||
framebuffer_info_t rgb_fb_info = {};
|
||||
|
||||
psf_font_t rgb_console_font = {};
|
||||
void *rgb_console_font_glyphs = NULL;
|
||||
|
||||
unsigned int rgb_console_rows = 0;
|
||||
unsigned int rgb_console_cols = 0;
|
||||
int rgb_console_offset = 0;
|
||||
|
||||
typedef struct rgb_console_buffer_entry {
|
||||
char c;
|
||||
vga_rgb_color_t fg_color;
|
||||
vga_rgb_color_t bg_color;
|
||||
} rgb_console_buffer_entry_t;
|
||||
|
||||
rgb_console_buffer_entry_t *rgb_console_buffer = NULL;
|
||||
|
||||
static void vga_console_repaint();
|
||||
|
||||
void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info) {
|
||||
if (type == VGA_FB_TYPE_EGA_TEXT) {
|
||||
console_fb_addr = fb_addr;
|
||||
@@ -20,16 +42,59 @@ void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info) {
|
||||
}
|
||||
}
|
||||
|
||||
int vga_load_font(const char *filename) {
|
||||
int prev_width = 0, prev_height = 0;
|
||||
if (rgb_console_font_glyphs != NULL) {
|
||||
prev_width = rgb_console_font.width;
|
||||
prev_height = rgb_console_font.height;
|
||||
free(rgb_console_font_glyphs);
|
||||
}
|
||||
|
||||
rgb_console_font_glyphs = psf_read_font(filename, &rgb_console_font);
|
||||
if (rgb_console_font_glyphs == NULL) {
|
||||
fprintf(stderr, "Failed to read font %s (err: %d)\n", filename, errno);
|
||||
return -1;
|
||||
}
|
||||
rgb_console_cols = rgb_fb_info.width / rgb_console_font.width;
|
||||
rgb_console_rows = rgb_fb_info.height / rgb_console_font.height;
|
||||
|
||||
size_t buffer_size = rgb_console_rows * rgb_console_cols * sizeof(rgb_console_buffer_entry_t);
|
||||
rgb_console_buffer_entry_t *new_buffer = malloc(buffer_size);
|
||||
if (new_buffer == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory for console buffer.\n");
|
||||
return -1;
|
||||
}
|
||||
memset(new_buffer, 0, buffer_size);
|
||||
|
||||
if (rgb_console_buffer != NULL) {
|
||||
size_t prev_size = (rgb_fb_info.width / prev_width)
|
||||
* (rgb_fb_info.height / prev_height)
|
||||
* sizeof(rgb_console_buffer_entry_t);
|
||||
if (prev_size > buffer_size) {
|
||||
size_t diff = prev_size - buffer_size;
|
||||
memcpy(new_buffer, (void *) rgb_console_buffer + diff, buffer_size);
|
||||
// FIXME refactor to avoid this kludgy division
|
||||
rgb_console_offset -= diff / sizeof(rgb_console_buffer_entry_t);
|
||||
} else {
|
||||
memcpy(new_buffer, rgb_console_buffer, prev_size);
|
||||
memset((void *) new_buffer + prev_size, 0, buffer_size - prev_size);
|
||||
}
|
||||
free(rgb_console_buffer);
|
||||
}
|
||||
rgb_console_buffer = new_buffer;
|
||||
vga_console_repaint();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void vga_set_pixel(int x, int y, uint32_t val) {
|
||||
*(uint32_t *) (rgb_fb_addr + x * 4 + rgb_fb_info.pitch * y) = val;
|
||||
}
|
||||
|
||||
void vga_fill_rect(int x1, int y1, int x2, int y2, vga_color_t *color) {
|
||||
void vga_fill_rect(int x1, int y1, int x2, int y2, vga_rgb_color_t *color) {
|
||||
if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return;
|
||||
|
||||
uint32_t val = ((uint32_t) color->red << rgb_fb_info.red_field_position)
|
||||
| ((uint32_t) color->green << rgb_fb_info.green_field_position)
|
||||
| ((uint32_t) color->blue << rgb_fb_info.blue_field_position);
|
||||
| ((uint32_t) color->green << rgb_fb_info.green_field_position)
|
||||
| ((uint32_t) color->blue << rgb_fb_info.blue_field_position);
|
||||
|
||||
int xmin = MAX(MIN(x1, x2), 0);
|
||||
int xmax = MIN(MAX(x1, x2), rgb_fb_info.width);
|
||||
@@ -42,45 +107,96 @@ void vga_fill_rect(int x1, int y1, int x2, int y2, vga_color_t *color) {
|
||||
}
|
||||
}
|
||||
|
||||
void vga_display_image_bgr(int x, int y, BITMAPINFOHEADER *header, uint8_t *image) {
|
||||
void vga_display_image_bgra(int x, int y, bmp_info_header_t *header, uint8_t *image) {
|
||||
if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return;
|
||||
|
||||
int xmax = MIN(x + header->biWidth, rgb_fb_info.width);
|
||||
int ymax = MIN(y + header->biHeight, rgb_fb_info.height);
|
||||
int xmax = MIN(x + header->width, rgb_fb_info.width);
|
||||
int ymax = MIN(y + header->height, rgb_fb_info.height);
|
||||
for (int y1 = y; y1 < ymax; y1++) {
|
||||
for (int x1 = x; x1 < xmax; x1++) {
|
||||
uint8_t *pixel = image + (x1 * y1 * 4); // (header->biHeight - y1)
|
||||
uint32_t val = (uint32_t) *(pixel) << rgb_fb_info.blue_field_position
|
||||
| (uint32_t) *(pixel + 1) << rgb_fb_info.green_field_position
|
||||
| (uint32_t) *(pixel + 2) << rgb_fb_info.red_field_position;
|
||||
vga_set_pixel(x1, y1, val);
|
||||
uint8_t *pixel = image + ((x1 + ((header->height - y1) * header->width)) * 4);
|
||||
vga_set_pixel(x1, y1, (uint32_t) *pixel << rgb_fb_info.blue_field_position
|
||||
| (uint32_t) *(pixel + 1) << rgb_fb_info.green_field_position
|
||||
| (uint32_t) *(pixel + 2) << rgb_fb_info.red_field_position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vga_print_char(char c, int col, int row, char attr) {
|
||||
if (console_fb_addr == NULL) return 0;
|
||||
if (!attr) attr = WHITE_ON_BLACK;
|
||||
static void vga_print_glyph(int offset, char c, vga_rgb_color_t *fg_color, vga_rgb_color_t *bg_color) {
|
||||
if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return;
|
||||
|
||||
/* Error control: print a red 'E' if the coords aren't right */
|
||||
if (col >= MAX_COLS || row >= MAX_ROWS) {
|
||||
console_fb_addr[MAX_COLS * MAX_ROWS - 1] = vga_entry('E', RED_ON_WHITE);
|
||||
return vga_get_offset(col, row);
|
||||
int row = offset / rgb_console_cols;
|
||||
int x = (offset % rgb_console_cols) * rgb_console_font.width;
|
||||
int y = row * rgb_console_font.height;
|
||||
|
||||
uint32_t fg_val = ((uint32_t) fg_color->red << rgb_fb_info.red_field_position)
|
||||
| ((uint32_t) fg_color->green << rgb_fb_info.green_field_position)
|
||||
| ((uint32_t) fg_color->blue << rgb_fb_info.blue_field_position);
|
||||
uint32_t bg_val = ((uint32_t) bg_color->red << rgb_fb_info.red_field_position)
|
||||
| ((uint32_t) bg_color->green << rgb_fb_info.green_field_position)
|
||||
| ((uint32_t) bg_color->blue << rgb_fb_info.blue_field_position);
|
||||
|
||||
int xmax = MIN(x + rgb_console_font.width, rgb_fb_info.width);
|
||||
int ymax = MIN(y + rgb_console_font.height, rgb_fb_info.height);
|
||||
uint8_t *glyph = rgb_console_font_glyphs + (rgb_console_font.bytes_per_glyph * (uint8_t) c);
|
||||
|
||||
for (int y1 = y; y1 < ymax; y1++) {
|
||||
for (int x1 = x; x1 < xmax; x1++) {
|
||||
uint8_t gb = *(glyph + (y1 - y));
|
||||
vga_set_pixel(x1, y1, (gb >> (8 - (x1 - x))) & 1 ? fg_val : bg_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vga_print_char(char c, int offset, char attr) {
|
||||
if (rgb_fb_addr != NULL) {
|
||||
if (rgb_console_font_glyphs == NULL) return 0;
|
||||
if (offset < 0) {
|
||||
offset = rgb_console_offset;
|
||||
} else if (offset >= rgb_console_rows * rgb_console_cols) {
|
||||
return rgb_console_offset;
|
||||
}
|
||||
|
||||
if (c == '\b') {
|
||||
offset--;
|
||||
} else if (c == '\n') {
|
||||
unsigned int row = offset / rgb_console_cols;
|
||||
offset = (row + 1) * rgb_console_cols;
|
||||
} else {
|
||||
vga_rgb_color_t fg_color = {255, 255, 255};
|
||||
vga_rgb_color_t bg_color = {0, 0, 0};
|
||||
|
||||
// FIXME make more dynamic
|
||||
if (attr == RED_ON_BLACK) {
|
||||
fg_color = (vga_rgb_color_t) {255, 0, 0};
|
||||
bg_color = (vga_rgb_color_t) {0, 0, 0};
|
||||
}
|
||||
|
||||
rgb_console_buffer[offset] = (rgb_console_buffer_entry_t) {c, fg_color, bg_color};
|
||||
if (!c) c = ' ';
|
||||
vga_print_glyph(offset++, c, &fg_color, &bg_color);
|
||||
}
|
||||
rgb_console_offset = offset = vga_handle_scrolling(offset);
|
||||
} else if (console_fb_addr != NULL) {
|
||||
if (!attr) attr = WHITE_ON_BLACK;
|
||||
|
||||
if (offset < 0) {
|
||||
offset = vga_get_cursor_offset();
|
||||
} else if (offset >= MAX_ROWS * MAX_COLS) {
|
||||
console_fb_addr[MAX_COLS * MAX_ROWS - 1] = vga_entry('E', RED_ON_WHITE);
|
||||
return vga_get_cursor_offset();
|
||||
}
|
||||
|
||||
if (c == '\b') {
|
||||
offset--;
|
||||
} else if (c == '\n') {
|
||||
offset = vga_get_offset(0, vga_get_offset_row(offset) + 1);
|
||||
} else {
|
||||
console_fb_addr[offset++] = ((uint16_t) attr << 8 | c);
|
||||
}
|
||||
vga_set_cursor_offset(offset = vga_handle_scrolling(offset));
|
||||
}
|
||||
|
||||
int offset;
|
||||
if (col >= 0 && row >= 0) offset = vga_get_offset(col, row);
|
||||
else offset = vga_get_cursor_offset();
|
||||
|
||||
if (c == '\b') {
|
||||
offset--;
|
||||
} else if (c == '\n') {
|
||||
row = vga_get_offset_row(offset);
|
||||
offset = vga_get_offset(0, row + 1);
|
||||
} else {
|
||||
console_fb_addr[offset++] = ((uint16_t) attr << 8 | c);
|
||||
}
|
||||
vga_set_cursor_offset(offset = vga_handle_scrolling(offset));
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -102,28 +218,52 @@ void vga_set_cursor_offset(int offset) {
|
||||
}
|
||||
|
||||
void vga_clear_screen() {
|
||||
if (console_fb_addr == NULL) return;
|
||||
memset((void *) console_fb_addr, 0, MAX_COLS * MAX_ROWS * sizeof(*console_fb_addr));
|
||||
vga_set_cursor_offset(vga_get_offset(0, 0));
|
||||
if (console_fb_addr != NULL) {
|
||||
memset(console_fb_addr, 0, MAX_COLS * MAX_ROWS * sizeof(*console_fb_addr));
|
||||
vga_set_cursor_offset(vga_get_offset(0, 0));
|
||||
} else if (rgb_fb_addr != NULL) {
|
||||
vga_fill_rect(0, 0, rgb_fb_info.width, rgb_fb_info.height, &(vga_rgb_color_t) {0, 0, 0});
|
||||
memset(rgb_console_buffer, 0, rgb_console_rows * rgb_console_cols);
|
||||
rgb_console_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance the text cursor, scrolling the video buffer if necessary. */
|
||||
int vga_handle_scrolling(int cursor_offset) {
|
||||
if (console_fb_addr == NULL) return 0;
|
||||
if (cursor_offset < MAX_ROWS * MAX_COLS)
|
||||
return cursor_offset;
|
||||
static void vga_console_repaint() {
|
||||
for (size_t i = 0; i < rgb_console_rows * rgb_console_cols; ++i) {
|
||||
rgb_console_buffer_entry_t *entry = &rgb_console_buffer[i];
|
||||
char c = entry->c;
|
||||
if (!c) c = ' '; // FIXME improve
|
||||
vga_print_glyph(i, c, &entry->fg_color, &entry->bg_color);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shuffle the rows back one. */
|
||||
for (int i = 1; i < MAX_ROWS; i++) {
|
||||
memcpy((void *) (console_fb_addr + vga_get_offset(0, i - 1)),
|
||||
(void *) (console_fb_addr + vga_get_offset(0, i)),
|
||||
MAX_COLS * sizeof(*console_fb_addr));
|
||||
// Advance the text cursor, scrolling the video buffer if necessary.
|
||||
int vga_handle_scrolling(int cursor_offset) {
|
||||
if (console_fb_addr != NULL) {
|
||||
if (cursor_offset < MAX_ROWS * MAX_COLS)
|
||||
return cursor_offset;
|
||||
|
||||
for (int i = 1; i < MAX_ROWS; i++) {
|
||||
memcpy(console_fb_addr + vga_get_offset(0, i - 1),
|
||||
console_fb_addr + vga_get_offset(0, i),
|
||||
MAX_COLS * sizeof(*console_fb_addr));
|
||||
}
|
||||
|
||||
memset(console_fb_addr + vga_get_offset(0, MAX_ROWS - 1),
|
||||
0, MAX_COLS * sizeof(*console_fb_addr));
|
||||
|
||||
cursor_offset -= MAX_COLS;
|
||||
} else if (rgb_fb_addr != NULL) {
|
||||
if (cursor_offset < rgb_console_rows * rgb_console_cols)
|
||||
return cursor_offset;
|
||||
|
||||
size_t end_offset = (rgb_console_rows - 1) * rgb_console_cols;
|
||||
memmove(rgb_console_buffer, rgb_console_buffer + rgb_console_cols,
|
||||
end_offset * sizeof(rgb_console_buffer_entry_t));
|
||||
memset(rgb_console_buffer + end_offset, 0, rgb_console_cols * sizeof(rgb_console_buffer_entry_t));
|
||||
cursor_offset -= rgb_console_cols;
|
||||
vga_console_repaint();
|
||||
}
|
||||
|
||||
/* Blank the last line by setting all bytes to 0 */
|
||||
memset((void *) (console_fb_addr + vga_get_offset(0, MAX_ROWS - 1)),
|
||||
0, MAX_COLS * sizeof(*console_fb_addr));
|
||||
|
||||
cursor_offset -= MAX_COLS;
|
||||
return cursor_offset;
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
#define VGA_FB_TYPE_RGB 1
|
||||
#define VGA_FB_TYPE_EGA_TEXT 2
|
||||
|
||||
struct framebuffer_info {
|
||||
typedef struct framebuffer_info {
|
||||
uint32_t pitch;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
@@ -27,25 +27,25 @@ struct framebuffer_info {
|
||||
uint8_t green_mask_size;
|
||||
uint8_t blue_field_position;
|
||||
uint8_t blue_mask_size;
|
||||
};
|
||||
typedef struct framebuffer_info framebuffer_info_t;
|
||||
} framebuffer_info_t;
|
||||
|
||||
struct vga_color {
|
||||
typedef struct vga_rgb_color {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
typedef struct vga_color vga_color_t;
|
||||
} vga_rgb_color_t;
|
||||
|
||||
void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info);
|
||||
|
||||
void vga_fill_rect(int x1, int y1, int x2, int y2, vga_color_t *color);
|
||||
int vga_load_font(const char *filename);
|
||||
|
||||
void vga_display_image_bgr(int x, int y, BITMAPINFOHEADER *header, uint8_t *image);
|
||||
void vga_fill_rect(int x1, int y1, int x2, int y2, vga_rgb_color_t *color);
|
||||
|
||||
void vga_display_image_bgra(int x, int y, bmp_info_header_t *header, uint8_t *image);
|
||||
|
||||
// --- Console
|
||||
|
||||
int vga_print_char(char c, int col, int row, char attr);
|
||||
int vga_print_char(char c, int offset, char attr);
|
||||
|
||||
int vga_handle_scrolling(int cursor_offset);
|
||||
|
||||
|
||||
+7
-12
@@ -8,13 +8,12 @@
|
||||
#include "drivers/pci.h"
|
||||
#include "drivers/ata.h"
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
#ifdef ENABLE_DWARF
|
||||
#include "dwarf.h"
|
||||
#include "bmp.h"
|
||||
#include "drivers/vga.h"
|
||||
#include "arch/x86/mmu.h"
|
||||
|
||||
#ifdef ENABLE_DWARF
|
||||
#include "dwarf.h"
|
||||
#endif
|
||||
|
||||
#include <common.h>
|
||||
@@ -51,18 +50,14 @@ void kernel_main(uint32_t multiboot_magic, void *multiboot_info) {
|
||||
// dwarf_find_debug_info();
|
||||
#endif
|
||||
|
||||
console_set_vga_enabled(vga_enabled);
|
||||
if (vga_enabled && !vga_load_font("assets/default8x16.psfu")) {
|
||||
console_set_vga_enabled(vga_enabled);
|
||||
}
|
||||
clear_screen();
|
||||
|
||||
// FIXME add to malloc
|
||||
page_table_set(0x400000, 0xC0400000, 0x83);
|
||||
BITMAPINFOHEADER bmpHeader;
|
||||
uint8_t *bmp = LoadBitmapFile("assets/test.bmp", &bmpHeader);
|
||||
if (bmp == NULL) {
|
||||
fprintf(stderr, "Failed to read bitmap");
|
||||
} else {
|
||||
printf("Displaying image...\n");
|
||||
vga_display_image_bgr(0, 0, &bmpHeader, bmp);
|
||||
}
|
||||
page_table_set(0x800000, 0xC0800000, 0x83);
|
||||
|
||||
#ifdef KDEBUG
|
||||
kprint("Initializing timer...\n");
|
||||
|
||||
+1
-7
@@ -123,13 +123,7 @@ void multiboot_init(uint32_t magic, void *info_ptr) {
|
||||
break;
|
||||
|
||||
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
|
||||
vga_fill_rect(0, 0, 100, 100, &(vga_color_t) {255, 255, 255});
|
||||
vga_fill_rect(100, 0, 200, 100, &(vga_color_t) {255, 0, 0});
|
||||
vga_fill_rect(200, 0, 300, 100, &(vga_color_t) {0, 255, 0});
|
||||
vga_fill_rect(300, 0, 400, 100, &(vga_color_t) {0, 0, 255});
|
||||
vga_fill_rect(0, 100, 100, 200, &(vga_color_t) {255, 0, 0});
|
||||
vga_fill_rect(100, 100, 200, 200, &(vga_color_t) {0, 255, 0});
|
||||
vga_fill_rect(200, 100, 300, 200, &(vga_color_t) {255, 255, 255});
|
||||
console_set_vga_enabled(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "psf.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
|
||||
void *psf_read_font(const char *filename, psf_font_t *header) {
|
||||
FILE *font_file;
|
||||
void *glyphs_data;
|
||||
|
||||
font_file = fopen(filename, "r");
|
||||
if (ferror(font_file))
|
||||
return NULL;
|
||||
|
||||
fread(header, sizeof(psf_font_t), 1, font_file);
|
||||
if (ferror(font_file) || header->magic != PSF_FONT_MAGIC) {
|
||||
fclose(font_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(font_file, header->header_size, SEEK_SET);
|
||||
|
||||
uint32_t glyphs_size = header->bytes_per_glyph * header->num_glyph;
|
||||
glyphs_data = malloc(glyphs_size);
|
||||
if (glyphs_data == NULL) {
|
||||
errno = ENOMEM;
|
||||
free(glyphs_data);
|
||||
fclose(font_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fread(glyphs_data, glyphs_size, 1, font_file);
|
||||
if (ferror(font_file)) {
|
||||
fclose(font_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(font_file);
|
||||
return glyphs_data;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PSF_FONT_MAGIC 0x864ab572
|
||||
|
||||
typedef struct psf_font {
|
||||
uint32_t magic; // magic
|
||||
uint32_t version; // zero
|
||||
uint32_t header_size; // offset of bitmaps in file, 32
|
||||
uint32_t flags; // 0 if there's no unicode table
|
||||
uint32_t num_glyph; // number of glyphs
|
||||
uint32_t bytes_per_glyph; // size of each glyph
|
||||
uint32_t height; // height in pixels
|
||||
uint32_t width; // width in pixels
|
||||
} psf_font_t;
|
||||
|
||||
void *psf_read_font(const char *filename, psf_font_t *header);
|
||||
+39
-7
@@ -1,24 +1,26 @@
|
||||
#include "shell.h"
|
||||
#include "bmp.h"
|
||||
#include "console.h"
|
||||
#include "drivers/acpi.h"
|
||||
#include "drivers/ata.h"
|
||||
#include "drivers/keyboard.h"
|
||||
#include "drivers/ports.h"
|
||||
#include "drivers/serial.h"
|
||||
#include "tests/tests.h"
|
||||
#include "drivers/pci.h"
|
||||
#include "drivers/pci_registry.h"
|
||||
#include "drivers/ata.h"
|
||||
#include "drivers/ports.h"
|
||||
#include "drivers/serial.h"
|
||||
#include "drivers/vga.h"
|
||||
#include "elf.h"
|
||||
#include "tests/tests.h"
|
||||
|
||||
// FIXME
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <vector.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <vector.h>
|
||||
|
||||
#define KEY_BUFFER_INITIAL_SIZE 0x100
|
||||
static char *key_buffer;
|
||||
@@ -220,6 +222,32 @@ static int command_exec(const char *path) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int command_display(const char* path) {
|
||||
if (!_fs_mounted) return 255;
|
||||
|
||||
char path_buf[512];
|
||||
path_append(path_buf, curr_path, path, sizeof(path_buf));
|
||||
|
||||
bmp_info_header_t header;
|
||||
uint8_t *bmp = bmp_read_image(path_buf, &header);
|
||||
if (bmp == NULL) {
|
||||
fprintf(stderr, "Failed to read bitmap");
|
||||
return 1;
|
||||
} else {
|
||||
vga_display_image_bgra(0, 0, &header, bmp);
|
||||
}
|
||||
free(bmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int command_font(const char *path) {
|
||||
if (!_fs_mounted) return 255;
|
||||
char path_buf[512];
|
||||
path_append(path_buf, curr_path, path, sizeof(path_buf));
|
||||
return vga_load_font(path_buf) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void print_prompt(int ret) {
|
||||
if (_fs_mounted) {
|
||||
printf("%d %s # ", ret, curr_path);
|
||||
@@ -295,6 +323,10 @@ static void shell_callback(char *input) {
|
||||
ret = command_objdump(input + 8);
|
||||
} else if (strncmp(input, "cat ", 4) == 0) {
|
||||
ret = command_cat(input + 4);
|
||||
} else if (strncmp(input, "display ", 8) == 0) {
|
||||
ret = command_display(input + 8);
|
||||
} else if (strncmp(input, "font ", 5) == 0) {
|
||||
ret = command_font(input + 5);
|
||||
} else if (strncmp(input, "./", 2) == 0) {
|
||||
ret = command_exec(input + 2);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user