From d72aae7bf91f0be187fd8e631a736a1bd3c4f1a5 Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 14 Oct 2024 23:08:21 +0200 Subject: [PATCH] Mon 14 Oct 23:06:38 CEST 2024 --- kernel/graphics.c | 421 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100644 kernel/graphics.c diff --git a/kernel/graphics.c b/kernel/graphics.c new file mode 100644 index 0000000..c900cc5 --- /dev/null +++ b/kernel/graphics.c @@ -0,0 +1,421 @@ +/* +Copyright (C) 2016-2019 The University of Notre Dame +This software is distributed under the GNU General Public License. +See the file LICENSE for details. +*/ + +#include "graphics.h" +#include "kernel/types.h" +#include "kernel/error.h" +#include "ioports.h" +#include "font.h" +#include "string.h" +#include "kmalloc.h" +#include "bitmap.h" +#include "string.h" +#include "process.h" + +#define FACTOR 256 + +struct graphics_clip { + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; +}; + +struct graphics { + struct bitmap *bitmap; + struct graphics_color fgcolor; + struct graphics_color bgcolor; + struct graphics_clip clip; + struct graphics *parent; + int refcount; +}; + +static struct graphics_color color_black = { 0, 0, 0, 0 }; +static struct graphics_color color_white = { 255, 255, 255, 0 }; + +struct graphics graphics_root; + +struct graphics *graphics_create_root() +{ + struct graphics *g = &graphics_root; + g->bitmap = bitmap_create_root(); + g->fgcolor = color_white; + g->bgcolor = color_black; + g->clip.x = 0; + g->clip.y = 0; + g->clip.w = g->bitmap->width; + g->clip.h = g->bitmap->height; + g->parent = 0; + g->refcount = 1; + return g; +} + +struct graphics *graphics_create(struct graphics *parent ) +{ + struct graphics *g = kmalloc(sizeof(*g)); + if(!g) return 0; + + memcpy(g, parent, sizeof(*g)); + + g->parent = graphics_addref(parent); + g->refcount = 1; + + return g; +} + +struct graphics *graphics_addref( struct graphics *g ) +{ + g->refcount++; + return g; +} + +void graphics_delete( struct graphics *g ) +{ + if(!g) return; + + /* Cannot delete the statically allocated root graphics */ + if(g==&graphics_root) return; + + g->refcount--; + if(g->refcount==0) { + graphics_delete(g->parent); + kfree(g); + } +} + +#define ADVANCE(n) { cmd+=n; length-=n; } + +int graphics_write(struct graphics *g, int *cmd, int length ) +{ + struct graphics_color c; + + while(length>0) { + switch (*cmd) { + case GRAPHICS_FGCOLOR: + c.r = cmd[1]; + c.g = cmd[2]; + c.b = cmd[3]; + c.a = 0; + graphics_fgcolor(g, c); + ADVANCE(4) + break; + case GRAPHICS_BGCOLOR: + c.r = cmd[1]; + c.g = cmd[2]; + c.b = cmd[3]; + c.a = 0; + graphics_bgcolor(g, c); + ADVANCE(4) + break; + case GRAPHICS_RECT: + graphics_rect(g, cmd[1], cmd[2], cmd[3], cmd[4]); + ADVANCE(5) + break; + case GRAPHICS_CLEAR: + graphics_clear(g, cmd[1], cmd[2], cmd[3], cmd[4]); + ADVANCE(5) + break; + case GRAPHICS_LINE: + graphics_line(g, cmd[1], cmd[2], cmd[3], cmd[4]); + ADVANCE(5) + break; + case GRAPHICS_TEXT: { + int x = cmd[1]; + int y = cmd[2]; + int strlength = cmd[3]; + int i; + for(i = 0; iclip.w; +} + +uint32_t graphics_height(struct graphics * g) +{ + return g->clip.h; +} + +void graphics_fgcolor(struct graphics *g, struct graphics_color c) +{ + g->fgcolor = c; +} + +void graphics_bgcolor(struct graphics *g, struct graphics_color c) +{ + g->bgcolor = c; +} + +int graphics_clip(struct graphics *g, int x, int y, int w, int h) +{ + // Clip values may not be negative + if(x<0 || y<0 || w<0 || h<0) return 0; + + // Child origin is relative to parent's clip origin. + x += g->clip.x; + y += g->clip.y; + + // Child origin must fall within parent clip + if(x>=g->bitmap->width || y>=g->bitmap->width) return 0; + + // Child width must fall within parent size + if((x + w) >= g->bitmap->width || (y + h) >= g->bitmap->height) return 0; + + // Apply the clip + g->clip.x = x; + g->clip.y = y; + g->clip.w = w; + g->clip.h = h; + return 1; +} + +static inline void plot_pixel(struct bitmap *b, int x, int y, struct graphics_color c) +{ + uint8_t *v = b->data + (b->width * y + x) * 3; + if(c.a == 0) { + v[2] = c.r; + v[1] = c.g; + v[0] = c.b; + } else { + uint16_t a = c.a; + uint16_t b = 256 - a; + v[0] = (c.r * b + v[0] * a) >> 8; + v[1] = (c.g * b + v[1] * a) >> 8; + v[2] = (c.b * b + v[2] * a) >> 8; + } +} + +static void graphics_rect_internal(struct graphics *g, int x, int y, int w, int h, struct graphics_color c ) +{ + int i, j; + + if(x<0) { w+=x; x=0; } + if(y<0) { h+=y; y=0; } + + if(x>g->clip.w || y>g->clip.h) return; + + w = MIN(g->clip.w - x, w); + h = MIN(g->clip.h - y, h); + + x += g->clip.x; + y += g->clip.y; + + for(j = 0; j < h; j++) { + for(i = 0; i < w; i++) { + plot_pixel(g->bitmap, x + i, y + j,c); + } + } +} + + +void graphics_rect(struct graphics *g, int x, int y, int w, int h ) +{ + graphics_rect_internal(g,x,y,w,h,g->fgcolor); +} + +void graphics_clear(struct graphics *g, int x, int y, int w, int h) +{ + graphics_rect_internal(g,x,y,w,h,g->bgcolor); +} + +static inline void graphics_line_vert(struct graphics *g, int x, int y, int w, int h) +{ + do { + plot_pixel(g->bitmap, x, y, g->fgcolor); + y++; + h--; + } while(h > 0); +} + +static inline void graphics_line_q1(struct graphics *g, int x, int y, int w, int h) +{ + int slope = FACTOR * w / h; + int counter = 0; + + do { + plot_pixel(g->bitmap, x, y, g->fgcolor); + y++; + h--; + counter += slope; + if(counter > FACTOR) { + counter = counter - FACTOR; + x++; + w--; + } + } while(h > 0); +} + +static inline void graphics_line_q2(struct graphics *g, int x, int y, int w, int h) +{ + int slope = FACTOR * h / w; + int counter = 0; + + do { + plot_pixel(g->bitmap, x, y, g->fgcolor); + x++; + w--; + counter += slope; + if(counter > FACTOR) { + counter = counter - FACTOR; + y++; + h--; + } + } while(w > 0); +} + +/* h<0, w>0, abs(h) < w */ + +static inline void graphics_line_q3(struct graphics *g, int x, int y, int w, int h) +{ + int slope = -FACTOR * h / w; + int counter = 0; + + do { + plot_pixel(g->bitmap, x, y, g->fgcolor); + x++; + w--; + counter += slope; + if(counter > FACTOR) { + counter = counter - FACTOR; + y--; + h--; + } + } while(w>0); +} + +/* h<0, w>0, abs(h) > w */ + +static inline void graphics_line_q4(struct graphics *g, int x, int y, int w, int h) +{ + int slope = -FACTOR * w / h; + int counter = 0; + + do { + plot_pixel(g->bitmap, x, y, g->fgcolor); + y--; + h++; + counter += slope; + if(counter > FACTOR) { + counter = counter - FACTOR; + x++; + w--; + } + } while(h<0); +} + +static inline void graphics_line_hozo(struct graphics *g, int x, int y, int w, int h) +{ + do { + plot_pixel(g->bitmap, x, y, g->fgcolor); + x++; + w--; + } while(w > 0); +} + +void graphics_line(struct graphics *g, int x, int y, int w, int h) +{ + // If width is negative, reverse direction to simplify. + if(w < 0) { + x = x + w; + y = y + h; + w = -w; + h = -h; + } + + // If line falls outside of clip region, bail out. + if(x<0 || y<0 || x>g->clip.w || y>g->clip.h) return; + if((x+w)>=g->clip.w || (y+h)>=g->clip.h || (y+h)<0 ) return; + + // Adjust origin to clip region. + x += g->clip.x; + y += g->clip.y; + + if(h>0) { + if(w==0) { + graphics_line_vert(g, x, y, w, h); + } else if(h > w) { + graphics_line_q1(g, x, y, w, h); + } else { + graphics_line_q2(g, x, y, w, h); + } + } else if(h<0) { + if(w==0) { + graphics_line_vert(g, x, y+h, w, -h); + } else if(-h < w) { + graphics_line_q3(g, x, y, w, h); + } else { + graphics_line_q4(g, x, y, w, h); + } + } else { //h==0 + graphics_line_hozo(g, x, y, w, h); + } +} + +void graphics_bitmap(struct graphics *g, int x, int y, int width, int height, uint8_t * data) +{ + int i, j, b; + int value; + + width = MIN(g->clip.w - x, width); + height = MIN(g->clip.h - y, height); + x += g->clip.x; + y += g->clip.y; + + b = 0; + + for(j = 0; j < height; j++) { + for(i = 0; i < width; i++) { + value = ((*data) << b) & 0x80; + if(value) { + plot_pixel(g->bitmap, x + i, y + j, g->fgcolor); + } else { + plot_pixel(g->bitmap, x + i, y + j, g->bgcolor); + } + b++; + if(b == 8) { + data++; + b = 0; + } + } + } +} + +void graphics_char(struct graphics *g, int x, int y, unsigned char c) +{ + uint32_t u = ((uint32_t) c) * FONT_WIDTH * FONT_HEIGHT / 8; + return graphics_bitmap(g, x, y, FONT_WIDTH, FONT_HEIGHT, &fontdata[u]); +} + +void graphics_scrollup(struct graphics *g, int x, int y, int w, int h, int dy) +{ + int j; + + w = MIN(g->clip.w - x, w); + h = MIN(g->clip.h - y, h); + x += g->clip.x; + y += g->clip.y; + + if(dy > h) + dy = h; + + for(j = 0; j < (h - dy); j++) { + memcpy(&g->bitmap->data[((y + j) * g->bitmap->width + x) * 3], &g->bitmap->data[((y + j + dy) * g->bitmap->width + x) * 3], w * 3); + } + + graphics_clear(g, x, y + h - dy, w, dy); +}