202 lines
6.3 KiB
Rust
202 lines
6.3 KiB
Rust
// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
|
|
//
|
|
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
|
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
|
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
|
// copied, modified, or distributed except according to those terms.
|
|
|
|
use gilrs::ff::{BaseEffect, BaseEffectType, DistanceModel, EffectBuilder};
|
|
use gilrs::{Axis, Button, EventType, Gilrs};
|
|
|
|
use std::io::{self, Write};
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
enum Modify {
|
|
DistModel,
|
|
RefDistance,
|
|
RolloffFactor,
|
|
MaxDistance,
|
|
}
|
|
|
|
impl Modify {
|
|
fn next(&mut self) {
|
|
use crate::Modify::*;
|
|
*self = match *self {
|
|
DistModel => RefDistance,
|
|
RefDistance => RolloffFactor,
|
|
RolloffFactor => MaxDistance,
|
|
MaxDistance => DistModel,
|
|
};
|
|
print!("\x1b[2K\r{:?}", self);
|
|
io::stdout().flush().unwrap();
|
|
}
|
|
|
|
fn prev(&mut self) {
|
|
use crate::Modify::*;
|
|
*self = match *self {
|
|
DistModel => MaxDistance,
|
|
RefDistance => DistModel,
|
|
RolloffFactor => RefDistance,
|
|
MaxDistance => RolloffFactor,
|
|
};
|
|
print!("\x1b[2K\r{:?}", self);
|
|
io::stdout().flush().unwrap();
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
env_logger::init();
|
|
let mut gilrs = Gilrs::new().unwrap();
|
|
|
|
println!("Connected gamepads:");
|
|
|
|
let mut support_ff = Vec::new();
|
|
for (idx, gp) in gilrs.gamepads() {
|
|
let ff = gp.is_ff_supported();
|
|
println!(
|
|
"{}) {} ({})",
|
|
idx,
|
|
gp.name(),
|
|
if ff {
|
|
"Force feedback supported"
|
|
} else {
|
|
"Force feedback not supported"
|
|
}
|
|
);
|
|
if ff {
|
|
support_ff.push(idx);
|
|
}
|
|
}
|
|
|
|
println!("----------------------------------------");
|
|
println!(
|
|
"Use sticks to move listener. Triggers change properties of distance model. South/west \
|
|
button changes active property. Press east button on action pad to quit."
|
|
);
|
|
|
|
let pos1 = [-100.0, 0.0, 0.0];
|
|
|
|
let mut effect_builder = EffectBuilder::new()
|
|
.add_effect(BaseEffect {
|
|
kind: BaseEffectType::Strong { magnitude: 45_000 },
|
|
..Default::default()
|
|
})
|
|
.add_effect(BaseEffect {
|
|
kind: BaseEffectType::Weak { magnitude: 45_000 },
|
|
..Default::default()
|
|
})
|
|
.distance_model(DistanceModel::None)
|
|
.gamepads(&support_ff)
|
|
.clone();
|
|
|
|
let left_effect = effect_builder.position(pos1).finish(&mut gilrs).unwrap();
|
|
|
|
left_effect.play().unwrap();
|
|
|
|
println!("Playing one effects…");
|
|
println!("Position of effect sources: {:?}", pos1);
|
|
|
|
let mut listeners = support_ff
|
|
.iter()
|
|
.map(|&idx| (idx, [0.0, 0.0, 0.0]))
|
|
.collect::<Vec<_>>();
|
|
|
|
let mut ref_distance = 10.0;
|
|
let mut rolloff_factor = 0.5;
|
|
let mut max_distance = 100.0;
|
|
let mut modify = Modify::DistModel;
|
|
let mut model = 0usize;
|
|
|
|
'main: loop {
|
|
while let Some(event) = gilrs.next_event() {
|
|
match event.event {
|
|
EventType::ButtonReleased(Button::East, ..) => break 'main,
|
|
EventType::ButtonReleased(Button::South, ..) => modify.next(),
|
|
EventType::ButtonReleased(Button::West, ..) => modify.prev(),
|
|
EventType::ButtonReleased(Button::LeftTrigger, ..)
|
|
if modify == Modify::DistModel =>
|
|
{
|
|
model = model.wrapping_sub(1);
|
|
}
|
|
EventType::ButtonReleased(Button::RightTrigger, ..)
|
|
if modify == Modify::DistModel =>
|
|
{
|
|
model = model.wrapping_add(1);
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
for &mut (idx, ref mut pos) in &mut listeners {
|
|
let velocity = 0.5;
|
|
|
|
let gp = gilrs.gamepad(idx);
|
|
let (sx, sy) = (gp.value(Axis::LeftStickX), gp.value(Axis::LeftStickY));
|
|
|
|
if sx.abs() > 0.5 || sy.abs() > 0.5 {
|
|
if sx.abs() > 0.5 {
|
|
pos[0] += velocity * sx.signum();
|
|
}
|
|
if sy.abs() > 0.5 {
|
|
pos[1] += velocity * sy.signum();
|
|
}
|
|
|
|
gilrs.gamepad(idx).set_listener_position(*pos).unwrap();
|
|
|
|
let dist = ((pos[0] - pos1[0]).powi(2) + (pos[1] - pos1[1]).powi(2)).sqrt();
|
|
print!(
|
|
"\x1b[2K\rPosition of listener {:2} has changed: [{:6.1}, {:6.1}].Distance: \
|
|
{:.1}",
|
|
idx, pos[0], pos[1], dist
|
|
);
|
|
io::stdout().flush().unwrap();
|
|
}
|
|
|
|
let x = if gp.is_pressed(Button::LeftTrigger) {
|
|
-1.0
|
|
} else if gp.is_pressed(Button::RightTrigger) {
|
|
1.0
|
|
} else {
|
|
continue;
|
|
};
|
|
|
|
match modify {
|
|
Modify::RolloffFactor => rolloff_factor += x * velocity * 0.1,
|
|
Modify::RefDistance => ref_distance += x * velocity * 0.1,
|
|
Modify::MaxDistance => max_distance += x * velocity * 1.0,
|
|
Modify::DistModel => (), // DistanceModel handled in event loop
|
|
}
|
|
|
|
let model = match model % 4 {
|
|
0 => DistanceModel::None,
|
|
1 => DistanceModel::LinearClamped {
|
|
ref_distance,
|
|
rolloff_factor,
|
|
max_distance,
|
|
},
|
|
2 => DistanceModel::InverseClamped {
|
|
ref_distance,
|
|
rolloff_factor,
|
|
max_distance,
|
|
},
|
|
3 => DistanceModel::ExponentialClamped {
|
|
ref_distance,
|
|
rolloff_factor,
|
|
max_distance,
|
|
},
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
match left_effect.set_distance_model(model) {
|
|
Ok(()) => print!("\x1b[2K\r{:?}", model),
|
|
Err(e) => print!("\x1b[2K\r{}", e),
|
|
}
|
|
io::stdout().flush().unwrap();
|
|
}
|
|
|
|
thread::sleep(Duration::from_millis(16));
|
|
}
|
|
}
|