gterm: Reintroduce fast canvas drawing, only.
Co-authored-by: StaticSaga <61866965+StaticSaga@users.noreply.github.com>
This commit is contained in:
parent
f4dc6481f1
commit
e5ec3c1fb3
@ -28,46 +28,6 @@ struct bmp_header {
|
|||||||
uint32_t blue_mask;
|
uint32_t blue_mask;
|
||||||
} __attribute__((packed));
|
} __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) {
|
int bmp_open_image(struct image *image, struct file_handle *file) {
|
||||||
struct bmp_header header;
|
struct bmp_header header;
|
||||||
fread(file, &header, 0, sizeof(struct bmp_header));
|
fread(file, &header, 0, sizeof(struct bmp_header));
|
||||||
@ -76,21 +36,18 @@ int bmp_open_image(struct image *image, struct file_handle *file) {
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// We don't support bpp lower than 8
|
// We don't support bpp lower than 8
|
||||||
if (header.bi_bpp < 8)
|
if (header.bi_bpp % 8 != 0)
|
||||||
return -1;
|
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);
|
image->x_size = header.bi_width;
|
||||||
fread(file, local->image, header.bf_offset, header.bf_size);
|
image->y_size = header.bi_height;
|
||||||
|
image->pitch = ALIGN_UP(header.bi_width * header.bi_bpp, 32) / 8;
|
||||||
local->pitch = ALIGN_UP(header.bi_width * header.bi_bpp, 32) / 8;
|
image->bpp = header.bi_bpp;
|
||||||
local->header = header;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -74,17 +74,7 @@ void gterm_plot_px(int x, int y, uint32_t hex) {
|
|||||||
gterm_framebuffer[fb_i] = hex;
|
gterm_framebuffer[fb_i] = hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) {
|
static uint32_t blend_gradient_from_box(int x, int y, uint32_t bg_px, 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;
|
int distance, x_distance, y_distance;
|
||||||
|
|
||||||
if (x < frame_width)
|
if (x < frame_width)
|
||||||
@ -115,14 +105,100 @@ static uint32_t blend_gradient_from_box(int x, int y, uint32_t hex) {
|
|||||||
return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px);
|
return colour_blend((hex & 0xffffff) | (new_alpha << 24), bg_px);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gterm_generate_canvas(void) {
|
typedef int fixedp6; // the last 6 bits are the fixed point part
|
||||||
if (background) {
|
static int fixedp6_to_int(fixedp6 value) { return value / 64; }
|
||||||
for (int y = 0; y < gterm_height; y++) {
|
static fixedp6 int_to_fixedp6(int value) { return value * 64; }
|
||||||
for (int x = 0; x < gterm_width; x++) {
|
|
||||||
bg_canvas[y * gterm_width + x] = blend_gradient_from_box(x, y, ansi_colours[8]);
|
// Draw rect at coordinates, copying from the image to the fb and canvas, applying fn on every pixel
|
||||||
gterm_plot_px(x, y, bg_canvas[y * gterm_width + x]);
|
__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);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_internal(frame_width, frame_width_end, frame_height, frame_height_end);
|
||||||
} else {
|
} else {
|
||||||
for (int y = 0; y < gterm_height; y++) {
|
for (int y = 0; y < gterm_height; y++) {
|
||||||
for (int x = 0; x < gterm_width; x++) {
|
for (int x = 0; x < gterm_width; x++) {
|
||||||
|
@ -17,9 +17,6 @@ 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) {
|
void image_make_stretched(struct image *image, int new_x_size, int new_y_size) {
|
||||||
image->type = IMAGE_STRETCHED;
|
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->x_size = new_x_size;
|
||||||
image->y_size = new_y_size;
|
image->y_size = new_y_size;
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,14 @@ struct image {
|
|||||||
int x_size;
|
int x_size;
|
||||||
int y_size;
|
int y_size;
|
||||||
int type;
|
int type;
|
||||||
union {
|
uint8_t *img;
|
||||||
struct {
|
int bpp;
|
||||||
int x_displacement;
|
int pitch;
|
||||||
int y_displacement;
|
int img_width; // x_size = scaled size, img_width = bitmap size
|
||||||
};
|
int img_height;
|
||||||
struct {
|
int x_displacement;
|
||||||
int old_x_size;
|
int y_displacement;
|
||||||
int old_y_size;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
uint32_t back_colour;
|
uint32_t back_colour;
|
||||||
uint32_t (*get_pixel)(struct image *this, int x, int y);
|
|
||||||
void *local;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
Loading…
Reference in New Issue
Block a user