diff options
author | Alex Auvolat <alex@adnab.me> | 2015-03-11 14:35:54 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2015-03-11 14:35:54 +0100 |
commit | 5e9251bd48acafff575ed1c740e4dc05ec175508 (patch) | |
tree | 00f95aafd4e0399bcb1858f24b7e79b06a216f30 /src | |
parent | 052ca1dc143b1df2800f9c4e43daf80c96fb472e (diff) | |
download | kogata-5e9251bd48acafff575ed1c740e4dc05ec175508.tar.gz kogata-5e9251bd48acafff575ed1c740e4dc05ec175508.zip |
Add simple drawing code & font loading.
Diffstat (limited to 'src')
-rw-r--r-- | src/common/include/proto/fb.h | 14 | ||||
-rw-r--r-- | src/kernel/dev/vesa.c | 31 | ||||
-rw-r--r-- | src/lib/include/draw.h | 62 | ||||
-rw-r--r-- | src/lib/include/proto/font_file.h | 14 | ||||
-rw-r--r-- | src/lib/libkogata/Makefile | 2 | ||||
-rw-r--r-- | src/lib/libkogata/draw.c | 317 | ||||
-rw-r--r-- | src/sysbin/giosrv/main.c | 3 | ||||
-rw-r--r-- | src/sysbin/login/main.c | 42 |
8 files changed, 453 insertions, 32 deletions
diff --git a/src/common/include/proto/fb.h b/src/common/include/proto/fb.h index dab9643..710ecb1 100644 --- a/src/common/include/proto/fb.h +++ b/src/common/include/proto/fb.h @@ -5,12 +5,14 @@ #include <stdint.h> #include <stddef.h> -#define FB_MM_RGB16 1 // 2 bytes (16 bits) per pixel, blue 0-4, green 5-9, red 10-14 -#define FB_MM_BGR16 2 // 2 bytes (16 bits) per pixel, red 0-4, green 5-9, blue 10-14 -#define FB_MM_RGB24 3 // 3 bytes (24 bits) per pixel, blue 0-7, green 8-15, red 16-23 -#define FB_MM_BGR24 4 // 3 bytes (24 bits) per pixel, red 0-7, green 8-15, blue 16-23 -#define FB_MM_RGB32 5 // 4 bytes (32 bits) per pixel, blue 0-7, green 8-15, red 16-23 -#define FB_MM_BGR32 6 // 4 bytes (32 bits) per pixel, red 0-7, green 8-15, blue 16-23 +#define FB_MM_RGB15 1 // 15 bits per pixel, blue 0-4, green 5-9, red 10-14 +#define FB_MM_BGR15 2 // 15 bits per pixel, red 0-4, green 5-9, blue 10-14 +#define FB_MM_RGB16 3 // 2 bytes (16 bits) per pixel, blue 0-4, green 5-9, red 10-14 +#define FB_MM_BGR16 4 // 2 bytes (16 bits) per pixel, red 0-4, green 5-9, blue 10-14 +#define FB_MM_RGB24 5 // 3 bytes (24 bits) per pixel, blue 0-7, green 8-15, red 16-23 +#define FB_MM_BGR24 6 // 3 bytes (24 bits) per pixel, red 0-7, green 8-15, blue 16-23 +#define FB_MM_RGB32 7 // 4 bytes (32 bits) per pixel, blue 0-7, green 8-15, red 16-23 +#define FB_MM_BGR32 8 // 4 bytes (32 bits) per pixel, red 0-7, green 8-15, blue 16-23 #define FB_MM_GREY8 10 // 1 byte (8 bits) per pixel greyscale typedef struct { diff --git a/src/kernel/dev/vesa.c b/src/kernel/dev/vesa.c index a039d01..f77b230 100644 --- a/src/kernel/dev/vesa.c +++ b/src/kernel/dev/vesa.c @@ -243,9 +243,9 @@ fs_node_ops_t vesa_fs_ops = { static struct fb_memory_model { int bpp, rp, gp, bp, rs, gs, bs, mm; } fb_memory_models[8] = { - { 15, 10, 5, 0, 5, 5, 5, FB_MM_RGB16 }, + { 15, 10, 5, 0, 5, 5, 5, FB_MM_RGB15 }, + { 15, 0, 5, 10, 5, 5, 5, FB_MM_BGR15 }, { 16, 10, 5, 0, 5, 5, 5, FB_MM_RGB16 }, - { 15, 0, 5, 10, 5, 5, 5, FB_MM_BGR16 }, { 16, 0, 5, 10, 5, 5, 5, FB_MM_BGR16 }, { 24, 16, 8, 0, 8, 8, 8, FB_MM_RGB24 }, { 24, 0, 8, 16, 8, 8, 8, FB_MM_BGR24 }, @@ -443,12 +443,29 @@ void vesa_clear(vesa_driver_t *d) { int tly = (mode->info.height / 2) - (kogata_logo.height / 2); int tlx = (mode->info.width / 2) - (kogata_logo.width / 2); - int mbpp = (mode->info.bpp / 8); - for (unsigned l = 0; l < kogata_logo.height; l++) { - memcpy(region + (tly + l) * mode->info.pitch + tlx * mbpp, - buffer + kogata_logo.width * l * kogata_logo.bytes_per_pixel, - kogata_logo.width * kogata_logo.bytes_per_pixel); + if (mode->info.bpp == 24) { + for (unsigned l = 0; l < kogata_logo.height; l++) { + memcpy(region + (tly + l) * mode->info.pitch + tlx * 3, + buffer + kogata_logo.width * l * kogata_logo.bytes_per_pixel, + kogata_logo.width * kogata_logo.bytes_per_pixel); + } + } else if (mode->info.bpp == 32) { + for (unsigned l = 0; l < kogata_logo.height; l++) { + uint32_t *p = (uint32_t*)(region + (tly + l) * mode->info.pitch + tlx * 4); + uint8_t *r = (uint8_t*)(buffer + kogata_logo.width * l * kogata_logo.bytes_per_pixel); + for (unsigned c = 0; c < kogata_logo.width; c++) { + p[c] = r[3*c] | (r[3*c+1] << 8) | (r[3*c+2] <<16); + } + } + } else if (mode->info.bpp == 15 || mode->info.bpp == 16) { + for (unsigned l = 0; l < kogata_logo.height; l++) { + uint16_t *p = (uint16_t*)(region + (tly + l) * mode->info.pitch + tlx * 2); + uint8_t *r = (uint8_t*)(buffer + kogata_logo.width * l * kogata_logo.bytes_per_pixel); + for (unsigned c = 0; c < kogata_logo.width; c++) { + p[c] = (r[3*c]/8) | ((r[3*c+1]/8) << 5) | ((r[3*c+2]/8) <<10); + } + } } end: diff --git a/src/lib/include/draw.h b/src/lib/include/draw.h new file mode 100644 index 0000000..893c5a3 --- /dev/null +++ b/src/lib/include/draw.h @@ -0,0 +1,62 @@ +#pragma once + +#include <syscall.h> +#include <proto/fb.h> + +// ---- Generic drawing functions + +// ---- Data structures + +typedef struct { + fb_info_t geom; + + fd_t fd; + uint8_t* data; +} fb_t; + +typedef struct font font_t; + +typedef uint32_t color_t; // a color is always linked to a FB on which it is to be applied + +// ---- Buffer creation + +fb_t *g_fb_from_file(fd_t file, fb_info_t *geom); +fb_t *g_fb_from_mem(uint8_t* region, fb_info_t *geom); + +void g_delete_fb(fb_t *fb); + +// ---- Color manipulation + +color_t g_color_rgb(fb_t *f, uint8_t r, uint8_t g, uint8_t b); + +// ---- Drawing primitives + +void g_plot(fb_t *fb, int x, int y, color_t c); + +void g_hline(fb_t *fb, int x, int y, int w, color_t c); // horizontal line +void g_vline(fb_t *fb, int x, int y, int h, color_t c); // vertical line +void g_line(fb_t *fb, int x1, int y1, int x2, int y2, color_t c); + +void g_rect(fb_t *fb, int x, int y, int w, int h, color_t c); +void g_fillrect(fb_t *fb, int x, int y, int w, int h, color_t c); +void g_rect_r(fb_t *fb, fb_region_t reg, color_t c); +void g_fillrect_r(fb_t *fb, fb_region_t reg, color_t c); + +void g_circle(fb_t *fb, int cx, int cy, int r, color_t c); +void g_fillcircle(fb_t *fb, int cx, int cy, int r, color_t c); + +void g_blit(fb_t *dst, int x, int y, fb_t *src); +void g_blit_region(fb_t *dst, int x, int y, fb_t *src, fb_region_t reg); + +// ---- Text manipulation + +font_t *g_load_font(const char* fontname); +void g_free_font(font_t *f); + +int g_text_width(font_t *f, const char* text); +int g_text_height(font_t *f, const char* text); + +void g_write(fb_t *fb, int x, int y, const char* text, font_t *font, color_t c); + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/include/proto/font_file.h b/src/lib/include/proto/font_file.h new file mode 100644 index 0000000..e57c0ab --- /dev/null +++ b/src/lib/include/proto/font_file.h @@ -0,0 +1,14 @@ +#pragma once + +#include <stdint.h> +#include <stddef.h> + +#define ASCII_BITMAP_FONT_MAGIC 0xD184C274 + +typedef struct { + uint32_t magic; + uint16_t cw, ch; + uint32_t nchars; +} ascii_bitmap_font_header; + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libkogata/Makefile b/src/lib/libkogata/Makefile index 48c6bc2..a8df419 100644 --- a/src/lib/libkogata/Makefile +++ b/src/lib/libkogata/Makefile @@ -1,5 +1,5 @@ OBJ = start.o malloc.o debug.o syscall.o user_region.o \ - mainloop.o gip.o + mainloop.o gip.o draw.o LIB = ../../common/libkogata/libkogata.lib ../../common/libalgo/libalgo.lib ../../common/libc/libc.lib diff --git a/src/lib/libkogata/draw.c b/src/lib/libkogata/draw.c new file mode 100644 index 0000000..22ad8ba --- /dev/null +++ b/src/lib/libkogata/draw.c @@ -0,0 +1,317 @@ +#include <syscall.h> +#include <malloc.h> +#include <string.h> +#include <printf.h> + +#include <proto/font_file.h> + +#include <user_region.h> + +#include <draw.h> + +fb_t *g_fb_from_file(fd_t file, fb_info_t *geom) { + fb_t *ret = (fb_t*)malloc(sizeof(fb_t)); + if (ret == 0) return 0; + + memcpy(&ret->geom, geom, sizeof(fb_info_t)); + ret->fd = file; + + ret->data = (uint8_t*)region_alloc(geom->height * geom->pitch, "Framebuffer"); + if (ret->data == 0) goto error; + + bool map_ok = mmap_file(file, 0, ret->data, geom->height * geom->pitch, MM_READ | MM_WRITE); + if (!map_ok) goto error; + + return ret; + +error: + if (ret && ret->data) region_free(ret->data); + if (ret) free(ret); + return 0; +} + +fb_t *g_fb_from_mem(uint8_t* data, fb_info_t *geom) { + fb_t *ret = (fb_t*)malloc(sizeof(fb_t)); + if (ret == 0) return 0; + + memcpy(&ret->geom, geom, sizeof(fb_info_t)); + ret->fd = 0; + ret->data = data; + + return ret; +} + +void g_delete_fb(fb_t *fb) { + if (fb->fd != 0) { + munmap(fb->data); + region_free(fb->data); + } + free(fb); +} + +// ---- Color management + +color_t g_color_rgb(fb_t *f, uint8_t r, uint8_t g, uint8_t b) { + int m = f->geom.memory_model; + if (m == FB_MM_RGB24 || m == FB_MM_RGB32) return (r << 16) | (g << 8) | b; + if (m == FB_MM_BGR24 || m == FB_MM_BGR32) return (b << 16) | (g << 8) | r; + if (m == FB_MM_GREY8) return ((r + g + b) / 3) & 0xFF; + if (m == FB_MM_RGB16 || m == FB_MM_RGB15) return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); + if (m == FB_MM_BGR16 || m == FB_MM_BGR15) return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3); + return 0; // unknown? +} + +// ---- Plot + +inline void g_plot24(uint8_t* p, color_t c) { + p[0] = c & 0xFF; + p[1] = (c >> 8) & 0xFF; + p[2] = (c >> 16) & 0xFF; +} + +void g_plot(fb_t *fb, int x, int y, color_t c) { + if (fb->geom.bpp == 8) { + fb->data[y * fb->geom.pitch + x] = (c & 0xFF); + } else if (fb->geom.bpp == 15 || fb->geom.bpp == 16) { + uint16_t *p = (uint16_t*)(fb->data + y * fb->geom.pitch + 2 * x); + *p = (c & 0xFFFF); + } else if (fb->geom.bpp == 24) { + g_plot24(fb->data + y * fb->geom.pitch + 3 * x, c); + } else if (fb->geom.bpp == 32) { + uint32_t *p = (uint32_t*)(fb->data + y * fb->geom.pitch + 4 * x); + *p = c; + } +} + +void g_hline(fb_t *fb, int x, int y, int w, color_t c) { + if (fb->geom.bpp == 8) { + for (int u = x; u < x + w; u++) { + fb->data[y * fb->geom.pitch + u] = (c & 0xFF); + } + } else if (fb->geom.bpp == 15 || fb->geom.bpp == 15) { + for (int u = x; u < x + w; u++) { + uint16_t *p = (uint16_t*)(fb->data + y * fb->geom.pitch + 2 * u); + *p = (c & 0xFFFF); + } + } else if (fb->geom.bpp == 24) { + for (int u = x; u < x + w; u++) { + g_plot24(fb->data + y * fb->geom.pitch + 3 * u, c); + } + } else if (fb->geom.bpp == 32) { + for (int u = x; u < x + w; u++) { + uint32_t *p = (uint32_t*)(fb->data + y * fb->geom.pitch + 4 * u); + *p = c; + } + } +} + +void g_vline(fb_t *fb, int x, int y, int h, color_t c) { + if (fb->geom.bpp == 8) { + for (int v = y; v < y + h; v++) { + fb->data[v * fb->geom.pitch + x] = (c & 0xFF); + } + } else if (fb->geom.bpp == 15 || fb->geom.bpp == 15) { + for (int v = y; v < y + h; v++) { + uint16_t *p = (uint16_t*)(fb->data + v * fb->geom.pitch + 2 * x); + *p = (c & 0xFFFF); + } + } else if (fb->geom.bpp == 24) { + for (int v = y; v < y + h; v++) { + g_plot24(fb->data + v * fb->geom.pitch + 3 * x, c); + } + } else if (fb->geom.bpp == 32) { + for (int v = y; v < y + h; v++) { + uint32_t *p = (uint32_t*)(fb->data + v * fb->geom.pitch + 4 * x); + *p = c; + } + } +} + +void g_line(fb_t *fb, int x1, int y1, int x2, int y2, color_t c) { + // TODO +} + +void g_rect(fb_t *fb, int x, int y, int w, int h, color_t c) { + g_hline(fb, x, y, w, c); + g_hline(fb, x, y+h-1, w, c); + g_vline(fb, x, y, h, c); + g_vline(fb, x+w-1, y, h, c); +} + +void g_fillrect(fb_t *fb, int x, int y, int w, int h, color_t c) { + if (fb->geom.bpp == 8) { + for (int v = y; v < y + h; v++) { + for (int u = x; u < x + w; u++) { + fb->data[v * fb->geom.pitch + u] = (c & 0xFF); + } + } + } else if (fb->geom.bpp == 15 || fb->geom.bpp == 15) { + for (int v = y; v < y + h; v++) { + for (int u = x; u < x + w; u++) { + uint16_t *p = (uint16_t*)(fb->data + v * fb->geom.pitch + 2 * u); + *p = (c & 0xFFFF); + } + } + } else if (fb->geom.bpp == 24) { + for (int v = y; v < y + h; v++) { + for (int u = x; u < x + w; u++) { + g_plot24(fb->data + v * fb->geom.pitch + 3 * u, c); + } + } + } else if (fb->geom.bpp == 32) { + for (int v = y; v < y + h; v++) { + for (int u = x; u < x + w; u++) { + uint32_t *p = (uint32_t*)(fb->data + v * fb->geom.pitch + 4 * u); + *p = c; + } + } + } +} + +void g_rect_r(fb_t *fb, fb_region_t reg, color_t c) { + g_rect(fb, reg.x, reg.y, reg.w, reg.h, c); +} + +void g_fillrect_r(fb_t *fb, fb_region_t reg, color_t c) { + g_fillrect(fb, reg.x, reg.y, reg.w, reg.h, c); +} + +void g_circle(fb_t *fb, int cx, int cy, int r, color_t c) { + // TODO +} + +void g_fillcircle(fb_t *fb, int cx, int cy, int r, color_t c) { + // TODO +} + +void g_blit(fb_t *dst, int x, int y, fb_t *src) { + fb_region_t r; + + r.x = 0; + r.y = 0; + r.w = src->geom.width; + r.h = src->geom.height; + + g_blit_region(dst, x, y, src, r); +} + +void g_blit_region(fb_t *dst, int x, int y, fb_t *src, fb_region_t reg) { + if (src->geom.memory_model == dst->geom.memory_model) { + for (uint32_t i = 0; i < reg.h; i++) { + memcpy( + dst->data + (y + i) * dst->geom.pitch + x * (dst->geom.bpp / 8), + src->data + (reg.y + i) * src->geom.pitch + reg.x * (src->geom.bpp / 8), + reg.w * (src->geom.bpp / 8)); + } + } else { + dbg_printf("Unsupported blit between different memory models.\n"); + } +} + +// ---- Text manipulation + +#define FONT_ASCII_BITMAP 1 +// more font types to come + +typedef struct font { + int type; + union { + struct { + uint8_t* data; + uint8_t cw, ch; // width, height of a character + uint32_t nchars; + } ascii_bitmap; + }; +} font_t; + +font_t *g_load_ascii_bitmap_font(fd_t f) { + font_t *font = 0; + + ascii_bitmap_font_header h; + + size_t s = read(f, 0, sizeof(h), (char*)&h); + if (s != sizeof(h)) goto error; + + if (h.magic != ASCII_BITMAP_FONT_MAGIC) goto error; + if (h.cw != 8) goto error; + + font = malloc(sizeof(font_t)); + if (font == 0) goto error; + memset(font, 0, sizeof(font_t)); + + + font->type = FONT_ASCII_BITMAP; + font->ascii_bitmap.cw = h.cw; + font->ascii_bitmap.ch = h.ch; + font->ascii_bitmap.nchars = h.nchars; + + + font->ascii_bitmap.data = (uint8_t*)malloc(h.ch * h.nchars); + if (font->ascii_bitmap.data == 0) goto error; + + size_t rd = read(f, sizeof(h), h.ch * h.nchars, (char*)font->ascii_bitmap.data); + if (rd != h.ch * h.nchars) goto error; + + return font; + +error: + if (font && font->ascii_bitmap.data) free(font->ascii_bitmap.data); + if (font) free(font); + close(f); + return 0; +} + +font_t *g_load_font(const char* fontname) { + char buf[128]; + + snprintf(buf, 128, "sys:/fonts/%s.bf", fontname); + fd_t f = open(buf, FM_READ); + if (f != 0) return g_load_ascii_bitmap_font(f); + + return 0; +} + +void g_free_font(font_t *f) { + if (f->type == FONT_ASCII_BITMAP) { + free(f->ascii_bitmap.data); + } + + free(f); +} + +int g_text_width(font_t *font, const char* text) { + if (font->type == FONT_ASCII_BITMAP) { + return font->ascii_bitmap.cw * strlen(text); + } + return 0; +} + +int g_text_height(font_t *font, const char* text) { + if (font->type == FONT_ASCII_BITMAP) { + return font->ascii_bitmap.ch; + } + return 0; +} + +void g_write(fb_t *fb, int x, int y, const char* text, font_t *font, color_t c) { + if (font->type == FONT_ASCII_BITMAP) { + while (*text != 0) { + uint8_t id = (uint8_t)*text; + if (id < font->ascii_bitmap.nchars) { + uint8_t *d = font->ascii_bitmap.data + (id * font->ascii_bitmap.ch); + for (int r = 0; r < font->ascii_bitmap.ch; r++) { + for (int j = 0; j < 8; j++) { + if (d[r] & (0x80 >> j)) { + g_plot(fb, x + j, y + r, c); + } + } + } + } + text++; + x += font->ascii_bitmap.cw; + } + } +} + + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/sysbin/giosrv/main.c b/src/sysbin/giosrv/main.c index fcb9360..b38d1c7 100644 --- a/src/sysbin/giosrv/main.c +++ b/src/sysbin/giosrv/main.c @@ -103,14 +103,17 @@ void disable_features(gip_handler_t *h, gip_msg_header *p) { void query_mode(gip_handler_t *h, gip_msg_header *p) { // TODO + gip_reply_fail(h, p); } void set_mode(gip_handler_t *h, gip_msg_header *p) { // TODO + gip_reply_fail(h, p); } void unknown_msg(gip_handler_t *h, gip_msg_header *p) { // TODO + gip_reply_fail(h, p); } void fd_error(gip_handler_t *h) { diff --git a/src/sysbin/login/main.c b/src/sysbin/login/main.c index eac19e7..294ad76 100644 --- a/src/sysbin/login/main.c +++ b/src/sysbin/login/main.c @@ -4,14 +4,12 @@ #include <debug.h> #include <gip.h> +#include <draw.h> typedef struct { fb_info_t mode; - - size_t fb_size; - void* map; - fd_t fd; + fb_t *fb; uint32_t sv_features, cl_features; } loginc_t; @@ -63,10 +61,13 @@ void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) loginc_t *c = (loginc_t*)s->data; - if (c->fd != 0) close(c->fd); - if (c->map != 0) { - munmap(c->map); - region_free(c->map); + if (c->fb != 0) { + g_delete_fb(c->fb); + c->fb = 0; + } + if (c->fd != 0) { + close(c->fd); + c->fd = 0; } c->fd = use_token(&m->tok); @@ -76,19 +77,24 @@ void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) dbg_printf("[login] Got buffer on FD %d, %dx%dx%d\n", c->fd, c->mode.width, c->mode.height, c->mode.bpp); - c->fb_size = c->mode.pitch * c->mode.height; - - c->map = region_alloc(c->fb_size, "Framebuffer"); - if (c->map != 0) { - bool ok = mmap_file(c->fd, 0, c->map, c->fb_size, MM_READ | MM_WRITE); - if (ok) { - memset(c->map, 0, c->fb_size); + c->fb = g_fb_from_file(c->fd, &m->geom); + if (c->fb != 0) { + color_t black = g_color_rgb(c->fb, 0, 0, 0); + color_t grey = g_color_rgb(c->fb, 128, 128, 128); + g_fillrect(c->fb, 0, 0, m->geom.width, m->geom.height, black); + g_fillrect(c->fb, 50, 50, 50, 50, grey); + + font_t *f = g_load_font("default"); + if (f != 0) { + g_write(c->fb, 50, 100, "Hello, world!", f, grey); + g_free_font(f); } else { - dbg_printf("[login] Could not mmap buffer.\n"); - region_free(c->map); - c->map = 0; + dbg_printf("Could not load font 'default'\n"); } + } else { + dbg_printf("Could not open framebuffer file %d\n", c->fd); } + } } |