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