1use std::collections::HashSet;
8use std::time::Duration;
9
10use anyhow::Result;
11pub use repame_sim::{Sim, SimTime};
12pub use repame_sprite::{Camera2d, FrameInput, PickEvent, SpriteInstance};
13pub use repose_core::input::{GamepadEvent, GamepadId};
14use repose_platform::gamepad::{GamepadBackend, create_backend};
15
16pub trait ShellHooks {
19 fn frame_input(&mut self, sim: &Sim) -> FrameInput;
21 fn on_frame(&mut self, _sim: &mut Sim, _dt: Duration) {}
24}
25
26#[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))]
31pub fn run_desktop(
32 title: &str,
33 size: (u32, u32),
34 root: impl FnMut(
35 &mut repose_core::runtime::Scheduler,
36 &repose_core::RenderContext,
37 ) -> repose_core::View
38 + 'static,
39) -> Result<()> {
40 let config = repose_app::AppConfig {
41 window_title: title.to_string(),
42 window_size: size,
43 ..Default::default()
44 };
45 repose_platform::run_desktop_app_with_config(root, config)?;
46 Ok(())
47}
48
49#[cfg(target_arch = "wasm32")]
52pub fn run_web(
53 root: impl FnMut(
54 &mut repose_core::runtime::Scheduler,
55 &repose_core::RenderContext,
56 ) -> repose_core::View
57 + 'static,
58) -> Result<(), wasm_bindgen::JsValue> {
59 let mut options = repose_platform::web::WebOptions::new(None);
60 options.set_prevent_default(true);
61 repose_platform::web::run_web_app(root, options)
62}
63
64#[cfg(target_os = "android")]
67pub fn run_android(
68 app: winit::platform::android::activity::AndroidApp,
69 root: impl FnMut(
70 &mut repose_core::runtime::Scheduler,
71 &repose_core::RenderContext,
72 ) -> repose_core::View
73 + 'static,
74) -> Result<()> {
75 repose_platform::android::run_android_app_with_options(
76 app,
77 root,
78 repose_app::AndroidOptions::default(),
79 )
80}
81
82pub struct GamepadPoller {
87 backend: Option<Box<dyn GamepadBackend>>,
88 connected: HashSet<u32>,
89}
90
91impl GamepadPoller {
92 pub fn new() -> Self {
93 Self {
94 backend: create_backend().map(|b| Box::new(b) as Box<dyn GamepadBackend>),
95 connected: HashSet::new(),
96 }
97 }
98
99 pub fn poll(&mut self) -> Vec<GamepadEvent> {
103 let Some(backend) = &mut self.backend else {
104 return Vec::new();
105 };
106 let events = backend.poll();
107 for ev in &events {
108 match ev {
109 GamepadEvent::Connected { id, .. } => {
110 self.connected.insert(id.0);
111 }
112 GamepadEvent::Disconnected { id } => {
113 self.connected.remove(&id.0);
114 }
115 _ => {}
116 }
117 }
118 events
119 }
120
121 pub fn connected_ids(&self) -> Vec<GamepadId> {
122 self.connected.iter().copied().map(GamepadId).collect()
123 }
124
125 pub fn connected_count(&self) -> usize {
126 self.connected.len()
127 }
128}
129
130impl Default for GamepadPoller {
131 fn default() -> Self {
132 Self::new()
133 }
134}