#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
#![warn(missing_docs)]
use cfg_if::cfg_if;
use handler::AppHandler;
use std::sync::Arc;
use web_time::Duration;
use winit::{
event::Event,
event_loop::{ControlFlow, EventLoop},
window::{Window, WindowAttributes},
};
mod handler;
mod input;
pub use input::{Input, InputState};
pub use anyhow;
pub use winit;
#[derive(Debug)]
pub struct Context {
target_frame_time: Duration,
max_frame_time: Duration,
exit: bool,
delta_time: Duration,
pub input: Input,
pub window: Arc<Window>,
}
impl Context {
#[inline]
pub(crate) fn new(window: Arc<Window>, fps: u32, max_frame_time: Duration) -> Self {
Self {
target_frame_time: Duration::from_secs_f64(1. / fps as f64),
max_frame_time,
delta_time: Duration::ZERO,
exit: false,
input: Input::new(),
window,
}
}
#[inline]
pub fn frame_time(&self) -> Duration {
self.delta_time
}
#[inline]
pub fn set_target_frame_time(&mut self, time: Duration) {
self.target_frame_time = time;
}
#[inline]
pub fn set_target_fps(&mut self, fps: u32) {
self.target_frame_time = Duration::from_secs_f64(1. / fps as f64);
}
#[inline]
pub fn set_max_frame_time(&mut self, time: Duration) {
self.max_frame_time = time;
}
#[inline]
pub fn exit(&mut self) {
self.exit = true;
}
}
pub trait App {
fn update(&mut self, ctx: &mut Context) -> anyhow::Result<()>;
fn render(&mut self, blending_factor: f64) -> anyhow::Result<()>;
#[inline]
fn handle(&mut self, _event: Event<()>) -> anyhow::Result<()> {
Ok(())
}
}
pub fn start(
window_attributes: WindowAttributes,
fps: u32,
max_frame_time: Duration,
app: impl App + 'static,
) -> anyhow::Result<()> {
let event_loop = EventLoop::new()?;
event_loop.set_control_flow(ControlFlow::Poll);
#[cfg_attr(target_arch = "wasm32", allow(unused_mut))]
let mut handler = AppHandler::new(window_attributes, fps, max_frame_time, app);
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
use winit::platform::web::EventLoopExtWebSys;
event_loop.spawn_app(handler);
} else {
event_loop.run_app(&mut handler)?;
}
}
Ok(())
}