/ src / main.rs
main.rs
  1  extern crate libremarkable;
  2  
  3  use libremarkable::appctx::ApplicationContext;
  4  use libremarkable::framebuffer::common::{color, display_temp, dither_mode, waveform_mode, DRAWING_QUANT_BIT};
  5  use libremarkable::framebuffer::PartialRefreshMode;
  6  use libremarkable::framebuffer::{FramebufferDraw, FramebufferRefresh};
  7  
  8  use std::{thread, time};
  9  use cgmath::{Point2, Vector2};
 10  use libremarkable::framebuffer::core::Framebuffer;
 11  use libremarkable::input::InputEvent::{MultitouchEvent, WacomEvent};
 12  
 13  use std::sync::{Arc, Mutex};
 14  use std::time::Duration;
 15  
 16  struct State {
 17      // points
 18      player_points: i32,
 19      enemy_points: i32,
 20  }
 21  
 22  struct BallMovementState {
 23      ball_pos: Point2<i32>,
 24      ball_speed_right: i32,
 25      ball_speed_up: i32,
 26  }
 27  
 28  fn main() {
 29      let mut app = ApplicationContext::default();
 30  
 31      hard_refresh(&mut app);
 32  
 33      //config /////////////////
 34      const SPEED_UP_RATE: i32 = 1;
 35      //////////////////////////
 36  
 37      // State
 38      let mut state = Arc::new(Mutex::new(State {
 39          player_points: 0,
 40          enemy_points: 0,
 41      }));
 42  
 43      let mut ball_pos = Point2 {x:100, y:100};
 44  
 45      // ball Movement
 46      let mut ball_state = Arc::new(Mutex::new(BallMovementState {
 47          ball_pos,
 48          ball_speed_right: 20,
 49          ball_speed_up: 20,
 50      }));
 51      // let mut ball_pos = Arc::new(Mutex::new(Point2 {x:100, y:100}));
 52      // let mut ball_speed_right = Arc::new(Mutex::new(20));
 53      // let mut ball_speed_up = Arc::new(Mutex::new(20));
 54  
 55      // finger platform movement
 56      let mut finger_cords = Point2 {x:0, y:0};
 57  
 58      // pen platform movement
 59      let mut pen_cords = Point2 {x:0, y:0};
 60  
 61      // framebuffer & Thread handles
 62      let mut fb = Arc::new(Mutex::new(app.get_framebuffer_ref()));
 63      let mut handles = vec![];
 64  
 65      app.clear(true);
 66      hard_refresh(&mut app);
 67  
 68      // Ball Thread
 69      // let ball_pos_ball_thread = ball_pos.clone();
 70      // let ball_speed_right_ball_thread = ball_speed_right.clone();
 71      // let ball_speed_up_ball_thread = ball_speed_up.clone();
 72      let ball_state_ball_thread = ball_state.clone();
 73      let state_ball_thread = state.clone();
 74      let fb_ball_thread = fb.clone();
 75      handles.push(thread::spawn(move || {
 76          println!("starting ball thread");
 77  
 78          let mut last_speedup = time::Instant::now();
 79          let mut last_update = time::Instant::now();
 80          let mut last_draw = time::Instant::now();
 81          let mut last_draw_pos = Point2 {x:0, y:0};
 82  
 83          loop {
 84              // let mut ball_speed_right = ball_speed_right_ball_thread.lock().unwrap();
 85              // let mut ball_speed_up = ball_speed_up_ball_thread.lock().unwrap();
 86  
 87              let mut ball_state = ball_state_ball_thread.lock().unwrap();
 88              let mut ball_speed_right = ball_state.ball_speed_right;
 89              let mut ball_speed_up = ball_state.ball_speed_up;
 90  
 91              // SpeedUp
 92              if time::Instant::now() - last_speedup > time::Duration::from_secs(10){
 93                  last_speedup = time::Instant::now();
 94                  if ball_speed_up > 0 { ball_speed_up += SPEED_UP_RATE}
 95                  else { ball_speed_up -= SPEED_UP_RATE }
 96  
 97                  if ball_speed_right > 0 { ball_speed_right += SPEED_UP_RATE}
 98                  else { ball_speed_right -= SPEED_UP_RATE }
 99  
100                  println!("SpeedUP!! x-speed: {}, y-speed: {}", ball_speed_right, ball_speed_up);
101              }
102  
103              //println!("{:?}", last_speedup);
104  
105              if time::Instant::now() - last_update > time::Duration::from_millis((500/ ball_speed_up).abs() as u64) {
106                  last_update = time::Instant::now();
107                  // let mut ball_pos = ball_pos_ball_thread.lock().unwrap();
108                  let ball_pos = ball_state.ball_pos;
109  
110                  let mut state = state_ball_thread.lock().unwrap();
111                  let mut fb = fb_ball_thread.lock().unwrap();
112  
113                  //println!("Ball at position before move: {}, {}", ball_pos.x, ball_pos.y);
114  
115                  // Move
116                  ball_state.ball_pos.x += (ball_speed_right / 2);
117                  ball_state.ball_pos.y += (ball_speed_up / 2);
118  
119                  // Handle collision
120                  handle_wall_collision(&mut ball_state, &mut state);
121                  // Draw ball
122                  if time::Instant::now() - last_draw > time::Duration::from_millis((1000/ ball_speed_up).abs() as u64) {
123                      last_draw = time::Instant::now();
124                      //println!("Drawing Ball at: {}, {}", ball_pos.x, ball_pos.y);
125                      last_draw_pos = draw_ball(&mut fb, last_draw_pos, ball_pos).clone();
126                  }
127              }
128          }
129      }));
130  
131      // points render thread
132      let state_points_render_thread = state.clone();
133      let fb_points_render_thread = fb.clone();
134      handles.push(thread::spawn(move || {
135          println!("starting render points thread");
136  
137          let mut last_update = time::Instant::now();
138          let mut old_state = State {
139              player_points: 1,
140              enemy_points: 1,
141          };
142          loop {
143              if time::Instant::now() - last_update > time::Duration::from_secs(1) {
144                  last_update = time::Instant::now();
145  
146                  let mut state = state_points_render_thread.lock().unwrap();
147                  println!("current state: {}, {}", state.player_points, state.enemy_points);
148                  if state.player_points == old_state.player_points && state.enemy_points == old_state.enemy_points { continue; }
149  
150                  old_state = State {
151                      player_points: state.player_points,
152                      enemy_points: state.enemy_points,
153                  };
154  
155                  let mut fb = fb_points_render_thread.lock().unwrap();
156  
157                  println!("rendering points!");
158                  render_points(*fb, &mut *state);
159              }
160          }
161      }));
162  
163      let ball_state_main = ball_state.clone();
164      let fb_main = fb.clone();
165      let mut last_update = time::Instant::now();
166      let mut last_draw_player = time::Instant::now();
167      let mut last_draw_enemy = time::Instant::now();
168      let mut last_drawn_cords_player = Point2 {x:0,y:0};
169      let mut last_drawn_cords_enemy = Point2 {x:0,y:0};
170      println!("starting main event loop!");
171      app.start_event_loop(true, true, false, |ctx, event| {
172          if time::Instant::now() - last_update > time::Duration::from_millis(10) {
173              last_update = time::Instant::now();
174              //println!("got event: {:?}", event);
175              // Input Handle
176              match event {
177                  MultitouchEvent { event: m_event } => {
178                      match handle_finger_input(m_event) {
179                          Some(cords) => {
180                              let mut ball_state = ball_state_main.lock().unwrap();
181                              let mut fb = fb_main.lock().unwrap();
182  
183                              finger_cords = cords;
184  
185                              //Draw enemy platform
186                              if time::Instant::now() - last_draw_enemy > time::Duration::from_millis(200) {
187                                  last_draw_enemy = time::Instant::now();
188                                  last_drawn_cords_enemy = draw_platform(finger_cords, last_drawn_cords_enemy, *fb, 210);
189                              }
190  
191                              handle_collision(&mut ball_state, pen_cords, finger_cords);
192                          },
193                          None => {}
194                      }
195                  }
196                  WacomEvent { event: w_event } => {
197                      //println!("got w_event, handling: {:?}", handle_pen_input(w_event));
198                      match handle_pen_input(w_event) {
199                          Some(cords) => {
200                              let mut ball_state = ball_state_main.lock().unwrap();
201                              let mut fb = fb_main.lock().unwrap();
202  
203                              pen_cords = cords;
204  
205                              // Draw player platform
206                              if time::Instant::now() - last_draw_player > time::Duration::from_millis(200) {
207                                  last_draw_player = time::Instant::now();
208                                  last_drawn_cords_player = draw_platform(pen_cords, last_drawn_cords_player, *fb, 1510);
209                              }
210  
211                              handle_collision(&mut ball_state, pen_cords, finger_cords);
212                          },
213                          None => {}
214                      }
215                  }
216                  _ => {}
217              }
218          }
219      });
220  
221      for handle in handles {
222          handle.join().unwrap();
223      }
224  }
225  
226  fn draw_platform(pen_pos: Point2<i32>, pen_last_pos: Point2<i32>, fb: &mut Framebuffer, height: i32) -> Point2<i32> {
227      let x = (pen_pos.x - 50) as i32;
228      let y = height;
229  
230      println!("drawing player platform");
231  
232      // turn white
233      if pen_last_pos.x - x > 5 || pen_last_pos.x - x < -5 && pen_last_pos.y != 0 {
234          let region = fb.draw_line(
235              pen_last_pos,
236              Point2{x: pen_last_pos.x+100, y},
237              10,
238              color::WHITE,
239          );
240  
241          refresh(fb, region, false);
242      }
243  
244      // turn black
245      let current_cords = cgmath::Point2 { x, y };
246  
247      let region = fb.draw_line(
248          current_cords,
249          Point2{x:x+100, y},
250          10,
251          color::BLACK,
252      );
253  
254      refresh(fb, region, false);
255  
256      return Point2{x,y}
257  }
258  
259  fn handle_wall_collision(ball_state: &mut BallMovementState, state: &mut State) {
260      let ball_pos = ball_state.ball_pos;
261      // walls
262      if ball_pos.x > libremarkable::dimensions::DISPLAYWIDTH as i32 - 5 || ball_pos.x < 5 {
263          println!("collision!! ball position: {}, {}", ball_pos.x, ball_pos.y);
264          ball_state.ball_speed_right *= -1;
265      }
266      if ball_pos.y > libremarkable::dimensions::DISPLAYHEIGHT as i32 - 5 || ball_pos.y < 5 {
267          println!("collision!! ball position: {}, {}", ball_pos.x, ball_pos.y);
268          ball_state.ball_speed_up *= -1;
269      }
270  
271      // goals - sets points
272      if ball_pos.y > libremarkable::dimensions::DISPLAYHEIGHT as i32 - 5 {
273          state.enemy_points += 1;
274      }
275      if ball_pos.y < 5 {
276          state.player_points += 1;
277      }
278  }
279  
280  fn handle_collision(ball_state: &mut BallMovementState, player_cords: Point2<i32>, enemy_cords: Point2<i32>) {
281      let ball_pos = ball_state.ball_pos;
282  
283      // player platform
284      if (ball_pos.x < player_cords.x + 80 && ball_pos.x > player_cords.x - 80) && (ball_pos.y > 1490 && ball_pos.y < 1510) {
285          ball_state.ball_speed_up *= -1;
286      }
287      // enemy platform
288      if (ball_pos.x < enemy_cords.x + 80 && ball_pos.x > enemy_cords.x - 80) && (ball_pos.y > 190 && ball_pos.y < 210) {
289          ball_state.ball_speed_up *= -1;
290      }
291  }
292  
293  fn handle_finger_input(event: libremarkable::input::MultitouchEvent) -> Option<Point2<i32>> {
294      match event {
295          libremarkable::input::MultitouchEvent::Move { finger: Finger } => {
296              //print!("(finger) x: {}, y: {}", Finger.pos.x, Finger.pos.y);
297  
298              let new_pos = Point2 {
299                  x: Finger.pos.x as i32,
300                  y: Finger.pos.y as i32,
301              };
302  
303              return Some(new_pos);
304          }
305          libremarkable::input::MultitouchEvent::Press { finger: Finger} => {
306              let new_pos = Point2 {
307                  x: Finger.pos.x as i32,
308                  y: Finger.pos.y as i32,
309              };
310  
311              return Some(new_pos);
312          }
313          _ => {}
314      }
315  
316      return None;
317  }
318  
319  fn handle_pen_input(event: libremarkable::input::WacomEvent) -> Option<Point2<i32>>{
320      //println!("handling event: {:?}", event);
321      match event {
322          libremarkable::input::WacomEvent::Hover {
323              position: cgmath::Point2 { x, y },
324              distance: u16,
325              tilt: _,
326          } => {
327              let new_position = Point2 {
328                  x: x as i32,
329                  y: y as i32
330              };
331  
332              return Some(new_position);
333          }
334          _  => {}
335      }
336  
337      return None;
338  }
339  
340  fn render_points(mut fb: &mut Framebuffer, state: &mut State) {
341      // enemy points
342      let region = fb.draw_text(
343          Point2{x:1300.0, y:100.0},
344          &(*state).enemy_points.to_string(),
345          50.0,
346          color::BLACK,
347          false,
348      );
349  
350      refresh(fb, region, true);
351  
352      // player points
353      let region = fb.draw_text(
354          Point2{x:100.0, y:1772.0},
355          &(*state).player_points.to_string(),
356          50.0,
357          color::BLACK,
358          false,
359      );
360  
361      refresh(fb, region, true);
362  }
363  
364  fn draw_ball (mut fb: &mut Framebuffer, last_ball_cords: Point2<i32>, ball_cords: Point2<i32>) -> Point2<i32> {
365      //println!("(ball) x: {}, y: {}", last_ball_cords.x, last_ball_cords.y);
366  
367      // turn white
368      let region = fb.fill_circle(
369          last_ball_cords,
370          10,
371          color::WHITE
372      );
373  
374      refresh(fb, region, false);
375  
376      // turn black
377      let region = fb.fill_circle(
378          ball_cords,
379          10,
380          color::BLACK
381      );
382  
383      refresh(fb, region, false);
384  
385      return ball_cords;
386  }
387  
388  fn refresh(fb: &mut libremarkable::framebuffer::core::Framebuffer, region: libremarkable::framebuffer::common::mxcfb_rect, force_full: bool) {
389      fb.partial_refresh(
390          &region,
391          PartialRefreshMode::Async,
392          // DU mode only supports black and white colors.
393          // See the documentation of the different waveform modes
394          // for more information
395          waveform_mode::WAVEFORM_MODE_DU,
396          display_temp::TEMP_USE_REMARKABLE_DRAW,
397          dither_mode::EPDC_FLAG_EXP1,
398          DRAWING_QUANT_BIT,
399          force_full,
400      );
401  }
402  
403  fn hard_refresh(app: &mut ApplicationContext) {
404      // fill with black
405      let fb = app.get_framebuffer_ref();
406      fb.fill_rect(
407          Point2{x:0,y:0},
408          Vector2{
409              x: libremarkable::dimensions::DISPLAYWIDTH as u32,
410              y: libremarkable::dimensions::DISPLAYHEIGHT as u32,
411          },
412          color::BLACK
413      );
414      fb.full_refresh(
415          // DU mode only supports black and white colors.
416          // See the documentation of the different waveform modes
417          // for more information
418          waveform_mode::WAVEFORM_MODE_DU,
419          display_temp::TEMP_USE_REMARKABLE_DRAW,
420          dither_mode::EPDC_FLAG_EXP1,
421          DRAWING_QUANT_BIT,
422          true,
423      );
424  
425      fb.fill_rect(
426          Point2{x:0,y:0},
427          Vector2{
428              x: libremarkable::dimensions::DISPLAYWIDTH as u32,
429              y: libremarkable::dimensions::DISPLAYHEIGHT as u32,
430          },
431          color::WHITE
432      );
433      fb.full_refresh(
434          // DU mode only supports black and white colors.
435          // See the documentation of the different waveform modes
436          // for more information
437          waveform_mode::WAVEFORM_MODE_DU,
438          display_temp::TEMP_USE_REMARKABLE_DRAW,
439          dither_mode::EPDC_FLAG_EXP1,
440          DRAWING_QUANT_BIT,
441          true,
442      );
443  }