sailor 0.1.0

A sailing navigation application.
mod drawing;
mod app_state;
mod stats;
mod config;

extern crate lyon;
extern crate nalgebra_glm as glm;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate serde_derive;


use osm::*;
use lyon::math::{
    vector,
};

use winit::{
    event::{
        Event,
        WindowEvent,
        ElementState,
        MouseButton,
        MouseScrollDelta,
        KeyboardInput,
        VirtualKeyCode,
    },
    event_loop::ControlFlow
};

use crate::config::CONFIG;

fn main() {
    log::set_max_level(CONFIG.general.log_level.to_level_filter());
    pretty_env_logger::init();

    let z = 8.0;
    let tile_coordinate = deg2num(47.3769, 8.5417, z as u32);
    let zurich = num_to_global_space(&tile_coordinate);

    let width = 1600;
    let height = 1000;

    let event_loop = winit::event_loop::EventLoop::new();
    let hdpi_factor = event_loop.available_monitors().next().expect("No monitors found").hidpi_factor();

    let mut app_state = app_state::AppState::new("config/style.css", zurich.clone(), width, height, z, hdpi_factor);

    let mut painter = drawing::Painter::init(&event_loop, width, height, &app_state);
    let mut hud = drawing::ui::HUD::new(&painter.window, &mut painter.device);

    let mut mouse_down = false;
    let mut last_pos = winit::dpi::LogicalPosition::new(0.0, 0.0);

    event_loop.run(move |event, _, control_flow| {
        *control_flow = if cfg!(feature = "metal-auto-capture") {
            ControlFlow::Exit
        } else {
            ControlFlow::Poll
        };
        let (route_mouse, route_keyboard) = hud.interact(&painter.window, &event);
        match event.clone() {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::Destroyed => {
                    *control_flow = ControlFlow::Exit;
                },
                WindowEvent::Resized(size) => {
                    let physical = size.to_physical(painter.get_hidpi_factor());
                    app_state.screen.width = physical.width.round() as u32;
                    app_state.screen.height = physical.height.round() as u32;
                    painter.resize(physical.width.round() as u32, physical.height.round() as u32);
                },
                WindowEvent::KeyboardInput {
                    input: KeyboardInput { virtual_keycode: Some(keycode), .. },
                    ..
                } => {
                    if route_keyboard {
                        match keycode {
                            VirtualKeyCode::Escape => {
                                *control_flow = ControlFlow::Exit;
                            },
                            VirtualKeyCode::Tab => app_state.advance_selected_object(),
                            _ => {}
                        }
                    }
                },
                WindowEvent::CloseRequested => {
                    *control_flow = ControlFlow::Exit;
                },
                WindowEvent::MouseInput { state, button, .. } => {
                    if route_mouse {
                        match button {
                            MouseButton::Left => {
                                match state {
                                    ElementState::Pressed => {
                                        mouse_down = true;
                                    },
                                    ElementState::Released => {
                                        mouse_down = false;
                                        app_state.update_selected_hover_objects();
                                    }
                                }
                            },
                            _ => {},
                        }
                    }
                },
                WindowEvent::MouseWheel { delta, .. } => {
                    if route_mouse {
                        match delta {
                            MouseScrollDelta::LineDelta(_x, y) => app_state.zoom += 0.1 * y,
                            _ => ()
                        }
                    }
                },
                WindowEvent::CursorMoved { position, .. } => {
                    let size = app_state.screen.get_tile_size() as f32;
                    let mut delta = vector((position.x - last_pos.x) as f32, (position.y - last_pos.y) as f32);
                    let zoom_x = (app_state.screen.width as f32) / size / 2f32.powf(app_state.zoom) / size / 2.0 / 1.3;
                    let zoom_y = (app_state.screen.height as f32) / size / 2f32.powf(app_state.zoom) / size / 2.0 / 1.3;
                    delta.x *= zoom_x;
                    delta.y *= zoom_y;

                    last_pos = position;

                    if route_mouse {
                        if mouse_down {
                            app_state.screen.center -= delta;
                        }

                        app_state.update_hovered_objects((position.x as f32, position.y as f32))
                    }
                },
                _ => (),
            },
            Event::EventsCleared => {
                painter.update_shader();
                app_state.load_tiles();
                painter.paint(&mut hud, &mut app_state);

                app_state.stats.capture_frame();
                if CONFIG.general.display_framerate {
                    println!("Frametime {:.2} at zoom {:.2}", app_state.stats.get_average(), app_state.zoom);
                }
            },
            _ => (),
        }
    });
}