refactor: separate renderer code
This commit is contained in:
parent
fe61e12903
commit
2670e7d1da
7 changed files with 273 additions and 234 deletions
11
TODO.md
11
TODO.md
|
@ -16,13 +16,16 @@
|
||||||
- [x] 2024-06-28: oauth2 with oauth2c
|
- [x] 2024-06-28: oauth2 with oauth2c
|
||||||
- [x] 2024-06-29: generate changeset
|
- [x] 2024-06-29: generate changeset
|
||||||
- [x] 2024-07-01: upload changeset
|
- [x] 2024-07-01: upload changeset
|
||||||
- [ ] 2024-07-01: add success or error messages buffer
|
- [x] 2024-07-01: add success or error messages buffer
|
||||||
- [ ] 2024-07-01: refacto with clippy
|
- [x] 2024-07-01: refacto with clippy
|
||||||
- [ ] 2024-07-01: configure proxy via env variable
|
- [ ] refacto renderer
|
||||||
|
- [ ] vim-like commands sequence
|
||||||
|
- [ ] show every singular nodes
|
||||||
|
- [ ] create node
|
||||||
|
- [ ] configure proxy via env variable
|
||||||
- [ ] add basic CLI interface
|
- [ ] add basic CLI interface
|
||||||
- oauth2 status command
|
- oauth2 status command
|
||||||
- [ ] show icons on POI
|
- [ ] show icons on POI
|
||||||
- [ ] vim-like commands sequence
|
|
||||||
- [ ] vim-like text manual command bottom.
|
- [ ] vim-like text manual command bottom.
|
||||||
- `:Goto <coords>`
|
- `:Goto <coords>`
|
||||||
- `:Info`
|
- `:Info`
|
||||||
|
|
196
src/main.rs
196
src/main.rs
|
@ -13,25 +13,24 @@ use std::{collections::{HashMap, HashSet}, fs, process, sync::{Arc, Mutex}, thre
|
||||||
|
|
||||||
use anyhow::{Context, Result, anyhow};
|
use anyhow::{Context, Result, anyhow};
|
||||||
|
|
||||||
use data::{bbox_center, session::{read_session, write_session, Session}, IndexedData};
|
use data::{session::{read_session, write_session, Session}, IndexedData};
|
||||||
use fully_pub::fully_pub;
|
use fully_pub::fully_pub;
|
||||||
use layers::{load_osm_data, load_osm_zone, load_static_cities_layer, Layer, LayerKind};
|
use layers::{load_osm_data, load_osm_zone, load_static_cities_layer, Layer, LayerKind};
|
||||||
use osm_api::OSMApiClient;
|
use osm_api::OSMApiClient;
|
||||||
use raylib::prelude::*;
|
use raylib::prelude::*;
|
||||||
use ui::{edit_tags, inputs::{collect_actions_from_inputs, UiAction}, messages::{render_messages, UiMessage, UiMessageLevel}, selection::get_objects_in_area};
|
use ui::{edit_tags, inputs::{collect_actions_from_inputs, UiAction}, messages::{UiMessage, UiMessageLevel}, renderer::render_app, selection::get_objects_in_area};
|
||||||
use utils::{deg2num, get_envelope_from_bounds};
|
use utils::deg2num;
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use serde::{Deserialize};
|
use serde::Deserialize;
|
||||||
use ureq::Agent;
|
use ureq::Agent;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use crate::utils::CanvasPos;
|
|
||||||
use crate::utils::Invertion;
|
use crate::utils::Invertion;
|
||||||
use crate::utils::ToSlice;
|
use crate::utils::ToSlice;
|
||||||
|
|
||||||
pub const USER_AGENT: &str = "BobOSM dev";
|
pub const USER_AGENT: &str = "BobOSM dev";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
struct Camera {
|
struct Camera {
|
||||||
bounds: (Vector2, Vector2),
|
bounds: (Vector2, Vector2),
|
||||||
center: Vector2,
|
center: Vector2,
|
||||||
|
@ -41,6 +40,14 @@ struct Camera {
|
||||||
canvas_to_real_factor: f32
|
canvas_to_real_factor: f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[fully_pub]
|
||||||
|
struct AppContext {
|
||||||
|
/// snapshot of camera state
|
||||||
|
camera: Camera,
|
||||||
|
state: Arc<Mutex<AppState>>,
|
||||||
|
layers: Arc<Mutex<Vec<Layer>>>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
#[fully_pub]
|
#[fully_pub]
|
||||||
enum UiMode {
|
enum UiMode {
|
||||||
|
@ -270,7 +277,6 @@ fn main() -> Result<()> {
|
||||||
UiAction::NavigatePan(move_v) => {
|
UiAction::NavigatePan(move_v) => {
|
||||||
camera.bounds.0 += move_v;
|
camera.bounds.0 += move_v;
|
||||||
camera.bounds.1 += move_v;
|
camera.bounds.1 += move_v;
|
||||||
|
|
||||||
},
|
},
|
||||||
UiAction::NavigateZoom { focus, factor } => {
|
UiAction::NavigateZoom { focus, factor } => {
|
||||||
camera.bounds.0 = focus + (camera.bounds.0 - focus).scale_by(factor);
|
camera.bounds.0 = focus + (camera.bounds.0 - focus).scale_by(factor);
|
||||||
|
@ -347,177 +353,11 @@ fn main() -> Result<()> {
|
||||||
camera.zoom = 1.0/(camera.bounds.0.x - camera.bounds.1.x).abs();
|
camera.zoom = 1.0/(camera.bounds.0.x - camera.bounds.1.x).abs();
|
||||||
camera.map_zoom = 4.680_851*camera.zoom;
|
camera.map_zoom = 4.680_851*camera.zoom;
|
||||||
|
|
||||||
let mut d = rl.begin_drawing(&thread);
|
render_app(&mut rl, &thread, AppContext {
|
||||||
// d.draw_texture(&static_t, 0, 0, Color::WHITE);
|
state: app_state.clone(),
|
||||||
|
layers: layers.clone(),
|
||||||
d.clear_background(Color::BLACK);
|
camera: camera.clone()
|
||||||
// if let Some(texture) = tmp_texture {
|
})
|
||||||
// println!("{:?}", &texture);
|
|
||||||
// println!("center_canvas_pos {:?}", center_canvas_pos);
|
|
||||||
// d.draw_texture(texture, center_canvas_pos.x.ceil() as i32, center_canvas_pos.y.ceil() as i32, Color::WHITE);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Repère A: Canvas
|
|
||||||
// Repère B: Virtual canvas
|
|
||||||
// draw raster tiles
|
|
||||||
|
|
||||||
// render layers
|
|
||||||
let current_bounds_aabb = get_envelope_from_bounds(camera.bounds, 0.30);
|
|
||||||
{ // layers
|
|
||||||
let app_state_ref = app_state.lock().unwrap();
|
|
||||||
for (layer_i, layer) in layers.lock().unwrap().iter().enumerate() {
|
|
||||||
// Draw ways
|
|
||||||
if let Some(tree) = &layer.ways_tree {
|
|
||||||
for way in tree.locate_in_envelope_intersecting(¤t_bounds_aabb) {
|
|
||||||
let mut last_p: Option<Vector2> = None;
|
|
||||||
for p in &way.positions {
|
|
||||||
if let Some(last_p_v) = last_p {
|
|
||||||
d.draw_line_ex(
|
|
||||||
last_p_v.to_canvas_pos(&camera),
|
|
||||||
p.to_canvas_pos(&camera),
|
|
||||||
1.0,
|
|
||||||
Color::BLUE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
last_p = Some(*p);
|
|
||||||
}
|
|
||||||
let bbox_center_canvas = bbox_center(way.bbox).to_canvas_pos(&camera);
|
|
||||||
// draw name in center of polygon
|
|
||||||
if !way.name.is_empty() && (
|
|
||||||
(camera.zoom <= 0.9 && way.importance >= 10) ||
|
|
||||||
(camera.zoom >= 1.0 && way.importance >= 9) ||
|
|
||||||
camera.zoom >= 1.2
|
|
||||||
)
|
|
||||||
{
|
|
||||||
d.draw_text(
|
|
||||||
&way.name.to_string(),
|
|
||||||
bbox_center_canvas.x.ceil() as i32 - ((way.name.len()/2)*6) as i32,
|
|
||||||
bbox_center_canvas.y.ceil() as i32 - 5,
|
|
||||||
12,
|
|
||||||
Color::WHITE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw POI points of interest
|
|
||||||
if let Some(tree) = &layer.pois_tree {
|
|
||||||
for point in tree.locate_in_envelope(¤t_bounds_aabb) {
|
|
||||||
let canvas_pos = point.pos.to_canvas_pos(&camera);
|
|
||||||
let size = 2.0*(((1.)/(1.+ (-(0.4 * camera.zoom - 4.)).exp() )) + 0.2);
|
|
||||||
|
|
||||||
// check if object is selected.
|
|
||||||
let is_selected: bool =
|
|
||||||
if let Some(selected_elements) = app_state_ref.selected_elements_per_layer.get(layer_i) {
|
|
||||||
selected_elements.iter().any(|e_id| *e_id == point.id)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
let line_thickness: f32 =
|
|
||||||
(match point.importance {
|
|
||||||
10 => 5.,
|
|
||||||
9 => 3.,
|
|
||||||
_ => 3.0
|
|
||||||
}) +
|
|
||||||
(if is_selected { 4.0 } else { 0. });
|
|
||||||
|
|
||||||
let color = if is_selected {
|
|
||||||
Color::YELLOW
|
|
||||||
} else {
|
|
||||||
match point.importance {
|
|
||||||
10 => Color::GREEN,
|
|
||||||
9 => Color::RED,
|
|
||||||
3 => Color::PURPLE,
|
|
||||||
_ => Color::new(255, 255, 255, 100)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
d.draw_poly_lines_ex(
|
|
||||||
canvas_pos,
|
|
||||||
5,
|
|
||||||
match point.importance {
|
|
||||||
10 => size*19.,
|
|
||||||
9 => size*8.,
|
|
||||||
_ => size*3.0
|
|
||||||
},
|
|
||||||
0.,
|
|
||||||
line_thickness,
|
|
||||||
color
|
|
||||||
);
|
|
||||||
|
|
||||||
if
|
|
||||||
(camera.zoom <= 0.9 && point.importance >= 10) ||
|
|
||||||
(camera.zoom >= 1.0 && point.importance >= 9) ||
|
|
||||||
camera.zoom >= 1.2
|
|
||||||
{
|
|
||||||
d.draw_text(
|
|
||||||
&point.name.to_string(),
|
|
||||||
canvas_pos.x.ceil() as i32 + 8,
|
|
||||||
canvas_pos.y.ceil() as i32,
|
|
||||||
match point.importance {
|
|
||||||
10 => 17,
|
|
||||||
9 => 14,
|
|
||||||
_ => 12
|
|
||||||
},
|
|
||||||
Color::WHITE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.draw_circle_sector_lines(mouse_pos, 10.0, 0.0, 360.0, 1, Color::MAGENTA);
|
|
||||||
|
|
||||||
{
|
|
||||||
// draw meta/debug info
|
|
||||||
let app_state_ref = app_state.lock().unwrap();
|
|
||||||
d.draw_text(&format!("Zoom: {:?}, Bounds: {:?}", camera.zoom, camera.bounds), 13, 12, 15, Color::WHITE);
|
|
||||||
d.draw_text(&format!("Mouse: {:?}", real_mouse_pos), 13, 30, 15, Color::WHITE);
|
|
||||||
d.draw_text(&format!("Center: {:?}", camera.center), 13, 45, 15, Color::WHITE);
|
|
||||||
|
|
||||||
// draw app mode
|
|
||||||
d.draw_text(
|
|
||||||
&format!("M: {}",
|
|
||||||
match app_state_ref.ui_mode {
|
|
||||||
UiMode::View => "View",
|
|
||||||
UiMode::Edit => "Edit"
|
|
||||||
})
|
|
||||||
,
|
|
||||||
12, screen_def.1 - 50,
|
|
||||||
15,
|
|
||||||
Color::WHITE
|
|
||||||
);
|
|
||||||
// draw loading indicator
|
|
||||||
if app_state_ref.loading {
|
|
||||||
// TODO: add a sprite
|
|
||||||
d.draw_circle_v(
|
|
||||||
Vector2::new(20., (screen_def.1-20) as f32),
|
|
||||||
10.0,
|
|
||||||
Color::WHITE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw UI messages and alerts
|
|
||||||
render_messages(
|
|
||||||
&app_state_ref.messages,
|
|
||||||
&mut d,
|
|
||||||
&screen_def
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw target cross (center fixed cursor)
|
|
||||||
let cross_width = 6;
|
|
||||||
d.draw_line_v(
|
|
||||||
Vector2::new(((screen_def.0/2) - cross_width) as f32, (screen_def.1/2) as f32),
|
|
||||||
Vector2::new(((screen_def.0/2) + cross_width) as f32, (screen_def.1/2) as f32),
|
|
||||||
Color::WHITE
|
|
||||||
);
|
|
||||||
d.draw_line_v(
|
|
||||||
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) - cross_width) as f32),
|
|
||||||
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) + cross_width) as f32),
|
|
||||||
Color::WHITE
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,19 @@ enum UiAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_real_mouse_pos(
|
||||||
|
rl: &RaylibHandle,
|
||||||
|
camera: &Camera
|
||||||
|
) -> Vector2
|
||||||
|
{
|
||||||
|
let mouse_pos = rl.get_mouse_position();
|
||||||
|
let top_left_bound = Vector2::new(camera.bounds.0.x, camera.bounds.1.y);
|
||||||
|
top_left_bound +
|
||||||
|
mouse_pos
|
||||||
|
.invert_for_canvas()
|
||||||
|
.scale_by(camera.canvas_to_real_factor)
|
||||||
|
}
|
||||||
|
|
||||||
/// entry point to handle UI inputs
|
/// entry point to handle UI inputs
|
||||||
pub fn collect_actions_from_inputs(
|
pub fn collect_actions_from_inputs(
|
||||||
rl: &mut RaylibHandle,
|
rl: &mut RaylibHandle,
|
||||||
|
@ -101,12 +114,7 @@ pub fn collect_actions_from_inputs(
|
||||||
actions.push(UiAction::NavigatePan(move_v));
|
actions.push(UiAction::NavigatePan(move_v));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mouse_pos = rl.get_mouse_position();
|
let real_mouse_pos = get_real_mouse_pos(rl, &camera);
|
||||||
let top_left_bound = Vector2::new(camera.bounds.0.x, camera.bounds.1.y);
|
|
||||||
let real_mouse_pos = top_left_bound +
|
|
||||||
mouse_pos
|
|
||||||
.invert_for_canvas()
|
|
||||||
.scale_by(camera.canvas_to_real_factor);
|
|
||||||
let wheel_move = rl.get_mouse_wheel_move();
|
let wheel_move = rl.get_mouse_wheel_move();
|
||||||
if wheel_move.abs() > 0.0 {
|
if wheel_move.abs() > 0.0 {
|
||||||
actions.push(UiAction::NavigateZoom {
|
actions.push(UiAction::NavigateZoom {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use fully_pub::fully_pub;
|
use fully_pub::fully_pub;
|
||||||
use raylib::{color::Color, drawing::{RaylibDraw, RaylibDrawHandle}, math::Vector2};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[fully_pub]
|
#[fully_pub]
|
||||||
|
@ -48,7 +47,7 @@ impl UiMessage {
|
||||||
UiMessage::new(UiMessageLevel::Error, text)
|
UiMessage::new(UiMessageLevel::Error, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_dead(&self) -> bool {
|
pub fn is_dead(&self) -> bool {
|
||||||
let current_epoch = SystemTime::now()
|
let current_epoch = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.expect("Time went backwards")
|
.expect("Time went backwards")
|
||||||
|
@ -57,43 +56,3 @@ impl UiMessage {
|
||||||
(current_epoch - self.created_at) > self.ttl
|
(current_epoch - self.created_at) > self.ttl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_messages(
|
|
||||||
messages: &Vec<UiMessage>,
|
|
||||||
draw_handle: &mut RaylibDrawHandle,
|
|
||||||
screen_def: &(i32, i32)
|
|
||||||
) -> () {
|
|
||||||
let mut vertical_offset: i32 = 0;
|
|
||||||
for message in messages.iter().rev() {
|
|
||||||
if message.is_dead() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let text: &str = &message.text.to_string();
|
|
||||||
|
|
||||||
let padding = Vector2::new(10., 5.);
|
|
||||||
let pos: Vector2 = Vector2::new(
|
|
||||||
((screen_def.0/2) - 200) as f32,
|
|
||||||
(screen_def.1) as f32,
|
|
||||||
) + padding - Vector2::new(0., 40.0 + vertical_offset as f32);
|
|
||||||
|
|
||||||
draw_handle.draw_rectangle_v(
|
|
||||||
pos-padding,
|
|
||||||
Vector2::new(600.0 + 2.0*padding.x, 14.0 + 2.0*padding.y),
|
|
||||||
Color::WHITE
|
|
||||||
);
|
|
||||||
draw_handle.draw_text(
|
|
||||||
text,
|
|
||||||
pos.x as i32,
|
|
||||||
pos.y as i32,
|
|
||||||
16,
|
|
||||||
match message.level {
|
|
||||||
UiMessageLevel::Success => Color::GREEN,
|
|
||||||
UiMessageLevel::Warning => Color::ORANGE,
|
|
||||||
UiMessageLevel::Error => Color::RED,
|
|
||||||
_ => Color::GRAY
|
|
||||||
}
|
|
||||||
);
|
|
||||||
vertical_offset += 30;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
/// takes the pre-processed data to be rendered and turn it into vectors instructions sent to raylib
|
|
||||||
fn map_render() {
|
|
||||||
|
|
||||||
}
|
|
43
src/ui/renderer/messages.rs
Normal file
43
src/ui/renderer/messages.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use raylib::{color::Color, drawing::{RaylibDraw, RaylibDrawHandle}, math::Vector2};
|
||||||
|
|
||||||
|
use crate::ui::messages::{UiMessage, UiMessageLevel};
|
||||||
|
|
||||||
|
pub fn render_messages(
|
||||||
|
messages: &Vec<UiMessage>,
|
||||||
|
draw_handle: &mut RaylibDrawHandle,
|
||||||
|
screen_def: &(i32, i32)
|
||||||
|
) -> () {
|
||||||
|
let mut vertical_offset: i32 = 0;
|
||||||
|
for message in messages.iter().rev() {
|
||||||
|
if message.is_dead() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let text: &str = &message.text.to_string();
|
||||||
|
|
||||||
|
let padding = Vector2::new(10., 5.);
|
||||||
|
let pos: Vector2 = Vector2::new(
|
||||||
|
((screen_def.0/2) - 200) as f32,
|
||||||
|
(screen_def.1) as f32,
|
||||||
|
) + padding - Vector2::new(0., 40.0 + vertical_offset as f32);
|
||||||
|
|
||||||
|
draw_handle.draw_rectangle_v(
|
||||||
|
pos-padding,
|
||||||
|
Vector2::new(600.0 + 2.0*padding.x, 14.0 + 2.0*padding.y),
|
||||||
|
Color::WHITE
|
||||||
|
);
|
||||||
|
draw_handle.draw_text(
|
||||||
|
text,
|
||||||
|
pos.x as i32,
|
||||||
|
pos.y as i32,
|
||||||
|
16,
|
||||||
|
match message.level {
|
||||||
|
UiMessageLevel::Success => Color::GREEN,
|
||||||
|
UiMessageLevel::Warning => Color::ORANGE,
|
||||||
|
UiMessageLevel::Error => Color::RED,
|
||||||
|
_ => Color::GRAY
|
||||||
|
}
|
||||||
|
);
|
||||||
|
vertical_offset += 30;
|
||||||
|
}
|
||||||
|
}
|
190
src/ui/renderer/mod.rs
Normal file
190
src/ui/renderer/mod.rs
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
mod messages;
|
||||||
|
|
||||||
|
use messages::render_messages;
|
||||||
|
use raylib::{color::Color, drawing::RaylibDraw, math::Vector2, RaylibHandle, RaylibThread};
|
||||||
|
|
||||||
|
use crate::{data::bbox_center, utils::{get_envelope_from_bounds, CanvasPos}, AppContext, UiMode};
|
||||||
|
|
||||||
|
use super::inputs::get_real_mouse_pos;
|
||||||
|
|
||||||
|
/// render entry point
|
||||||
|
/// takes the pre-processed data to be rendered and turn it into vectors instructions sent to raylib
|
||||||
|
pub fn render_app(
|
||||||
|
rl: &mut RaylibHandle,
|
||||||
|
thread: &RaylibThread,
|
||||||
|
context: AppContext
|
||||||
|
) {
|
||||||
|
let camera = context.camera;
|
||||||
|
let screen_def = (rl.get_screen_width(), rl.get_screen_height());
|
||||||
|
let mouse_pos = rl.get_mouse_position();
|
||||||
|
let real_mouse_pos = get_real_mouse_pos(&rl, &camera);
|
||||||
|
|
||||||
|
let mut d = rl.begin_drawing(&thread);
|
||||||
|
// d.draw_texture(&static_t, 0, 0, Color::WHITE);
|
||||||
|
|
||||||
|
d.clear_background(Color::BLACK);
|
||||||
|
// if let Some(texture) = tmp_texture {
|
||||||
|
// println!("{:?}", &texture);
|
||||||
|
// println!("center_canvas_pos {:?}", center_canvas_pos);
|
||||||
|
// d.draw_texture(texture, center_canvas_pos.x.ceil() as i32, center_canvas_pos.y.ceil() as i32, Color::WHITE);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// render layers
|
||||||
|
let current_bounds_aabb = get_envelope_from_bounds(camera.bounds, 0.30);
|
||||||
|
{ // layers
|
||||||
|
let app_state_ref = context.state.lock().unwrap();
|
||||||
|
for (layer_i, layer) in context.layers.lock().unwrap().iter().enumerate() {
|
||||||
|
// Draw ways
|
||||||
|
if let Some(tree) = &layer.ways_tree {
|
||||||
|
for way in tree.locate_in_envelope_intersecting(¤t_bounds_aabb) {
|
||||||
|
let mut last_p: Option<Vector2> = None;
|
||||||
|
for p in &way.positions {
|
||||||
|
if let Some(last_p_v) = last_p {
|
||||||
|
d.draw_line_ex(
|
||||||
|
last_p_v.to_canvas_pos(&camera),
|
||||||
|
p.to_canvas_pos(&camera),
|
||||||
|
1.0,
|
||||||
|
Color::BLUE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
last_p = Some(*p);
|
||||||
|
}
|
||||||
|
let bbox_center_canvas = bbox_center(way.bbox).to_canvas_pos(&camera);
|
||||||
|
// draw name in center of polygon
|
||||||
|
if !way.name.is_empty() && (
|
||||||
|
(camera.zoom <= 0.9 && way.importance >= 10) ||
|
||||||
|
(camera.zoom >= 1.0 && way.importance >= 9) ||
|
||||||
|
camera.zoom >= 1.2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
d.draw_text(
|
||||||
|
&way.name.to_string(),
|
||||||
|
bbox_center_canvas.x.ceil() as i32 - ((way.name.len()/2)*6) as i32,
|
||||||
|
bbox_center_canvas.y.ceil() as i32 - 5,
|
||||||
|
12,
|
||||||
|
Color::WHITE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw POI points of interest
|
||||||
|
if let Some(tree) = &layer.pois_tree {
|
||||||
|
for point in tree.locate_in_envelope(¤t_bounds_aabb) {
|
||||||
|
let canvas_pos = point.pos.to_canvas_pos(&camera);
|
||||||
|
let size = 2.0*(((1.)/(1.+ (-(0.4 * camera.zoom - 4.)).exp() )) + 0.2);
|
||||||
|
|
||||||
|
// check if object is selected.
|
||||||
|
let is_selected: bool =
|
||||||
|
if let Some(selected_elements) = app_state_ref.selected_elements_per_layer.get(layer_i) {
|
||||||
|
selected_elements.iter().any(|e_id| *e_id == point.id)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let line_thickness: f32 =
|
||||||
|
(match point.importance {
|
||||||
|
10 => 5.,
|
||||||
|
9 => 3.,
|
||||||
|
_ => 3.0
|
||||||
|
}) +
|
||||||
|
(if is_selected { 4.0 } else { 0. });
|
||||||
|
|
||||||
|
let color = if is_selected {
|
||||||
|
Color::YELLOW
|
||||||
|
} else {
|
||||||
|
match point.importance {
|
||||||
|
10 => Color::GREEN,
|
||||||
|
9 => Color::RED,
|
||||||
|
3 => Color::PURPLE,
|
||||||
|
_ => Color::new(255, 255, 255, 100)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
d.draw_poly_lines_ex(
|
||||||
|
canvas_pos,
|
||||||
|
5,
|
||||||
|
match point.importance {
|
||||||
|
10 => size*19.,
|
||||||
|
9 => size*8.,
|
||||||
|
_ => size*3.0
|
||||||
|
},
|
||||||
|
0.,
|
||||||
|
line_thickness,
|
||||||
|
color
|
||||||
|
);
|
||||||
|
|
||||||
|
if
|
||||||
|
(camera.zoom <= 0.9 && point.importance >= 10) ||
|
||||||
|
(camera.zoom >= 1.0 && point.importance >= 9) ||
|
||||||
|
camera.zoom >= 1.2
|
||||||
|
{
|
||||||
|
d.draw_text(
|
||||||
|
&point.name.to_string(),
|
||||||
|
canvas_pos.x.ceil() as i32 + 8,
|
||||||
|
canvas_pos.y.ceil() as i32,
|
||||||
|
match point.importance {
|
||||||
|
10 => 17,
|
||||||
|
9 => 14,
|
||||||
|
_ => 12
|
||||||
|
},
|
||||||
|
Color::WHITE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw mouse cursor
|
||||||
|
d.draw_circle_sector_lines(mouse_pos, 10.0, 0.0, 360.0, 1, Color::MAGENTA);
|
||||||
|
{
|
||||||
|
// draw meta/debug info
|
||||||
|
let app_state_ref = context.state.lock().unwrap();
|
||||||
|
d.draw_text(&format!("Zoom: {:?}, Bounds: {:?}", camera.zoom, camera.bounds), 13, 12, 15, Color::WHITE);
|
||||||
|
d.draw_text(&format!("Mouse: {:?}", real_mouse_pos), 13, 30, 15, Color::WHITE);
|
||||||
|
d.draw_text(&format!("Center: {:?}", camera.center), 13, 45, 15, Color::WHITE);
|
||||||
|
|
||||||
|
// draw app mode
|
||||||
|
d.draw_text(
|
||||||
|
&format!("M: {}",
|
||||||
|
match app_state_ref.ui_mode {
|
||||||
|
UiMode::View => "View",
|
||||||
|
UiMode::Edit => "Edit"
|
||||||
|
})
|
||||||
|
,
|
||||||
|
12, screen_def.1 - 50,
|
||||||
|
15,
|
||||||
|
Color::WHITE
|
||||||
|
);
|
||||||
|
// draw loading indicator
|
||||||
|
if app_state_ref.loading {
|
||||||
|
// TODO: add a sprite
|
||||||
|
d.draw_circle_v(
|
||||||
|
Vector2::new(20., (screen_def.1-20) as f32),
|
||||||
|
10.0,
|
||||||
|
Color::WHITE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw UI messages and alerts
|
||||||
|
render_messages(
|
||||||
|
&app_state_ref.messages,
|
||||||
|
&mut d,
|
||||||
|
&screen_def
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw target cross (center fixed cursor)
|
||||||
|
let cross_width = 6;
|
||||||
|
d.draw_line_v(
|
||||||
|
Vector2::new(((screen_def.0/2) - cross_width) as f32, (screen_def.1/2) as f32),
|
||||||
|
Vector2::new(((screen_def.0/2) + cross_width) as f32, (screen_def.1/2) as f32),
|
||||||
|
Color::WHITE
|
||||||
|
);
|
||||||
|
d.draw_line_v(
|
||||||
|
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) - cross_width) as f32),
|
||||||
|
Vector2::new((screen_def.0/2) as f32, ((screen_def.1/2) + cross_width) as f32),
|
||||||
|
Color::WHITE
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in a new issue