diff options
| author | Bobby <[email protected]> | 2026-02-24 06:45:06 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-02-24 06:45:06 +0530 |
| commit | 297c66b480a238dad5ce7f03405fe6f5b9123701 (patch) | |
| tree | c034198726c68d011380a581b1c32282eb7a2420 /hikari/display/framebuffer.zig | |
| parent | 6a7363663f34a031f3138802eeab1d5e569a753d (diff) | |
| download | akiba-297c66b480a238dad5ce7f03405fe6f5b9123701.tar.xz akiba-297c66b480a238dad5ce7f03405fe6f5b9123701.zip | |
Implement Hikari Custom Boot Loader
Diffstat (limited to 'hikari/display/framebuffer.zig')
| -rw-r--r-- | hikari/display/framebuffer.zig | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/hikari/display/framebuffer.zig b/hikari/display/framebuffer.zig new file mode 100644 index 0000000..cf7c0ab --- /dev/null +++ b/hikari/display/framebuffer.zig @@ -0,0 +1,156 @@ +//! Hikari Framebuffer + +const efi = @import("../efi/efi.zig"); + +pub const Framebuffer = struct { + base: [*]u32, + width: u32, + height: u32, + stride: u32, + pixel_format: efi.types.graphics.PixelFormat, + + pub fn initialize(gop: *efi.protocols.GraphicsOutputProtocol) Framebuffer { + const mode = gop.mode; + const info = mode.info; + + return Framebuffer{ + .base = @ptrFromInt(mode.framebuffer_base), + .width = info.horizontal_resolution, + .height = info.vertical_resolution, + .stride = info.pixels_per_scan_line, + .pixel_format = info.pixel_format, + }; + } + + pub fn put_pixel(self: *Framebuffer, x: u32, y: u32, color: Color) void { + if (x >= self.width or y >= self.height) { + return; + } + + const offset = y * self.stride + x; + self.base[offset] = color.to_pixel(self.pixel_format); + } + + pub fn fill_rect(self: *Framebuffer, x: u32, y: u32, w: u32, h: u32, color: Color) void { + const pixel = color.to_pixel(self.pixel_format); + const x_end = if (x + w > self.width) self.width else x + w; + const y_end = if (y + h > self.height) self.height else y + h; + + var py = y; + while (py < y_end) : (py += 1) { + var px = x; + while (px < x_end) : (px += 1) { + const offset = py * self.stride + px; + self.base[offset] = pixel; + } + } + } + + pub fn clear(self: *Framebuffer, color: Color) void { + self.fill_rect(0, 0, self.width, self.height, color); + } + + pub fn draw_horizontal_line(self: *Framebuffer, x: u32, y: u32, length: u32, color: Color) void { + if (y >= self.height) { + return; + } + + const pixel = color.to_pixel(self.pixel_format); + const x_end = if (x + length > self.width) self.width else x + length; + const row_offset = y * self.stride; + + var px = x; + while (px < x_end) : (px += 1) { + self.base[row_offset + px] = pixel; + } + } + + pub fn draw_vertical_line(self: *Framebuffer, x: u32, y: u32, length: u32, color: Color) void { + if (x >= self.width) { + return; + } + + const pixel = color.to_pixel(self.pixel_format); + const y_end = if (y + length > self.height) self.height else y + length; + + var py = y; + while (py < y_end) : (py += 1) { + self.base[py * self.stride + x] = pixel; + } + } + + pub fn draw_rect(self: *Framebuffer, x: u32, y: u32, w: u32, h: u32, color: Color) void { + self.draw_horizontal_line(x, y, w, color); + self.draw_horizontal_line(x, y + h - 1, w, color); + self.draw_vertical_line(x, y, h, color); + self.draw_vertical_line(x + w - 1, y, h, color); + } + + pub fn copy_rect(self: *Framebuffer, src_x: u32, src_y: u32, dst_x: u32, dst_y: u32, w: u32, h: u32) void { + if (src_y < dst_y) { + var row: u32 = h; + while (row > 0) { + row -= 1; + self.copy_row(src_x, src_y + row, dst_x, dst_y + row, w); + } + } else { + var row: u32 = 0; + while (row < h) : (row += 1) { + self.copy_row(src_x, src_y + row, dst_x, dst_y + row, w); + } + } + } + + fn copy_row(self: *Framebuffer, src_x: u32, src_y: u32, dst_x: u32, dst_y: u32, w: u32) void { + const src_offset = src_y * self.stride + src_x; + const dst_offset = dst_y * self.stride + dst_x; + + if (src_x < dst_x) { + var i: u32 = w; + while (i > 0) { + i -= 1; + self.base[dst_offset + i] = self.base[src_offset + i]; + } + } else { + var i: u32 = 0; + while (i < w) : (i += 1) { + self.base[dst_offset + i] = self.base[src_offset + i]; + } + } + } +}; + +pub const Color = struct { + r: u8, + g: u8, + b: u8, + a: u8, + + pub fn rgb(r: u8, g: u8, b: u8) Color { + return Color{ .r = r, .g = g, .b = b, .a = 255 }; + } + + pub fn rgba(r: u8, g: u8, b: u8, a: u8) Color { + return Color{ .r = r, .g = g, .b = b, .a = a }; + } + + pub fn to_pixel(self: Color, format: efi.types.graphics.PixelFormat) u32 { + return switch (format) { + .rgb => (@as(u32, self.r) << 16) | (@as(u32, self.g) << 8) | self.b, + .bgr => (@as(u32, self.b) << 16) | (@as(u32, self.g) << 8) | self.r, + else => (@as(u32, self.r) << 16) | (@as(u32, self.g) << 8) | self.b, + }; + } + + pub const black = Color.rgb(0, 0, 0); + pub const white = Color.rgb(255, 255, 255); + pub const red = Color.rgb(255, 0, 0); + pub const green = Color.rgb(0, 255, 0); + pub const blue = Color.rgb(0, 0, 255); + pub const cyan = Color.rgb(0, 255, 255); + pub const magenta = Color.rgb(255, 0, 255); + pub const yellow = Color.rgb(255, 255, 0); + pub const gray = Color.rgb(128, 128, 128); + pub const dark_gray = Color.rgb(64, 64, 64); + pub const light_gray = Color.rgb(192, 192, 192); +}; |
