diff --git a/userspace/Makefile b/userspace/Makefile index 5364bbe2..d069d699 100644 --- a/userspace/Makefile +++ b/userspace/Makefile @@ -38,6 +38,11 @@ clean: @${CC} ${CFLAGS} -s -o $@ $< lib/sha2.o ${ERRORS} @${END} "CC" "$< [w/libs]" +../hdd/bin/compositor: compositor.c lib/graphics.o lib/list.o + @${BEG} "CC" "$< [w/libs]" + @${CC} ${CFLAGS} -s -I ../util/toaru-toolchain/i686-pc-toaru/include/freetype2/ -o $@ $< lib/graphics.o lib/list.o ../util/toaru-toolchain/i686-pc-toaru/lib/libfreetype.a ${ERRORS} + @${END} "CC" "$< [w/libs]" + ../hdd/bin/%: %.cpp @${BEG} "CPP" "$<" @${CPP} ${CPPFLAGS} -s -o $@ $< ${ERRORS} diff --git a/userspace/compositor.c b/userspace/compositor.c new file mode 100644 index 00000000..21f754f4 --- /dev/null +++ b/userspace/compositor.c @@ -0,0 +1,166 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * Window Compositor + */ + +#include +#include +#include +#include +#include "lib/graphics.h" +#include "lib/list.h" + +typedef struct { + uint32_t wid; /* Window identifier */ + uint32_t owner; /* Owning process */ + + uint16_t width; /* Buffer width in pixels */ + uint16_t height; /* Buffer height in pixels */ + + int32_t x; /* X coordinate of upper-left corner */ + int32_t y; /* Y coordinate of upper-left corner */ + uint16_t z; /* Stack order */ + + void * buffer; /* Window buffer */ +} window_t; + +#define TO_WINDOW_OFFSET(x,y) (((x) - window->x) + ((y) - window->y) * window->width) +#define DIRECT_OFFSET(x,y) ((x) + (y) * window->width) + +list_t * window_list; + +int32_t min(int32_t a, int32_t b) { + return (a < b) ? a : b; +} + +int32_t max(int32_t a, int32_t b) { + return (a > b) ? a : b; +} + +uint8_t is_between(int32_t lo, int32_t hi, int32_t val) { + if (val >= lo && val < hi) return 1; + return 0; +} + +uint8_t is_top(window_t *window, uint16_t x, uint16_t y) { + uint16_t index = window->z; + foreach(node, window_list) { + window_t * win = (window_t *)node->value; + if (win == window) continue; + if (win->z < index) continue; + if (is_between(win->x, win->x + win->width, x) && is_between(win->y, win->y + win->height, y)) { + return 0; + } + } + return 1; +} + +void redraw_window(window_t *window) { + uint16_t _lo_x = max(window->x, 0); + uint16_t _hi_x = min(window->x + window->width, graphics_width); + uint16_t _lo_y = max(window->y, 0); + uint16_t _hi_y = min(window->y + window->height, graphics_height); + + for (uint16_t y = _lo_y; y < _hi_y; ++y) { + for (uint16_t x = _lo_x; x < _hi_x; ++x) { + if (is_top(window, x, y)) { + GFX(x,y) = ((uint32_t *)window->buffer)[TO_WINDOW_OFFSET(x,y)]; + } + } + } +} + +void init_window(window_t *window, int32_t x, int32_t y, uint16_t width, uint16_t height, uint16_t index) { + window->width = width; + window->height = height; + window->x = x; + window->y = y; + window->z = index; + /* XXX */ + window->buffer = (void *)malloc(sizeof(uint32_t) * window->width * window->height); +} + +void window_set_point(window_t * window, uint16_t x, uint16_t y, uint32_t color) { + ((uint32_t *)window->buffer)[DIRECT_OFFSET(x,y)] = color; +} + +void window_draw_line(window_t * window, uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1, uint32_t color) { + int deltax = abs(x1 - x0); + int deltay = abs(y1 - y0); + int sx = (x0 < x1) ? 1 : -1; + int sy = (y0 < y1) ? 1 : -1; + int error = deltax - deltay; + while (1) { + window_set_point(window, x0, y0, color); + if (x0 == x1 && y0 == y1) break; + int e2 = 2 * error; + if (e2 > -deltay) { + error -= deltay; + x0 += sx; + } + if (e2 < deltax) { + error += deltax; + y0 += sy; + } + } +} + +void window_fill(window_t *window, uint32_t color) { + for (uint16_t i = 0; i < window->height; ++i) { + for (uint16_t j = 0; j < window->width; ++j) { + ((uint32_t *)window->buffer)[DIRECT_OFFSET(j,i)] = color; + } + } +} + +int main(int argc, char * argv[]) { + init_graphics(); + window_list = list_create(); + + window_t wina, winb, root, panel; + + init_window(&root, 0, 0, graphics_width, graphics_height, 0); + list_insert(window_list, &root); + window_fill(&root, rgb(20,20,20)); + + init_window(&panel, 0, 0, graphics_width, 24, -1); + list_insert(window_list, &panel); + window_fill(&panel, rgb(20,40,60)); + + init_window(&wina, 10, 10, 300, 300, 1); + list_insert(window_list, &wina); + window_fill(&wina, rgb(0,255,0)); + + init_window(&winb, 120, 120, 300, 300, 2); + list_insert(window_list, &winb); + window_fill(&winb, rgb(0,0,255)); + + redraw_window(&root); /* We only need to redraw root if things move around */ + redraw_window(&panel); + + int16_t direction_x = 1; + int16_t direction_y = 1; + + while (1) { + window_draw_line(&wina, rand() % 300, rand() % 300, rand() % 300, rand() % 300, rgb(rand() % 255,rand() % 255,rand() % 255)); + window_draw_line(&winb, rand() % 300, rand() % 300, rand() % 300, rand() % 300, rgb(rand() % 255,rand() % 255,rand() % 255)); + redraw_window(&wina); + redraw_window(&winb); + redraw_window(&root); + + winb.x += direction_x; + winb.y += direction_y; + if (winb.x >= graphics_width - winb.width) { + direction_x = -1; + } + if (winb.y >= graphics_height - winb.height) { + direction_y = -1; + } + if (winb.x <= 0) { + direction_x = 1; + } + if (winb.y <= 0) { + direction_y = 1; + } + } +} diff --git a/userspace/lib/graphics.c b/userspace/lib/graphics.c new file mode 100644 index 00000000..b2bc8550 --- /dev/null +++ b/userspace/lib/graphics.c @@ -0,0 +1,44 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * Graphics library + */ + +#include +#include +#include "graphics.h" + +DEFN_SYSCALL0(getgraphicsaddress, 11); +DEFN_SYSCALL1(kbd_mode, 12, int); +DEFN_SYSCALL0(kbd_get, 13); +DEFN_SYSCALL1(setgraphicsoffset, 16, int); + +DEFN_SYSCALL0(getgraphicswidth, 18); +DEFN_SYSCALL0(getgraphicsheight, 19); +DEFN_SYSCALL0(getgraphicsdepth, 20); + +uint16_t graphics_width = 0; +uint16_t graphics_height = 0; +uint16_t graphics_depth = 0; + +/* Pointer to graphics memory */ +uint8_t * gfx_mem = 0; + +void init_graphics() { + graphics_width = syscall_getgraphicswidth(); + graphics_height = syscall_getgraphicsheight(); + graphics_depth = syscall_getgraphicsdepth(); + gfx_mem = (void *)syscall_getgraphicsaddress(); +} + +uint32_t rgb(uint8_t r, uint8_t g, uint8_t b) { + return 0xFF000000 + (r * 0x10000) + (g * 0x100) + (b * 0x1); +} + +uint32_t alpha_blend(uint32_t bottom, uint32_t top, uint32_t mask) { + float a = _RED(mask) / 256.0; + uint8_t red = _RED(bottom) * (1.0 - a) + _RED(top) * a; + uint8_t gre = _GRE(bottom) * (1.0 - a) + _GRE(top) * a; + uint8_t blu = _BLU(bottom) * (1.0 - a) + _BLU(top) * a; + return rgb(red,gre,blu); +} + diff --git a/userspace/lib/graphics.h b/userspace/lib/graphics.h new file mode 100644 index 00000000..f905ad5d --- /dev/null +++ b/userspace/lib/graphics.h @@ -0,0 +1,38 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#include +#include + +#define GFX_W graphics_width /* Display width */ +#define GFX_H graphics_height /* Display height */ +#define GFX_B (graphics_depth / 8) /* Display byte depth */ + +#define _RED(color) ((color & 0x00FF0000) / 0x10000) +#define _GRE(color) ((color & 0x0000FF00) / 0x100) +#define _BLU(color) ((color & 0x000000FF) / 0x1) + +/* + * Macros make verything easier. + */ +#define GFX(x,y) *((uint32_t *)&gfx_mem[(GFX_W * (y) + (x)) * GFX_B]) + +DECL_SYSCALL0(getgraphicsaddress); +DECL_SYSCALL1(kbd_mode, int); +DECL_SYSCALL0(kbd_get); +DECL_SYSCALL1(setgraphicsoffset, int); + +DECL_SYSCALL0(getgraphicswidth); +DECL_SYSCALL0(getgraphicsheight); +DECL_SYSCALL0(getgraphicsdepth); + +uint16_t graphics_width; +uint16_t graphics_height; +uint16_t graphics_depth; + +/* Pointer to graphics memory */ +uint8_t * gfx_mem; + + +void init_graphics(); +uint32_t rgb(uint8_t r, uint8_t g, uint8_t b); +uint32_t alpha_blend(uint32_t bottom, uint32_t top, uint32_t mask); diff --git a/userspace/lib/list.c b/userspace/lib/list.c new file mode 100644 index 00000000..85040035 --- /dev/null +++ b/userspace/lib/list.c @@ -0,0 +1,135 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * General-purpose list implementations. + */ +#include +#include "list.h" + +void list_destroy(list_t * list) { + /* Free all of the contents of a list */ + node_t * n = list->head; + while (n) { + free(n->value); + n = n->next; + } +} + +void list_free(list_t * list) { + /* Free the actual structure of a list */ + node_t * n = list->head; + while (n) { + node_t * s = n->next; + free(n); + n = s; + } +} + +void list_append(list_t * list, node_t * node) { + /* Insert a node onto the end of a list */ + if (!list->tail) { + list->head = node; + } else { + list->tail->next = node; + node->prev = list->tail; + } + list->tail = node; + list->length++; +} + +void list_insert(list_t * list, void * item) { + /* Insert an item into a list */ + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + list_append(list, node); +} + +list_t * list_create() { + /* Create a fresh list */ + list_t * out = malloc(sizeof(list_t)); + out->head = NULL; + out->tail = NULL; + out->length = 0; + return out; +} + +node_t * list_find(list_t * list, void * value) { + foreach(item, list) { + if (item->value == value) { + return item; + } + } + return NULL; +} + +void list_remove(list_t * list, size_t index) { + /* remove index from the list */ + if (index > list->length) return; + size_t i = 0; + node_t * n = list->head; + while (i < index) { + n = n->next; + i++; + } + list_delete(list, n); +} + +void list_delete(list_t * list, node_t * node) { + /* remove node from the list */ + if (node == list->head) { + list->head = node->next; + } + if (node == list->tail) { + list->tail = node->prev; + } + if (node->prev) { + node->prev->next = node->next; + } + if (node->next) { + node->next->prev = node->prev; + } + list->length--; +} + +node_t * list_pop(list_t * list) { + /* Remove and return the last value in the list + * If you don't need it, you still probably want to free it! + * Try free(list_pop(list)); ! + * */ + if (!list->tail) return NULL; + node_t * out = list->tail; + list_delete(list, list->tail); + return out; +} + +node_t * list_dequeue(list_t * list) { + if (!list->head) return NULL; + node_t * out = list->head; + list_delete(list, list->head); + return out; +} + +list_t * list_copy(list_t * original) { + /* Create a new copy of original */ + list_t * out = list_create(); + node_t * node = original->head; + while (node) { + list_insert(out, node->value); + } + return out; +} + +void list_merge(list_t * target, list_t * source) { + /* Destructively merges source into target */ + if (target->tail) { + target->tail->next = source->head; + } else { + target->head = source->head; + } + if (source->tail) { + target->tail = source->tail; + } + target->length += source->length; + free(source); +} diff --git a/userspace/lib/list.h b/userspace/lib/list.h new file mode 100644 index 00000000..abaa7196 --- /dev/null +++ b/userspace/lib/list.h @@ -0,0 +1,37 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * General-purpose list implementations. + */ +#ifndef LIST_H +#define LIST_H + +#include + +typedef struct node { + struct node * next; + struct node * prev; + void * value; +} __attribute__((packed)) node_t; + +typedef struct { + node_t * head; + node_t * tail; + size_t length; +} __attribute__((packed)) list_t; + +void list_destroy(list_t * list); +void list_free(list_t * list); +void list_append(list_t * list, node_t * item); +void list_insert(list_t * list, void * item); +list_t * list_create(); +node_t * list_find(list_t * list, void * value); +void list_remove(list_t * list, size_t index); +void list_delete(list_t * list, node_t * node); +node_t * list_pop(list_t * list); +node_t * list_dequeue(list_t * list); +list_t * list_copy(list_t * original); +void list_merge(list_t * target, list_t * source); + +#define foreach(i, list) for (node_t * i = list->head; i != NULL; i = i->next) + +#endif