mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-04-25 11:49:03 +02:00
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:
@@ -213,6 +213,7 @@ ifeq ($(KARCH),loongarch64)
|
||||
iso_root -o $(IMAGE_NAME).iso
|
||||
endif
|
||||
rm -rf iso_root
|
||||
qemu-system-$(KARCH) -cdrom $(IMAGE_NAME).iso -m 512M -serial stdio
|
||||
|
||||
$(IMAGE_NAME).hdd: limine/limine kernel
|
||||
rm -f $(IMAGE_NAME).hdd
|
||||
|
||||
7
kernel/Cargo.lock
generated
7
kernel/Cargo.lock
generated
@@ -22,4 +22,11 @@ name = "limine-rust-template"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"limine",
|
||||
"micromath",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "micromath"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815"
|
||||
|
||||
@@ -5,3 +5,10 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
limine = "0.5"
|
||||
micromath = "2.1.0"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@ use core::arch::asm;
|
||||
use limine::BaseRevision;
|
||||
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker};
|
||||
|
||||
mod graphics;
|
||||
use crate::graphics::*;
|
||||
pub mod utils;
|
||||
|
||||
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.
|
||||
/// See specification for further info.
|
||||
@@ -37,20 +37,26 @@ unsafe extern "C" fn kmain() -> ! {
|
||||
assert!(BASE_REVISION.is_supported());
|
||||
|
||||
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
|
||||
if let Some(framebuffer) = framebuffer_response.framebuffers().next() {
|
||||
graphics::create_rect(&framebuffer, 0, 0, framebuffer.width(), framebuffer.height(), graphics::rgb(253, 129, 0));
|
||||
if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() {
|
||||
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]
|
||||
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
hcf();
|
||||
idle();
|
||||
}
|
||||
|
||||
fn hcf() -> ! {
|
||||
fn idle() -> ! {
|
||||
loop {
|
||||
unsafe {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
175
kernel/src/utils/graphics.rs
Normal file
175
kernel/src/utils/graphics.rs
Normal 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
1
kernel/src/utils/math.rs
Normal 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
2
kernel/src/utils/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod math;
|
||||
pub mod graphics;
|
||||
Reference in New Issue
Block a user