schule-pong/src/main.rs

182 lines
6.3 KiB
Rust
Raw Normal View History

2024-02-22 13:01:00 +01:00
use engine::Engine;
2024-02-02 08:52:26 +01:00
fn main() {
2024-02-22 13:01:00 +01:00
Engine::new()
.set_render_fn(|mut ctx| {
// draw three colored rectagles(tm)
ctx.rect_unchecked(0, 0, 100, 100, 0xff0000);
ctx.rect_unchecked(100, 0, 100, 100, 0x00ff00);
ctx.rect_unchecked(0, 100, 100, 100, 0x0000ff);
2024-02-02 08:52:26 +01:00
})
2024-02-22 13:01:00 +01:00
.run();
2024-02-02 08:52:26 +01:00
}
2024-02-22 11:14:40 +01:00
2024-02-22 13:01:00 +01:00
mod engine {
const GAME_SIZE: (u32, u32) = (500, 800);
use std::{
num::NonZeroU32,
process,
time::{Duration, Instant},
};
2024-02-22 11:14:40 +01:00
use softbuffer::Buffer;
2024-02-22 13:01:00 +01:00
use winit::{
dpi::PhysicalSize,
event::{Event, KeyEvent, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop},
keyboard::{Key, NamedKey},
raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle, WindowHandle},
window::WindowBuilder,
};
type RenderFn = fn(&mut RenderCtx<'_, '_>);
// core game engine struct
pub struct Engine {
event_loop: EventLoop<()>,
render_fn: RenderFn,
2024-02-22 11:14:40 +01:00
}
2024-02-22 13:01:00 +01:00
impl Engine {
pub fn new() -> Self {
let event_loop = EventLoop::new().unwrap();
2024-02-22 11:14:40 +01:00
2024-02-22 13:01:00 +01:00
Self {
event_loop,
render_fn: |_| {},
}
2024-02-22 11:14:40 +01:00
}
2024-02-22 13:01:00 +01:00
// sets the render function for the game
pub fn set_render_fn(mut self, f: RenderFn) -> Self {
self.render_fn = f;
self
2024-02-22 11:14:40 +01:00
}
2024-02-22 13:01:00 +01:00
// runs the game and consumes self, this will finish the process
pub fn run(self) -> ! {
let Self {
event_loop,
render_fn,
} = self;
// set up window
let window = WindowBuilder::new()
.with_inner_size(winit::dpi::Size::Physical(PhysicalSize::new(1200, 700)))
.build(&event_loop)
.unwrap();
// set up softbuffer
let context = softbuffer::Context::new(window.display_handle().unwrap()).unwrap();
let mut surface =
softbuffer::Surface::new(&context, window.window_handle().unwrap()).unwrap();
event_loop
.run(|event, elwt| {
// shoddy vsync
elwt.set_control_flow(ControlFlow::WaitUntil(
Instant::now() + Duration::from_millis(1000 / 60),
));
match event {
// redraw
Event::NewEvents(StartCause::ResumeTimeReached {
start: _start,
requested_resume: _requested_resume,
}) => {
if let (Some(width), Some(height)) = {
let size = window.inner_size();
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
} {
surface.resize(width, height).unwrap();
let mut buffer = surface.buffer_mut().unwrap();
buffer.fill(0);
let mut ctx = RenderCtx::new(buffer, (width, height), GAME_SIZE);
// render
render_fn(&mut ctx);
ctx.force_present();
}
}
// crash game to exit lol
Event::WindowEvent {
window_id: _window_id,
event:
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
event:
KeyEvent {
logical_key: Key::Named(NamedKey::Escape),
..
},
..
},
} => todo!(),
// potential future keyboard handling
Event::WindowEvent {
window_id: _window_id,
event:
WindowEvent::KeyboardInput {
device_id: _device_id,
event: _event,
is_synthetic: _is_synthetic,
},
} => {}
_ => {}
}
})
.unwrap();
process::exit(0);
2024-02-22 11:14:40 +01:00
}
}
2024-02-22 13:01:00 +01:00
// render context
pub struct RenderCtx<'buf, 'win> {
buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>,
win_size: (u32, u32),
context_size: (u32, u32),
context_pos: (u32, u32),
2024-02-22 11:14:40 +01:00
}
2024-02-22 13:01:00 +01:00
impl<'buf, 'win> RenderCtx<'buf, 'win> {
// create new render context
pub fn new(
buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>,
2024-02-22 11:14:40 +01:00
win_size: (NonZeroU32, NonZeroU32),
2024-02-22 13:01:00 +01:00
context_size: (u32, u32),
) -> Self {
Self {
buffer,
win_size: (win_size.0.get(), win_size.1.get()),
context_size,
context_pos: (
(win_size.0.get() / 2).saturating_sub(context_size.0 / 2),
(win_size.1.get() / 2).saturating_sub(context_size.1 / 2),
2024-02-22 11:14:40 +01:00
),
2024-02-22 13:01:00 +01:00
}
2024-02-22 11:14:40 +01:00
}
2024-02-22 13:01:00 +01:00
// draw a rectangle in the context
//
// coordinates are relative to the context
pub fn rect_unchecked(&mut self, x: u32, y: u32, width: u32, height: u32, color: u32) {
// position in buffer coordinates and not relative coordinates
let x_buf_pos = self.context_pos.0 + x;
let y_buf_pos = self.context_pos.1 + y;
for y in y_buf_pos..(y_buf_pos + height) {
for x in x_buf_pos..(x_buf_pos + width) {
let index = y as usize * self.win_size.0 as usize + x as usize;
if let Some(px) = self.buffer.get_mut(index) {
*px = color
}
2024-02-22 11:14:40 +01:00
}
}
}
2024-02-22 13:01:00 +01:00
pub fn force_present(self) {
self.buffer.present().unwrap()
}
2024-02-22 11:14:40 +01:00
}
}