Add qemu auto-run to makefile, separate utils into a directory, add graphics support with rectangles, circles and triangles, double buffering (kind of) , and make example shapes on startup with an orange background.

This commit is contained in:
csd4ni3l
2026-03-13 23:00:27 +01:00
parent b80e6735cd
commit eeb1c6c701
8 changed files with 207 additions and 33 deletions

View File

@@ -213,6 +213,7 @@ ifeq ($(KARCH),loongarch64)
iso_root -o $(IMAGE_NAME).iso iso_root -o $(IMAGE_NAME).iso
endif endif
rm -rf iso_root rm -rf iso_root
qemu-system-$(KARCH) -cdrom $(IMAGE_NAME).iso -m 512M -serial stdio
$(IMAGE_NAME).hdd: limine/limine kernel $(IMAGE_NAME).hdd: limine/limine kernel
rm -f $(IMAGE_NAME).hdd rm -f $(IMAGE_NAME).hdd

7
kernel/Cargo.lock generated
View File

@@ -22,4 +22,11 @@ name = "limine-rust-template"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"limine", "limine",
"micromath",
] ]
[[package]]
name = "micromath"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815"

View File

@@ -5,3 +5,10 @@ edition = "2024"
[dependencies] [dependencies]
limine = "0.5" limine = "0.5"
micromath = "2.1.0"
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"

View File

@@ -1,25 +0,0 @@
use limine::framebuffer::Framebuffer;
pub fn rgb(r: u8, g: u8, b: u8) -> u32 {
((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
}
pub fn create_rect(framebuffer: &Framebuffer, x: u64, y: u64, width: u64, height: u64, color: u32) {
for fb_x in x..x+width {
for fb_y in y..y+height {
// Calculate the pixel offset using the framebuffer information we obtained above.
// We skip `i` scanlines (pitch is provided in bytes) and add `i * 4` to skip `i` pixels forward.
let bytes_per_pixel = framebuffer.bpp() as u64 / 8;
let pixel_offset = fb_y * framebuffer.pitch() + fb_x * bytes_per_pixel;
// Write 0xFFFFFFFF to the provided pixel offset to fill it white.
unsafe {
framebuffer
.addr()
.add(pixel_offset as usize)
.cast::<u32>()
.write(color)
};
}
}
}

View File

@@ -6,9 +6,9 @@ use core::arch::asm;
use limine::BaseRevision; use limine::BaseRevision;
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker}; use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker};
mod graphics; pub mod utils;
use crate::graphics::*;
use crate::utils::graphics::{Framebuffer, circle_filled, circle_outline, rectangle_filled, rectangle_outline, rgb, triangle_outline};
/// Sets the base revision to the latest revision supported by the crate. /// Sets the base revision to the latest revision supported by the crate.
/// See specification for further info. /// See specification for further info.
@@ -37,20 +37,26 @@ unsafe extern "C" fn kmain() -> ! {
assert!(BASE_REVISION.is_supported()); assert!(BASE_REVISION.is_supported());
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
if let Some(framebuffer) = framebuffer_response.framebuffers().next() { if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() {
graphics::create_rect(&framebuffer, 0, 0, framebuffer.width(), framebuffer.height(), graphics::rgb(253, 129, 0)); let mut fb = Framebuffer::new(&limine_framebuffer);
rectangle_filled(&mut fb, 0, 0, limine_framebuffer.width() as usize, limine_framebuffer.height() as usize, rgb(253, 129, 0));
rectangle_filled(&mut fb, 700, 400, 200, 200, rgb(0, 0, 0));
rectangle_outline(&mut fb, 400, 400, 100, 100, rgb(0, 0, 0));
circle_filled(&mut fb, 200, 200, 100.0, rgb(0, 0, 0));
circle_outline(&mut fb, 400, 200, 100.0, rgb(0, 0, 0));
triangle_outline(&mut fb, 100, 400, 200, 400, 150, 600, rgb(0, 0, 0));
} }
} }
hcf(); idle();
} }
#[panic_handler] #[panic_handler]
fn rust_panic(_info: &core::panic::PanicInfo) -> ! { fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
hcf(); idle();
} }
fn hcf() -> ! { fn idle() -> ! {
loop { loop {
unsafe { unsafe {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]

View File

@@ -0,0 +1,175 @@
use limine::framebuffer::Framebuffer as LimineFramebuffer;
use crate::utils::math::PI;
use micromath::F32Ext;
const MAX_BACKBUFFER_PIXELS: usize = 1920 * 1080;
static mut BACK_BUFFER: [u32; MAX_BACKBUFFER_PIXELS] = [0; MAX_BACKBUFFER_PIXELS];
pub fn rgb(r: u8, g: u8, b: u8) -> u32 {
((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
}
pub struct Framebuffer {
addr: *mut u32,
back_buffer: *mut u32,
width: usize,
height: usize,
pitch: usize,
back_buffer_len: usize,
}
impl Framebuffer {
pub fn new(limine_fb: &LimineFramebuffer) -> Framebuffer {
let width = limine_fb.width() as usize;
let height = limine_fb.height() as usize;
let pitch = limine_fb.pitch() as usize / 4;
let needed = pitch.saturating_mul(height);
let back_buffer_len = core::cmp::min(needed, MAX_BACKBUFFER_PIXELS);
Framebuffer {
addr: limine_fb.addr().cast::<u32>(),
back_buffer: core::ptr::addr_of_mut!(BACK_BUFFER).cast::<u32>(),
width,
height,
pitch,
back_buffer_len,
}
}
pub fn put_pixel(&mut self, x: usize, y: usize, color: u32) {
if x >= self.width || y >= self.height {
return;
}
let idx = y.saturating_mul(self.pitch).saturating_add(x);
if idx >= self.back_buffer_len {
return;
}
unsafe {
*self.back_buffer.add(idx) = color;
}
}
pub fn swap(&mut self) {
unsafe {
core::ptr::copy_nonoverlapping(self.back_buffer, self.addr, self.back_buffer_len);
}
}
}
pub fn line(framebuffer: &mut Framebuffer, mut x0: i64, mut y0: i64, x1: i64, y1: i64, color: u32) {
let mut dx = x1 - x0;
let mut dy = y1 - y0;
if dx < 0 {
dx = -dx;
}
if dy < 0 {
dy = -dy;
}
let step_x = if x0 < x1 {1} else {-1};
let step_y = if y0 < y1 {1} else {-1};
let mut error = dx - dy;
let mut e2: i64;
loop {
framebuffer.put_pixel(x0 as usize, y0 as usize, color);
if x0 == x1 && y0 == y1 {
break;
}
e2 = 2 * error;
if e2 > -dy {
error -= dy;
x0 += step_x;
}
if e2 < dx {
error += dx ;
y0 += step_y;
}
}
}
pub fn triangle_outline(framebuffer: &mut Framebuffer, x1: usize, y1: usize, x2: usize, y2: usize, x3: usize, y3: usize, color: u32) {
line(framebuffer, x1 as i64, y1 as i64, x2 as i64, y2 as i64, color);
line(framebuffer, x1 as i64, y1 as i64, x3 as i64, y3 as i64, color);
line(framebuffer, x2 as i64, y2 as i64, x3 as i64, y3 as i64, color);
framebuffer.swap();
}
pub fn circle_outline(framebuffer: &mut Framebuffer, x: usize, y: usize, radius: f32, color: u32) {
let mut i: f32 = 0.0;
loop {
i += 0.1;
let x1: f32 = radius * (i * PI / 180.0).cos();
let y1: f32 = radius * (i * PI / 180.0).sin();
framebuffer.put_pixel((x as f32 + x1) as usize, (y as f32 + y1) as usize, color);
if i >= 360.0 {
break
}
}
framebuffer.swap();
}
pub fn circle_filled(framebuffer: &mut Framebuffer, x0: usize, y0: usize, radius: f32, color: u32) {
let mut x = radius as i64;
let mut y: i64 = 0;
let mut x_change: i64 = 1 - (radius as i64 * 2);
let mut y_change: i64 = 0;
let mut radius_error: i64 = 0;
while x >= y {
let mut i = x0 as i64 - x;
while i <= x0 as i64 + x {
framebuffer.put_pixel(i as usize, (y0 as i64 + y) as usize, color);
framebuffer.put_pixel(i as usize, (y0 as i64 - y) as usize, color);
i += 1;
}
let mut i = x0 as i64 - y;
while i <= x0 as i64 + y {
framebuffer.put_pixel(i as usize, (y0 as i64 + x) as usize, color);
framebuffer.put_pixel(i as usize, (y0 as i64 - x) as usize, color);
i += 1;
}
y += 1;
radius_error += y_change;
y_change += 2;
if (radius_error * 2) + x_change > 0 {
x -= 1;
radius_error += x_change;
x_change += 2;
}
}
framebuffer.swap();
}
pub fn rectangle_filled(framebuffer: &mut Framebuffer, x: usize, y: usize, width: usize, height: usize, color: u32) {
for fb_x in x..x+width {
for fb_y in y..y+height {
framebuffer.put_pixel(fb_x, fb_y, color);
}
}
framebuffer.swap();
}
pub fn rectangle_outline(framebuffer: &mut Framebuffer, x: i64, y: i64, width: i64, height: i64, color: u32) {
line(framebuffer, x, y, x + width, y, color); // bottomleft -> bottomright
line(framebuffer, x, y + height, x + width, y + height, color); // topleft -> topright
line(framebuffer, x, y, x, y + height, color); // bottomleft -> topleft
line(framebuffer, x + width, y, x + width, y + height, color); // bottomright -> topright
framebuffer.swap();
}

1
kernel/src/utils/math.rs Normal file
View File

@@ -0,0 +1 @@
pub const PI: f32 = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; // we are just a bit accurate (the library definitely needs this btw)

2
kernel/src/utils/mod.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod math;
pub mod graphics;