aboutsummaryrefslogtreecommitdiffstats
path: root/src/event_filter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/event_filter.rs')
-rw-r--r--src/event_filter.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/event_filter.rs b/src/event_filter.rs
new file mode 100644
index 0000000..9eb4620
--- /dev/null
+++ b/src/event_filter.rs
@@ -0,0 +1,107 @@
+use crate::cirque::TouchData;
+
+use core::{
+ cmp,
+ ops::Sub,
+};
+
+#[derive(Copy, Clone, Debug)]
+pub struct Point<T>(pub T, pub T);
+
+impl<T> Point<T>
+where
+ T: Sub<Output = T>,
+{
+ pub fn delta(self, p: Point<T>) -> Point<T> {
+ Point(p.0 - self.0, p.1 - self.1)
+ }
+}
+
+impl Point<isize> {
+ pub fn scale(self) -> Self {
+ Point(self.0 >> 2, self.1 >> 2)
+ }
+}
+
+impl From<&TouchData> for Point<isize> {
+ fn from(td: &TouchData) -> Self {
+ Self(td.x as _, td.y as _)
+ }
+}
+
+impl From<Point<isize>> for Point<i8> {
+ fn from(p: Point<isize>) -> Self {
+ Point(
+ cmp::min(i8::MAX as isize, cmp::max(p.0, i8::MIN as isize)) as i8,
+ cmp::min(i8::MAX as isize, cmp::max(p.1, i8::MIN as isize)) as i8,
+ )
+ }
+}
+
+pub struct AbsToRel {
+ last_touch: Point<isize>,
+ is_collecting: bool,
+}
+
+impl AbsToRel {
+ pub fn new() -> Self {
+ Self {
+ last_touch: Point(0, 0),
+ is_collecting: false,
+ }
+ }
+
+ pub fn update(&mut self, td: &TouchData) -> Option<Point<i8>> {
+ let p: Point<isize> = td.into();
+ let p = p.scale();
+
+ let res = self.last_touch.delta(p);
+ self.last_touch = p;
+ if self.is_collecting && td.is_pressed {
+ Some(res.into())
+ } else {
+ self.is_collecting = td.is_pressed;
+ None
+ }
+ }
+}
+
+pub struct TrackBall(Point<i8>, i8, u32);
+
+impl TrackBall
+where
+{
+ pub fn new(friction: i8) -> Self {
+ Self(Point(i8::default(), i8::default()), friction, 0)
+ }
+
+ pub fn update(&mut self, point: Option<Point<i8>>, elapsed: u32) -> Point<i8> {
+ if let Some(p) = point {
+ self.0 = p;
+ self.2 = 0;
+ } else {
+ let elapsed = elapsed + self.2;
+ // TODO: configure time divisor
+ let decel: i8 = self.1.saturating_mul((elapsed >> 15).try_into().unwrap_or(i8::MAX));
+ let rem = elapsed & (1 << 15) - 1;
+ self.2 = rem;
+
+ if decel > 0 {
+ let x = Self::abs_add(self.0.0, decel);
+ let y = Self::abs_add(self.0.1, decel);
+ self.0 = Point(x, y);
+ }
+ }
+ self.0
+ }
+
+ fn abs_add(speed: i8, decel: i8) -> i8 {
+ if speed > decel {
+ speed - decel
+ } else if speed < -decel {
+ speed + decel
+ } else {
+ 0
+ }
+ }
+}