#![doc(
html_logo_url = "https://raw.githubusercontent.com/ggez/good-web-game/master/about/logo.png"
)]
pub mod audio;
pub mod conf;
pub mod error;
pub mod event;
pub mod filesystem;
pub mod goodies;
pub mod graphics;
pub mod input;
pub mod timer;
mod context;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
pub use crate::context::Context;
pub use crate::error::*;
pub use cgmath;
pub extern crate miniquad;
pub extern crate mint;
use crate::event::ErrorOrigin;
use crate::filesystem::Filesystem;
#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
use crate::input::gamepad::GamepadId;
use crate::input::mouse;
use miniquad::GraphicsContext;
#[cfg(feature = "log-impl")]
pub use miniquad::{debug, info, log, warn};
struct EventHandlerWrapper<E: std::error::Error> {
event_handler: Box<dyn event::EventHandler<E>>,
context: Context,
}
impl<E: std::error::Error> miniquad::EventHandler for EventHandlerWrapper<E> {
fn update(&mut self, quad_ctx: &mut GraphicsContext) {
if !self.context.continuing {
quad_ctx.order_quit();
std::thread::yield_now();
return;
}
self.context.timer_context.tick();
graphics::release_dropped_bindings();
#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
{
while let Some(gilrs::Event { id, event, .. }) =
self.context.gamepad_context.next_event()
{
match event {
gilrs::EventType::ButtonPressed(button, _) => {
self.event_handler.gamepad_button_down_event(
&mut self.context,
quad_ctx,
button,
GamepadId(id),
);
}
gilrs::EventType::ButtonReleased(button, _) => {
self.event_handler.gamepad_button_up_event(
&mut self.context,
quad_ctx,
button,
GamepadId(id),
);
}
gilrs::EventType::AxisChanged(axis, value, _) => {
self.event_handler.gamepad_axis_event(
&mut self.context,
quad_ctx,
axis,
value,
GamepadId(id),
);
}
_ => {}
}
}
}
if let Err(e) = self.event_handler.update(&mut self.context, quad_ctx) {
error!("Error on EventHandler::update(): {:?}", e); eprintln!("Error on EventHandler::update(): {:?}", e);
if self
.event_handler
.on_error(&mut self.context, quad_ctx, ErrorOrigin::Update, e)
{
event::quit(&mut self.context);
}
}
}
fn draw(&mut self, quad_ctx: &mut GraphicsContext) {
if let Err(e) = self.event_handler.draw(&mut self.context, quad_ctx) {
error!("Error on EventHandler::draw(): {:?}", e);
eprintln!("Error on EventHandler::draw(): {:?}", e);
if self
.event_handler
.on_error(&mut self.context, quad_ctx, ErrorOrigin::Draw, e)
{
event::quit(&mut self.context);
}
}
self.context.mouse_context.reset_delta();
}
fn resize_event(&mut self, quad_ctx: &mut GraphicsContext, width: f32, height: f32) {
self.event_handler
.resize_event(&mut self.context, quad_ctx, width, height);
}
fn mouse_motion_event(&mut self, quad_ctx: &mut GraphicsContext, x: f32, y: f32) {
self.context
.mouse_context
.input_handler
.handle_mouse_move(x, y);
let old_pos = mouse::last_position(&self.context);
let dx = x - old_pos.x;
let dy = y - old_pos.y;
let old_delta = mouse::delta(&self.context);
self.context
.mouse_context
.set_delta((old_delta.x + dx, old_delta.y + dy).into());
self.context.mouse_context.set_last_position((x, y).into());
self.event_handler
.mouse_motion_event(&mut self.context, quad_ctx, x, y, dx, dy);
}
fn mouse_button_down_event(
&mut self,
quad_ctx: &mut GraphicsContext,
button: miniquad::MouseButton,
x: f32,
y: f32,
) {
self.context
.mouse_context
.input_handler
.handle_mouse_down(button);
self.event_handler.mouse_button_down_event(
&mut self.context,
quad_ctx,
button.into(),
x,
y,
);
}
fn mouse_button_up_event(
&mut self,
quad_ctx: &mut GraphicsContext,
button: miniquad::MouseButton,
x: f32,
y: f32,
) {
self.context
.mouse_context
.input_handler
.handle_mouse_up(button);
self.event_handler
.mouse_button_up_event(&mut self.context, quad_ctx, button.into(), x, y);
}
fn char_event(
&mut self,
quad_ctx: &mut GraphicsContext,
character: char,
_keymods: miniquad::KeyMods,
_repeat: bool,
) {
self.event_handler
.text_input_event(&mut self.context, quad_ctx, character);
}
fn key_down_event(
&mut self,
quad_ctx: &mut GraphicsContext,
keycode: miniquad::KeyCode,
keymods: miniquad::KeyMods,
repeat: bool,
) {
self.context.keyboard_context.set_key(keycode, true);
self.event_handler.key_down_event(
&mut self.context,
quad_ctx,
keycode,
keymods.into(),
repeat,
);
}
fn key_up_event(
&mut self,
quad_ctx: &mut GraphicsContext,
keycode: miniquad::KeyCode,
keymods: miniquad::KeyMods,
) {
self.context.keyboard_context.set_key(keycode, false);
self.event_handler
.key_up_event(&mut self.context, quad_ctx, keycode, keymods.into());
}
fn touch_event(
&mut self,
quad_ctx: &mut GraphicsContext,
phase: miniquad::TouchPhase,
id: u64,
x: f32,
y: f32,
) {
self.event_handler
.touch_event(&mut self.context, quad_ctx, phase, id, x, y);
}
}
pub fn start<F, E>(conf: conf::Conf, f: F) -> GameResult
where
E: std::error::Error + 'static,
F: 'static
+ FnOnce(&mut Context, &mut miniquad::GraphicsContext) -> Box<dyn event::EventHandler<E>>,
{
let fs = Filesystem::new(&conf);
let quad_conf = conf.into();
miniquad::start(quad_conf, |ctx| {
let mut context = Context::new(ctx, fs);
let (d_w, d_h) = ctx.screen_size();
context
.gfx_context
.set_screen_coordinates(graphics::Rect::new(0., 0., d_w, d_h));
let event_handler = f(&mut context, ctx);
Box::new(EventHandlerWrapper {
event_handler,
context,
})
});
Ok(())
}