1use super::effect_source::{DistanceModel, EffectSource, EffectState, Magnitude};
9use super::time::{Repeat, Ticks, TICK_DURATION};
10
11use std::ops::{Deref, DerefMut};
12use std::sync::mpsc::{self, Receiver, Sender};
13use std::thread;
14use std::time::{Duration, Instant};
15
16use crate::gamepad::GamepadId;
17use crate::Event;
18use gilrs_core::FfDevice;
19
20use vec_map::VecMap;
21
22#[derive(Debug)]
23pub(crate) enum Message {
24 Create {
25 id: usize,
26 effect: Box<EffectSource>,
27 },
28 HandleCloned {
29 id: usize,
30 },
31 HandleDropped {
32 id: usize,
33 },
34 Play {
35 id: usize,
36 },
37 Stop {
38 id: usize,
39 },
40 Open {
41 id: usize,
42 device: FfDevice,
43 },
44 Close {
45 id: usize,
46 },
47 SetListenerPosition {
48 id: usize,
49 position: [f32; 3],
50 },
51 SetGamepads {
52 id: usize,
53 gamepads: VecMap<()>,
54 },
55 AddGamepad {
56 id: usize,
57 gamepad_id: GamepadId,
58 },
59 SetRepeat {
60 id: usize,
61 repeat: Repeat,
62 },
63 SetDistanceModel {
64 id: usize,
65 model: DistanceModel,
66 },
67 SetPosition {
68 id: usize,
69 position: [f32; 3],
70 },
71 SetGain {
72 id: usize,
73 gain: f32,
74 },
75}
76
77pub(crate) enum FfMessage {
78 EffectCompleted { event: Event },
79}
80
81impl Message {
82 fn use_trace_level(&self) -> bool {
84 use self::Message::*;
85
86 matches!(
87 self,
88 &SetListenerPosition { .. } | &HandleCloned { .. } | &HandleDropped { .. }
89 )
90 }
91}
92
93#[derive(Debug)]
94struct Device {
95 inner: FfDevice,
96 position: [f32; 3],
97}
98
99struct Effect {
100 source: EffectSource,
101 count: usize,
103}
104
105impl Effect {
106 fn inc(&mut self) -> usize {
107 self.count += 1;
108 self.count
109 }
110
111 fn dec(&mut self) -> usize {
112 self.count -= 1;
113 self.count
114 }
115}
116
117impl From<EffectSource> for Effect {
118 fn from(source: EffectSource) -> Self {
119 Effect { source, count: 1 }
120 }
121}
122
123impl Deref for Effect {
124 type Target = EffectSource;
125
126 fn deref(&self) -> &Self::Target {
127 &self.source
128 }
129}
130
131impl DerefMut for Effect {
132 fn deref_mut(&mut self) -> &mut Self::Target {
133 &mut self.source
134 }
135}
136
137impl From<FfDevice> for Device {
138 fn from(inner: FfDevice) -> Self {
139 Device {
140 inner,
141 position: [0.0, 0.0, 0.0],
142 }
143 }
144}
145
146pub(crate) fn run(tx: Sender<FfMessage>, rx: Receiver<Message>) {
147 let mut effects = VecMap::<Effect>::new();
148 let mut devices = VecMap::<Device>::new();
149 let sleep_dur = Duration::from_millis(TICK_DURATION.into());
150 let mut tick = Ticks(0);
151 let mut completion_events = Vec::<Event>::new();
152
153 loop {
154 let t1 = Instant::now();
155 while let Ok(ev) = rx.try_recv() {
156 if ev.use_trace_level() {
157 trace!("New ff event: {:?}", ev);
158 } else {
159 debug!("New ff event: {:?}", ev);
160 }
161
162 match ev {
163 Message::Create { id, effect } => {
164 effects.insert(id, (*effect).into());
165 }
166 Message::Play { id } => {
167 if let Some(effect) = effects.get_mut(id) {
168 effect.source.state = EffectState::Playing { since: tick }
169 } else {
170 error!("{:?} with wrong ID", ev);
171 }
172 }
173 Message::Stop { id } => {
174 if let Some(effect) = effects.get_mut(id) {
175 effect.source.state = EffectState::Stopped
176 } else {
177 error!("{:?} with wrong ID", ev);
178 }
179 }
180 Message::Open { id, device } => {
181 devices.insert(id, device.into());
182 }
183 Message::Close { id } => {
184 devices.remove(id);
185 }
186 Message::SetListenerPosition { id, position } => {
187 if let Some(device) = devices.get_mut(id) {
188 device.position = position;
189 } else {
190 error!("{:?} with wrong ID", ev);
191 }
192 }
193 Message::HandleCloned { id } => {
194 if let Some(effect) = effects.get_mut(id) {
195 effect.inc();
196 } else {
197 error!("{:?} with wrong ID", ev);
198 }
199 }
200 Message::HandleDropped { id } => {
201 let mut drop = false;
202 if let Some(effect) = effects.get_mut(id) {
203 if effect.dec() == 0 {
204 drop = true;
205 }
206 } else {
207 error!("{:?} with wrong ID", ev);
208 }
209
210 if drop {
211 effects.remove(id);
212 }
213 }
214 Message::SetGamepads { id, gamepads } => {
215 if let Some(eff) = effects.get_mut(id) {
216 eff.source.devices = gamepads;
217 } else {
218 error!("Invalid effect id {} when changing gamepads.", id);
219 }
220 }
221 Message::AddGamepad { id, gamepad_id } => {
222 if let Some(eff) = effects.get_mut(id) {
223 eff.source.devices.insert(gamepad_id.0, ());
224 } else {
225 error!("Invalid effect id {} when changing gamepads.", id);
226 }
227 }
228 Message::SetRepeat { id, repeat } => {
229 if let Some(eff) = effects.get_mut(id) {
230 eff.source.repeat = repeat;
231 } else {
232 error!("Invalid effect id {} when changing repeat mode.", id);
233 }
234 }
235 Message::SetDistanceModel { id, model } => {
236 if let Some(eff) = effects.get_mut(id) {
237 eff.source.distance_model = model;
238 } else {
239 error!("Invalid effect id {} when changing distance model.", id);
240 }
241 }
242 Message::SetPosition { id, position } => {
243 if let Some(eff) = effects.get_mut(id) {
244 eff.source.position = position;
245 } else {
246 error!("Invalid effect id {}.", id);
247 }
248 }
249 Message::SetGain { id, gain } => {
250 if let Some(eff) = effects.get_mut(id) {
251 eff.source.gain = gain;
252 } else {
253 error!("Invalid effect id {} when changing effect gain.", id);
254 }
255 }
256 }
257 }
258
259 combine_and_play(&mut effects, &mut devices, tick, &mut completion_events);
260 completion_events.iter().for_each(|ev| {
261 let _ = tx.send(FfMessage::EffectCompleted { event: *ev });
262 });
263 completion_events.clear();
264
265 let dur = Instant::now().duration_since(t1);
266 if dur > sleep_dur {
267 warn!(
269 "One iteration of a force feedback loop took more than {}ms!",
270 TICK_DURATION
271 );
272 } else {
273 thread::sleep(sleep_dur - dur);
274 }
275 tick.inc();
276 }
277}
278
279pub(crate) fn init() -> (Sender<Message>, Receiver<FfMessage>) {
280 let (tx, _rx) = mpsc::channel();
281 let (_tx2, rx2) = mpsc::channel();
282
283 #[cfg(not(target_arch = "wasm32"))]
285 std::thread::Builder::new()
286 .name("gilrs".to_owned())
287 .spawn(move || run(_tx2, _rx))
288 .expect("failed to spawn thread");
289
290 (tx, rx2)
291}
292
293fn combine_and_play(
294 effects: &mut VecMap<Effect>,
295 devices: &mut VecMap<Device>,
296 tick: Ticks,
297 completion_events: &mut Vec<Event>,
298) {
299 for (dev_id, dev) in devices {
300 let mut magnitude = Magnitude::zero();
301 for (_, ref mut effect) in effects.iter_mut() {
302 if effect.devices.contains_key(dev_id) {
303 magnitude += effect.combine_base_effects(tick, dev.position);
304 completion_events.extend(effect.flush_completion_events());
305 }
306 }
307 trace!(
308 "({:?}) Setting ff state of {:?} to {:?}",
309 tick,
310 dev,
311 magnitude
312 );
313 dev.inner.set_ff_state(
314 magnitude.strong,
315 magnitude.weak,
316 Duration::from_millis(u64::from(TICK_DURATION) * 2),
317 );
318 }
319}