Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
parent
a0708eb3b6
commit
d72aae7bf9
421
kernel/graphics.c
Normal file
421
kernel/graphics.c
Normal file
|
@ -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; i<strlength; i++) {
|
||||||
|
graphics_char(g,x+i*FONT_WIDTH,y,cmd[4+i]);
|
||||||
|
}
|
||||||
|
ADVANCE(4+strlength)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return KERROR_INVALID_REQUEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t graphics_width(struct graphics * g)
|
||||||
|
{
|
||||||
|
return g->clip.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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user