diff options
author | fschildt <florian.schildt@protonmail.com> | 2025-08-22 15:23:11 +0200 |
---|---|---|
committer | fschildt <florian.schildt@protonmail.com> | 2025-08-22 15:23:11 +0200 |
commit | 2050c0e0576f05156f192aa4caf48834d2f28b14 (patch) | |
tree | ee58bd35b0df0a1bacfbc9700ed99ce80c99294e /src/client/draw.c |
Diffstat (limited to 'src/client/draw.c')
-rw-r--r-- | src/client/draw.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/client/draw.c b/src/client/draw.c new file mode 100644 index 0000000..b121b0e --- /dev/null +++ b/src/client/draw.c @@ -0,0 +1,174 @@ +#include "basic/string32.h" +#include "client/font.h" +#include <os/os.h> +#include <basic/math.h> +#include <client/draw.h> + +// @Nocommit +#include <stb/stb_image.h> +#include <stb/stb_image_write.h> + +void draw_rectf32(OSOffscreenBuffer *offscreen, RectF32 rect, V3F32 color) +{ + i32 xmin = f32_round_to_i32(rect.x0); + i32 ymin = f32_round_to_i32(rect.y0); + i32 xmax = f32_round_to_i32(rect.x1); + i32 ymax = f32_round_to_i32(rect.y1); + + if (xmin < 0) { + xmin = 0; + } + if (ymin < 0) { + ymin = 0; + } + if (xmax >= offscreen->width) { + xmax = offscreen->width - 1; + } + if (ymax >= offscreen->height) { + ymax = offscreen->height - 1; + } + + u8 rshift = offscreen->red_shift; + u8 gshift = offscreen->green_shift; + u8 bshift = offscreen->blue_shift; + for (i32 y = ymin; y <= ymax; y++) { + u32 *pixel = offscreen->pixels + y * offscreen->width + xmin; + for (i32 x = xmin; x <= xmax; x++) { + f32 r = color.x * 255.0; + f32 g = color.y * 255.0; + f32 b = color.z * 255.0; + u32 val = (u32)r << rshift | (u32)g << gshift | (u32)b << bshift; + *pixel++ = val; + } + } +} + +void draw_mono_bitmap(OSOffscreenBuffer *screen, V2F32 pos, Bitmap *bitmap, V3F32 color) +{ + i32 x0 = f32_round_to_i32(pos.x); + i32 y0 = f32_round_to_i32(pos.y); + i32 x1 = x0 + bitmap->width - 1; + i32 y1 = y0 + bitmap->height - 1; + + i32 cut_left = 0; + i32 cut_bot = 0; + + if (x0 < 0) { + cut_left = x0; + x0 = 0; + } + if (y0 < 0) { + cut_bot = y0; + y0 = 0; + } + if (x1 >= screen->width) { + x1 = screen->width - 1; + } + if (y1 >= screen->height) { + y1 = screen->height - 1; + } + + + u8 rshift = screen->red_shift; + u8 gshift = screen->green_shift; + u8 bshift = screen->blue_shift; + + u8 *grayscale = bitmap->data.grayscale + (-cut_bot * bitmap->width) + (-cut_left); + u32 *rgba = screen->pixels + y0 * screen->width + x0; + for (i32 y = y0; y <= y1; y++) { + u8 *alpha_row = grayscale; + u32 *pixel_row = rgba; + for (i32 x = x0; x <= x1; x++) { + f32 alpha = *alpha_row++ / 255.0; + + u32 pixel = *pixel_row; + f32 r0 = (pixel >> rshift) & 0xff; + f32 g0 = (pixel >> gshift) & 0xff; + f32 b0 = (pixel >> bshift) & 0xff; + + f32 r1 = r0 + (color.x - r0)*alpha; + f32 g1 = g0 + (color.y - g0)*alpha; + f32 b1 = b0 + (color.z - b0)*alpha; + + pixel = (u32)b1 << bshift | (u32)g1 << gshift | (u32)r1 << rshift; + *pixel_row++ = pixel; + } + grayscale += bitmap->width; + rgba += screen->width; + } +} + +void draw_border(OSOffscreenBuffer *screen, RectF32 rect, f32 size, V3F32 color) +{ + RectF32 draw_rect; + + // left + draw_rect.x0 = rect.x0; + draw_rect.y0 = rect.y0; + draw_rect.x1 = rect.x0 + size; + draw_rect.y1 = rect.y1; + draw_rectf32(screen, draw_rect, color); + + // bottom + draw_rect.x0 = rect.x0; + draw_rect.y0 = rect.y0; + draw_rect.x1 = rect.x1; + draw_rect.y1 = rect.y0 + size; + draw_rectf32(screen, draw_rect, color); + + // top + draw_rect.x0 = rect.x0; + draw_rect.y0 = rect.y1 - size; + draw_rect.x1 = rect.x1; + draw_rect.y1 = rect.y1; + draw_rectf32(screen, draw_rect, color); + + // right + draw_rect.x0 = rect.x1 - size; + draw_rect.y0 = rect.y0; + draw_rect.x1 = rect.x1; + draw_rect.y1 = rect.y1; + draw_rectf32(screen, draw_rect, color); +} + +void draw_cursor(OSOffscreenBuffer *screen, V2F32 pos, Font *font, String32 *str, u32 cursor) { + f32 width = font->scale; + f32 height = font->y_advance; + f32 xoff = font_get_string32_cursor_xoff(font, str, cursor); + V3F32 color = {0.0f, 0.0f, 0.0f}; + + pos.x += xoff; + + RectF32 rect = {pos.x, pos.y, pos.x + width, pos.y + height}; + draw_rectf32(screen, rect, color); +} + +void draw_string32(OSOffscreenBuffer *screen, V2F32 pos, String32 *str, Font *font) { + V3F32 color = v3f32(0, 0, 0); + + pos.y += font->baseline; + + for (int i = 0; i < str->len; i++) { + u32 c1 = str->codepoints[i]; + Glyph *glyph = font_get_glyph(font, c1); + + f32 draw_x = pos.x + glyph->xoff; + f32 draw_y = pos.y + glyph->yoff; + + if (c1 != ' ') { + Bitmap *mono_bitmap = &glyph->bitmap; + V2F32 draw_pos = v2f32(draw_x, draw_y); + draw_mono_bitmap(screen, draw_pos, mono_bitmap, color); + } + + u32 c2 = '\0'; + if (i < str->len -1) { + c2 = str->codepoints[i+1]; + } + f32 kern_advance = stbtt_GetCodepointKernAdvance(&font->info, c1, c2); + f32 advance_width = glyph->advance_width + kern_advance; + + pos.x += advance_width; + } +} + |