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
|
|
|
}
|
|
|
|
}
|