diff --git a/stage23/lib/bmp.c b/stage23/lib/bmp.c index a299caac..fb90149a 100644 --- a/stage23/lib/bmp.c +++ b/stage23/lib/bmp.c @@ -29,9 +29,44 @@ struct bmp_header { } __attribute__((packed)); struct bmp_local { + uint8_t *image; + uint32_t pitch; struct bmp_header header; }; +static uint32_t get_pixel(struct image *this, int x, int y) { + struct bmp_local *local = this->local; + struct bmp_header *header = &local->header; + + switch (this->type) { + case IMAGE_TILED: { + x %= header->bi_width; + y %= header->bi_height; + break; + } + case IMAGE_CENTERED: { + x -= this->x_displacement; + y -= this->y_displacement; + if (x < 0 || y < 0 || x >= this->x_size || y >= this->y_size) + return this->back_colour; + break; + } + case IMAGE_STRETCHED: { + x = (x * this->old_x_size) / this->x_size; + y = (y * this->old_y_size) / this->y_size; + break; + } + } + + size_t pixel_offset = local->pitch * (header->bi_height - y - 1) + x * (header->bi_bpp / 8); + + // TODO: Perhaps use masks here, they're there for a reason + uint32_t composite = 0; + for (int i = 0; i < header->bi_bpp / 8; i++) + composite |= (uint32_t)local->image[pixel_offset + i] << (i * 8); + + return composite; +} int bmp_open_image(struct image *image, struct file_handle *file) { struct bmp_header header; @@ -40,22 +75,22 @@ int bmp_open_image(struct image *image, struct file_handle *file) { if (memcmp(&header.bf_signature, "BM", 2) != 0) return -1; - if ((header.bi_bpp < 8) | ((header.bi_bpp % 8) != 0)) + // We don't support bpp lower than 8 + if (header.bi_bpp < 8) return -1; struct bmp_local *local = ext_mem_alloc(sizeof(struct bmp_local)); - image->img = ext_mem_alloc(header.bf_size); - fread(file, image->img, header.bf_offset, header.bf_size); + local->image = ext_mem_alloc(header.bf_size); + fread(file, local->image, header.bf_offset, header.bf_size); + local->pitch = ALIGN_UP(header.bi_width * header.bi_bpp, 32) / 8; local->header = header; - image->x_size = header.bi_width; - image->y_size = header.bi_height; - image->pitch = ALIGN_UP(header.bi_width * header.bi_bpp, 32) / 8; - image->local = local; - image->bpp = header.bi_bpp; - image->img_width = header.bi_width; - image->img_height = header.bi_height; + image->x_size = header.bi_width; + image->y_size = header.bi_height; + image->get_pixel = get_pixel; + image->local = local; + return 0; } diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c index 3feb3472..a8788b33 100644 --- a/stage23/lib/gterm.c +++ b/stage23/lib/gterm.c @@ -74,7 +74,17 @@ void gterm_plot_px(int x, int y, uint32_t hex) { gterm_framebuffer[fb_i] = hex; } -static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, uint32_t hex) { +static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) { + if (x >= frame_width && x < frame_width + VGA_FONT_WIDTH * cols + && y >= frame_height && y < frame_height + VGA_FONT_HEIGHT * rows) { + return colour_blend(hex, background->get_pixel(background, x, y)); + } + + uint32_t bg_px = background->get_pixel(background, x, y); + + if (margin_gradient == 0) + return bg_px; + int distance, x_distance, y_distance; if (x < frame_width) @@ -105,100 +115,14 @@ static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, uint32_t h return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px); } -typedef int fixedp6; // the last 6 bits are the fixed point part -static int fixedp6_to_int(fixedp6 value) { return value / 64; } -static fixedp6 int_to_fixedp6(int value) { return value * 64; } - -// Draw rect at coordinates, copying from the image to the fb and canvas, applying fn on every pixel -__attribute__((always_inline)) static inline void genloop(int xstart, int xend, int ystart, int yend, uint32_t (*blend)(int x, int y, uint32_t orig)) { - uint8_t *img = background->img; - const int img_width = background->img_width, img_height = background->img_height, img_pitch = background->pitch, colsize = background->bpp / 8; - - switch (background->type) { - case IMAGE_TILED: - for (int y = ystart; y < yend; y++) { - int image_y = y % img_height, image_x = xstart % img_width; - const size_t off = img_pitch * (img_height - 1 - image_y); - int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y; - for (int x = xstart; x < xend; x++) { - uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); - uint32_t i = blend(x, y, img_pixel); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; - if (image_x++ == img_width) image_x = 0; // image_x = x % img_width, but modulo is too expensive - } - } - break; - - case IMAGE_CENTERED: - for (int y = ystart; y < yend; y++) { - int image_y = y - background->y_displacement; - const size_t off = img_pitch * (img_height - 1 - image_y); - int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y; - if ((image_y < 0) || (image_y >= background->y_size)) { /* external part */ - for (int x = xstart; x < xend; x++) { - uint32_t i = blend(x, y, background->back_colour); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; - } - } - else { /* internal part */ - for (int x = xstart; x < xend; x++) { - int image_x = (x - background->x_displacement); - bool x_external = (image_x < 0) || (image_x >= background->x_size); - uint32_t img_pixel = *(uint32_t*)(img + image_x * colsize + off); - uint32_t i = blend(x, y, x_external ? background->back_colour : img_pixel); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; - } - } - } - break; - // For every pixel, ratio = img_width / gterm_width, img_x = x * ratio, x = (xstart + i) - // hence x = xstart * ratio + i * ratio - // so you can set x = xstart * ratio, and increment by ratio at each iteration - case IMAGE_STRETCHED: - for (int y = ystart; y < yend; y++) { - int img_y = (y * img_height) / gterm_height; // calculate Y with full precision - int off = img_pitch * (img_height - 1 - img_y); - int canvas_off = gterm_width * y, fb_off = gterm_pitch / 4 * y; - - size_t ratio = int_to_fixedp6(img_width) / gterm_width; - fixedp6 img_x = ratio * xstart; - for (int x = xstart; x < xend; x++) { - uint32_t img_pixel = *(uint32_t*)(img + fixedp6_to_int(img_x) * colsize + off); - uint32_t i = blend(x, y, img_pixel); - bg_canvas[canvas_off + x] = i; gterm_framebuffer[fb_off + x] = i; - img_x += ratio; - } - } - break; - } -} -static uint32_t blend_external(int x, int y, uint32_t orig) { (void)x; (void)y; return orig; } -static uint32_t blend_internal(int x, int y, uint32_t orig) { (void)x; (void)y; return colour_blend(ansi_colours[8], orig); } -static uint32_t blend_margin(int x, int y, uint32_t orig) { return blend_gradient_from_box(x, y, orig, ansi_colours[8]); } - -static void loop_external(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_external); } -static void loop_margin(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_margin); } -static void loop_internal(int xstart, int xend, int ystart, int yend) { genloop(xstart, xend, ystart, yend, blend_internal); } - void gterm_generate_canvas(void) { if (background) { - const int frame_height_end = frame_height + VGA_FONT_HEIGHT * rows, frame_width_end = frame_width + VGA_FONT_WIDTH * cols; - const int fheight = frame_height - margin_gradient, fheight_end = frame_height_end + margin_gradient, - fwidth = frame_width - margin_gradient, fwidth_end = frame_width_end + margin_gradient; - - loop_external(0, gterm_width, 0, fheight); - loop_external(0, gterm_width, fheight_end, gterm_height); - loop_external(0, fwidth, fheight, fheight_end); - loop_external(fwidth_end, gterm_width, fheight, fheight_end); - - if (margin_gradient) { - loop_margin(fwidth, fwidth_end, fheight, frame_height); - loop_margin(fwidth, fwidth_end, frame_height_end, fheight_end); - loop_margin(fwidth, frame_width, frame_height, frame_height_end); - loop_margin(frame_width_end, fwidth_end, frame_height, frame_height_end); + for (int y = 0; y < gterm_height; y++) { + for (int x = 0; x < gterm_width; x++) { + bg_canvas[y * gterm_width + x] = blend_gradient_from_box(x, y, ansi_colours[8]); + gterm_plot_px(x, y, bg_canvas[y * gterm_width + x]); + } } - - loop_internal(frame_width, frame_width_end, frame_height, frame_height_end); } else { for (int y = 0; y < gterm_height; y++) { for (int x = 0; x < gterm_width; x++) { @@ -208,7 +132,6 @@ void gterm_generate_canvas(void) { } } } -#undef genloop struct gterm_char { uint32_t c; @@ -216,30 +139,74 @@ struct gterm_char { int bg; }; +static void plot_char_mem(uint32_t *buf, struct gterm_char *c, int x, int y) { + uint8_t *glyph = &vga_font[(size_t)c->c * VGA_FONT_HEIGHT]; + + for (int i = 0; i < VGA_FONT_HEIGHT; i++) { + for (int j = 0; j < VGA_FONT_WIDTH; j++) { + if ((glyph[i] & (0x80 >> j))) { + buf[i * VGA_FONT_WIDTH + j] = ansi_colours[c->fg]; + } else { + if (c->bg == 8) + buf[i * VGA_FONT_WIDTH + j] = bg_canvas[(y + i) * gterm_width + (x + j)]; + else + buf[i * VGA_FONT_WIDTH + j] = ansi_colours[c->bg]; + } + } + } +} + void gterm_plot_char(struct gterm_char *c, int x, int y) { uint8_t *glyph = &vga_font[(size_t)c->c * VGA_FONT_HEIGHT]; for (int i = 0; i < VGA_FONT_HEIGHT; i++) { - uint32_t *line = gterm_framebuffer + x + (y + i) * (gterm_pitch / 4), *canvas_line = bg_canvas + x + (y + i) * gterm_width; for (int j = 0; j < VGA_FONT_WIDTH; j++) { if ((glyph[i] & (0x80 >> j))) { - line[j] = ansi_colours[c->fg]; + gterm_plot_px(x + j, y + i, ansi_colours[c->fg]); } else { if (c->bg == 8) - line[j] = canvas_line[j]; + gterm_plot_px(x + j, y + i, bg_canvas[(y + i) * gterm_width + (x + j)]); else - line[j] = ansi_colours[c->bg]; + gterm_plot_px(x + j, y + i, ansi_colours[c->bg]); } } } } static void plot_char_grid_force(struct gterm_char *c, int x, int y) { - gterm_plot_char(c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT); + uint32_t new_char[VGA_FONT_WIDTH * VGA_FONT_HEIGHT]; + plot_char_mem(new_char, c, + x * VGA_FONT_WIDTH + frame_width, y * VGA_FONT_HEIGHT + frame_height); + + for (int i = 0; i < VGA_FONT_HEIGHT; i++) { + for (int j = 0; j < VGA_FONT_WIDTH; j++) { + gterm_plot_px(x * VGA_FONT_WIDTH + frame_width + j, + y * VGA_FONT_HEIGHT + frame_height + i, + new_char[i * VGA_FONT_WIDTH + j]); + } + } } static void plot_char_grid(struct gterm_char *c, int x, int y) { - if (!double_buffer_enabled) gterm_plot_char(c, frame_width + x * VGA_FONT_WIDTH, frame_height + y * VGA_FONT_HEIGHT); + uint32_t old_char[VGA_FONT_WIDTH * VGA_FONT_HEIGHT]; + uint32_t new_char[VGA_FONT_WIDTH * VGA_FONT_HEIGHT]; + + plot_char_mem(old_char, &grid[x + y * cols], + x * VGA_FONT_WIDTH + frame_width, y * VGA_FONT_HEIGHT + frame_height); + plot_char_mem(new_char, c, + x * VGA_FONT_WIDTH + frame_width, y * VGA_FONT_HEIGHT + frame_height); + + if (!double_buffer_enabled) { + for (int i = 0; i < VGA_FONT_HEIGHT; i++) { + for (int j = 0; j < VGA_FONT_WIDTH; j++) { + if (old_char[i * VGA_FONT_WIDTH + j] != new_char[i * VGA_FONT_WIDTH + j]) + gterm_plot_px(x * VGA_FONT_WIDTH + frame_width + j, + y * VGA_FONT_HEIGHT + frame_height + i, + new_char[i * VGA_FONT_WIDTH + j]); + } + } + } + grid[x + y * cols] = *c; } @@ -299,14 +266,13 @@ static void scroll(void) { void gterm_clear(bool move) { clear_cursor(); - if (!double_buffer_enabled) - for (int y = frame_height; y < frame_height + VGA_FONT_HEIGHT * rows; y++) - memcpy(gterm_framebuffer + y * (gterm_pitch / 4) + frame_width, bg_canvas + y * gterm_width + frame_width, VGA_FONT_WIDTH * cols * 4); struct gterm_char empty; empty.c = ' '; empty.fg = 9; empty.bg = 8; - for (int i = 0; i < rows * cols; i++) grid[i] = empty; + for (int i = 0; i < rows * cols; i++) { + plot_char_grid(&empty, i % cols, i / cols); + } if (move) { cursor_x = 0; diff --git a/stage23/lib/image.c b/stage23/lib/image.c index a325cc70..fe0f08b4 100644 --- a/stage23/lib/image.c +++ b/stage23/lib/image.c @@ -17,6 +17,9 @@ void image_make_centered(struct image *image, int frame_x_size, int frame_y_size void image_make_stretched(struct image *image, int new_x_size, int new_y_size) { image->type = IMAGE_STRETCHED; + image->old_x_size = image->x_size; + image->old_y_size = image->y_size; + image->x_size = new_x_size; image->y_size = new_y_size; } diff --git a/stage23/lib/image.h b/stage23/lib/image.h index 717e6138..7e9cbd8f 100644 --- a/stage23/lib/image.h +++ b/stage23/lib/image.h @@ -9,13 +9,6 @@ struct image { int x_size; int y_size; int type; - - - uint8_t *img; - int bpp; - int pitch; - int img_width; // x_size = scaled size, img_width = bitmap size - int img_height; union { struct { int x_displacement; @@ -27,6 +20,7 @@ struct image { }; }; uint32_t back_colour; + uint32_t (*get_pixel)(struct image *this, int x, int y); void *local; };