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
|
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
7
kernel/Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -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::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.
|
||||||
@@ -35,22 +35,28 @@ unsafe extern "C" fn kmain() -> ! {
|
|||||||
// All limine requests must also be referenced in a called function, otherwise they may be
|
// All limine requests must also be referenced in a called function, otherwise they may be
|
||||||
// removed by the linker.
|
// removed by the linker.
|
||||||
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")]
|
||||||
|
|||||||
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