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