From 885a7b1f31cdd39aa5745f042969a578b7aa2f2b Mon Sep 17 00:00:00 2001 From: antifallobst Date: Tue, 21 Feb 2023 10:19:29 +0100 Subject: [PATCH] feature (kernel): Implemented graphics_buffers (canvases) and alpha blending --- kernel/inc/drivers/graphics/color.h | 2 + kernel/inc/drivers/graphics/renderer.h | 36 +++++-- kernel/src/drivers/graphics/color.c | 25 +++++ kernel/src/drivers/graphics/renderer.c | 126 ++++++++++++++++++++----- kernel/src/kmain.c | 19 ++-- 5 files changed, 168 insertions(+), 40 deletions(-) create mode 100644 kernel/src/drivers/graphics/color.c diff --git a/kernel/inc/drivers/graphics/color.h b/kernel/inc/drivers/graphics/color.h index 4c6ce9e..fa2dc58 100644 --- a/kernel/inc/drivers/graphics/color.h +++ b/kernel/inc/drivers/graphics/color.h @@ -25,4 +25,6 @@ typedef struct { uint8_t blue; } color_argb_T; +color_argb_T color_argb_blend_alpha(color_argb_T background, color_argb_T foreground); + #endif //NOX_COLOR_H diff --git a/kernel/inc/drivers/graphics/renderer.h b/kernel/inc/drivers/graphics/renderer.h index 589ab27..a76a5e9 100644 --- a/kernel/inc/drivers/graphics/renderer.h +++ b/kernel/inc/drivers/graphics/renderer.h @@ -22,17 +22,35 @@ #include "drivers/graphics/framebuffer.h" #include "boot/boot_info.h" +typedef struct graphics_buffer_T graphics_buffer_T; +struct graphics_buffer_T { + color_argb_T* buffer; + uint32_t width; + uint32_t height; + uint32_t pos_x; + uint32_t pos_y; + graphics_buffer_T* prev; + graphics_buffer_T* next; +}; + typedef struct { - framebuffer_T framebuffer; - uint32_t* back_buffer; - uint64_t buffer_size; - font_T font; + framebuffer_T framebuffer; + uint32_t* back_buffer; + uint64_t buffer_size; + graphics_buffer_T* graphics_buffers; + font_T font; } graphics_renderer_T; -void graphics_renderer_set_pixel (uint32_t x, uint32_t y, color_argb_T color); -color_argb_T graphics_renderer_get_pixel (uint32_t x, uint32_t y); -void graphics_renderer_draw_char (uint32_t x, uint32_t y, color_argb_T color, char chr); -void graphics_renderer_update (); -void graphics_renderer_init (boot_info_T* boot_info); +graphics_buffer_T* graphics_buffer_request (uint32_t pos_x, uint32_t pos_y, uint32_t width, uint32_t height); +void graphics_buffer_destruct (graphics_buffer_T* graphics_buffer); +void graphics_buffer_set_pixel (graphics_buffer_T* graphics_buffer, uint32_t x, uint32_t y, color_argb_T color); +color_argb_T graphics_buffer_get_pixel (graphics_buffer_T* graphics_buffer, uint32_t x, uint32_t y); +void graphics_buffer_draw_char (graphics_buffer_T* graphics_buffer, uint32_t x, uint32_t y, color_argb_T color, char chr); + +void graphics_renderer_init (boot_info_T* boot_info); +void graphics_renderer_update (); +graphics_buffer_T* graphics_renderer_get_top_buffer (); +uint32_t graphics_renderer_get_width (); +uint32_t graphics_renderer_get_height (); #endif //NOX_RENDERER_H diff --git a/kernel/src/drivers/graphics/color.c b/kernel/src/drivers/graphics/color.c new file mode 100644 index 0000000..aea3644 --- /dev/null +++ b/kernel/src/drivers/graphics/color.c @@ -0,0 +1,25 @@ +/* Copyright (C) Antifallobst + * + * NoxOS is free software: + * you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * NoxOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#include "drivers/graphics/color.h" + +color_argb_T color_argb_blend_alpha(color_argb_T background, color_argb_T foreground) { + color_argb_T color = foreground; + color.red += ((foreground.red * foreground.alpha) + (background.red * (0xFF - foreground.alpha))) / 0xFF; + color.green += ((foreground.green * foreground.alpha) + (background.green * (0xFF - foreground.alpha))) / 0xFF; + color.blue += ((foreground.blue * foreground.alpha) + (background.blue * (0xFF - foreground.alpha))) / 0xFF; + + return color; +} diff --git a/kernel/src/drivers/graphics/renderer.c b/kernel/src/drivers/graphics/renderer.c index 0c81230..a057bcc 100644 --- a/kernel/src/drivers/graphics/renderer.c +++ b/kernel/src/drivers/graphics/renderer.c @@ -20,46 +20,66 @@ graphics_renderer_T g_renderer; -void graphics_renderer_set_pixel(uint32_t x, uint32_t y, color_argb_T color) { - uint64_t position = y * g_renderer.framebuffer.width + x; +graphics_buffer_T* graphics_buffer_request(uint32_t pos_x, uint32_t pos_y, uint32_t width, uint32_t height) { + graphics_buffer_T* graphics_buffer = memory_allocate(sizeof(graphics_buffer_T)); - g_renderer.back_buffer[position] = (color.red << g_renderer.framebuffer.shift_red) | - (color.green << g_renderer.framebuffer.shift_green) | - (color.blue << g_renderer.framebuffer.shift_blue); + graphics_buffer->pos_x = pos_x; + graphics_buffer->pos_y = pos_y; + graphics_buffer->width = width; + graphics_buffer->height = height; + graphics_buffer->buffer = memory_allocate(width * height * sizeof(color_argb_T)); + memory_set(graphics_buffer->buffer, 0, width * height * sizeof(color_argb_T)); + + graphics_buffer_T* top_buffer = graphics_renderer_get_top_buffer(); + graphics_buffer->prev = top_buffer; + graphics_buffer->next = NULL; + if (top_buffer == NULL) { + g_renderer.graphics_buffers = graphics_buffer; + } else { + top_buffer->next = graphics_buffer; + } + + return graphics_buffer; } -color_argb_T graphics_renderer_get_pixel(uint32_t x, uint32_t y) { - uint64_t position = y * g_renderer.framebuffer.width + x; +void graphics_buffer_destruct(graphics_buffer_T* graphics_buffer) { + if (graphics_buffer->prev != NULL) { + graphics_buffer->prev->next = graphics_buffer->next; + } else { + g_renderer.graphics_buffers = graphics_buffer->next; + } + if (graphics_buffer->next != NULL) { + graphics_buffer->next->prev = graphics_buffer->prev; + } - color_argb_T color; - color.alpha = 0xFF; - color.red = g_renderer.back_buffer[position] & (0xFF << g_renderer.framebuffer.shift_red); - color.green = g_renderer.back_buffer[position] & (0xFF << g_renderer.framebuffer.shift_green); - color.blue = g_renderer.back_buffer[position] & (0xFF << g_renderer.framebuffer.shift_blue); - - return color; + memory_free(graphics_buffer->buffer); + memory_free(graphics_buffer); } -void graphics_renderer_draw_char(uint32_t x, uint32_t y, color_argb_T color, char chr) { +void graphics_buffer_set_pixel(graphics_buffer_T* graphics_buffer, uint32_t x, uint32_t y, color_argb_T color) { + graphics_buffer->buffer[y * graphics_buffer->width + x] = color; +} + +color_argb_T graphics_buffer_get_pixel(graphics_buffer_T* graphics_buffer, uint32_t x, uint32_t y) { + return graphics_buffer->buffer[y * graphics_buffer->width + x]; +} + +void graphics_buffer_draw_char(graphics_buffer_T* graphics_buffer, uint32_t x, uint32_t y, color_argb_T color, char chr) { uint8_t* glyph = &g_renderer.font.buffer[g_renderer.font.glyph_size * chr]; for (int y_pos = 0; y_pos < g_renderer.font.height; y_pos++){ for (int x_pos = 0; x_pos < g_renderer.font.width; x_pos++){ if (*glyph & (1 << x_pos)) { - graphics_renderer_set_pixel(x + x_pos, y + y_pos, color); + graphics_buffer_set_pixel(graphics_buffer, x + x_pos, y + y_pos, color); } else { - graphics_renderer_set_pixel(x + x_pos, y + y_pos, (color_argb_T){0x00, 0x00, 0x00, 0x00}); + graphics_buffer_set_pixel(graphics_buffer, x + x_pos, y + y_pos, (color_argb_T){0x00, 0x00, 0x00, 0x00}); } } glyph++; } } -void graphics_renderer_update() { - memory_copy(g_renderer.back_buffer, g_renderer.framebuffer.address, g_renderer.buffer_size); -} - void graphics_renderer_init(boot_info_T* boot_info_T) { struct limine_framebuffer* framebuffer = boot_info_T->framebuffer->framebuffers[0]; @@ -73,9 +93,65 @@ void graphics_renderer_init(boot_info_T* boot_info_T) { g_renderer.framebuffer.shift_green = framebuffer->green_mask_shift; g_renderer.framebuffer.shift_blue = framebuffer->blue_mask_shift; - g_renderer.buffer_size = g_renderer.framebuffer.width * g_renderer.framebuffer.height * g_renderer.framebuffer.bytes_per_pixel; - g_renderer.back_buffer = memory_allocate(g_renderer.buffer_size); - memory_set(g_renderer.back_buffer, 0, g_renderer.buffer_size); + g_renderer.buffer_size = g_renderer.framebuffer.width * g_renderer.framebuffer.height * g_renderer.framebuffer.bytes_per_pixel; + g_renderer.back_buffer = memory_allocate(g_renderer.buffer_size); + g_renderer.graphics_buffers = NULL; + g_renderer.font = g_font; - g_renderer.font = g_font; + memory_set(g_renderer.back_buffer, 0, g_renderer.buffer_size); +} + +void graphics_renderer_update() { + graphics_buffer_T* graphics_buffer = g_renderer.graphics_buffers; + while (graphics_buffer != NULL) { + + uint32_t size_x = MIN(graphics_buffer->pos_x + graphics_buffer->width, g_renderer.framebuffer.width); + uint32_t size_y = MIN(graphics_buffer->pos_y + graphics_buffer->height, g_renderer.framebuffer.height); + + for (uint32_t y = graphics_buffer->pos_y; y < size_y; y++) { + for (uint32_t x = graphics_buffer->pos_x; x < size_x; x++) { + color_argb_T color = graphics_buffer->buffer[(y - graphics_buffer->pos_y) * graphics_buffer->width + (x - graphics_buffer->pos_x)]; + + color_argb_T original; + original.alpha = 0xFF; + original.red = (g_renderer.back_buffer[y * g_renderer.framebuffer.width + x] >> g_renderer.framebuffer.shift_red) & 0xFF; + original.green = (g_renderer.back_buffer[y * g_renderer.framebuffer.width + x] >> g_renderer.framebuffer.shift_green) & 0xFF; + original.blue = (g_renderer.back_buffer[y * g_renderer.framebuffer.width + x] >> g_renderer.framebuffer.shift_blue) & 0xFF; + + // apply transparency + color = color_argb_blend_alpha(original, color); + + // write into back_buffer + g_renderer.back_buffer[y * g_renderer.framebuffer.width + x] = (color.red << g_renderer.framebuffer.shift_red) | + (color.green << g_renderer.framebuffer.shift_green) | + (color.blue << g_renderer.framebuffer.shift_blue); + } + } + + graphics_buffer = graphics_buffer->next; + } + + // swap back_buffer into framebuffer + memory_copy(g_renderer.back_buffer, g_renderer.framebuffer.address, g_renderer.buffer_size); +} + +graphics_buffer_T* graphics_renderer_get_top_buffer() { + if (g_renderer.graphics_buffers == NULL) { + return NULL; + } + + graphics_buffer_T* graphics_buffer = g_renderer.graphics_buffers; + while (graphics_buffer->next != NULL) { + graphics_buffer = graphics_buffer->next; + } + + return graphics_buffer; +} + +uint32_t graphics_renderer_get_width() { + return g_renderer.framebuffer.width; +} + +uint32_t graphics_renderer_get_height() { + return g_renderer.framebuffer.height; } \ No newline at end of file diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index 5a8854f..5a96ff1 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -56,13 +56,20 @@ void kmain(boot_info_T boot_info) { limine_terminal_print(&boot_info, "Kernel initialized\n"); log(LOG_INFO, "!=====[ Kernel Initialized ]=====!\n"); - graphics_renderer_draw_char(0, 0, (color_argb_T){0xFF, 0xFF, 0, 0}, 'R'); - graphics_renderer_draw_char(8, 0, (color_argb_T){0xFF, 0, 0xFF, 0}, 'G'); - graphics_renderer_draw_char(16, 0, (color_argb_T){0xFF, 0, 0, 0xFF}, 'B'); - graphics_renderer_update(); + graphics_buffer_T* buffer = graphics_buffer_request(0, 0, 50, 50); + graphics_buffer_T* buffer2 = graphics_buffer_request(0, 0, 50, 50); - color_argb_T color = graphics_renderer_get_pixel(0, 5); - log(LOG_DEBUG, "ALPHA[0x%xb] RED[0x%xb] GREEN[0x%xb] BLUE[0x%xb]", color.alpha, color.red, color.green, color.blue); + for (int x = 0; x < 50; x++) { + for (int y = 0; y < 50; y++) { + graphics_buffer_set_pixel(buffer2, x, y, (color_argb_T){0x80, 0xca, 0xca, 0xca}); + } + } + + graphics_buffer_draw_char(buffer, 0, 0, (color_argb_T){0xFF, 0xFF, 0, 0}, 'R'); + graphics_buffer_draw_char(buffer, 8, 0, (color_argb_T){0xFF, 0, 0xFF, 0}, 'G'); + graphics_buffer_draw_char(buffer, 16, 0, (color_argb_T){0xFF, 0, 0, 0xFF}, 'B'); + + graphics_renderer_update(); CORE_HALT_FOREVER }