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 ®ion, 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 }