mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 03:41:09 +03:00
revamp handling of onscreen stuff. no more callback plumbing, and can
plumb prerender successfully into dynamic stuff. just can't do as much work directly in DrawMap.
This commit is contained in:
parent
bc4ba647bc
commit
61d1d2fe83
@ -2,9 +2,9 @@
|
||||
|
||||
## Performance
|
||||
|
||||
- cache draw stuff
|
||||
- use a Drawable in DrawPed/DrawCar/DrawBike.
|
||||
- fix the process_objects callback nonsense
|
||||
- cache draw agents
|
||||
- dont use traits for things... or move code back to DrawMap after all.
|
||||
- actually use Drawables in the places
|
||||
|
||||
## Quick n easy
|
||||
|
||||
|
@ -7,10 +7,9 @@ use crate::render::extra_shape::{DrawExtraShape, ExtraShapeID};
|
||||
use crate::render::intersection::DrawIntersection;
|
||||
use crate::render::lane::DrawLane;
|
||||
use crate::render::parcel::DrawParcel;
|
||||
use crate::render::pedestrian::DrawPedestrian;
|
||||
use crate::render::turn::DrawTurn;
|
||||
use crate::render::{draw_vehicle, Renderable};
|
||||
use crate::state::{Flags, ShowObjects};
|
||||
use crate::render::Renderable;
|
||||
use crate::state::Flags;
|
||||
use aabb_quadtree::QuadTree;
|
||||
use abstutil::Timer;
|
||||
use ezgui::Prerender;
|
||||
@ -19,17 +18,11 @@ use map_model::{
|
||||
AreaID, BuildingID, BusStopID, FindClosest, IntersectionID, Lane, LaneID, Map, ParcelID,
|
||||
RoadID, Traversable, Turn, TurnID, LANE_THICKNESS,
|
||||
};
|
||||
use sim::{GetDrawAgents, Tick};
|
||||
use sim::Tick;
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum RenderOrder {
|
||||
BackToFront,
|
||||
FrontToBack,
|
||||
}
|
||||
|
||||
pub struct DrawMap {
|
||||
pub lanes: Vec<DrawLane>,
|
||||
pub intersections: Vec<DrawIntersection>,
|
||||
@ -40,7 +33,8 @@ pub struct DrawMap {
|
||||
pub bus_stops: HashMap<BusStopID, DrawBusStop>,
|
||||
pub areas: Vec<DrawArea>,
|
||||
|
||||
agents: RefCell<AgentCache>,
|
||||
// TODO Move?
|
||||
pub agents: RefCell<AgentCache>,
|
||||
|
||||
quadtree: QuadTree<ID>,
|
||||
}
|
||||
@ -271,123 +265,23 @@ impl DrawMap {
|
||||
results
|
||||
}
|
||||
|
||||
// False from the callback means abort
|
||||
pub fn handle_objects<T: ShowObjects, F: FnMut(Box<&Renderable>) -> bool>(
|
||||
&self,
|
||||
screen_bounds: Bounds,
|
||||
map: &Map,
|
||||
sim: &GetDrawAgents,
|
||||
show_objs: &T,
|
||||
order: RenderOrder,
|
||||
mut callback: F,
|
||||
) {
|
||||
// From background to foreground Z-order
|
||||
let mut areas: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut parcels: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut lanes: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut intersections: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut buildings: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut extra_shapes: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut bus_stops: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut turn_icons: Vec<Box<&Renderable>> = Vec::new();
|
||||
// We can't immediately grab the Renderables; we need to do it all at once at the end.
|
||||
let mut agents_on: Vec<Traversable> = Vec::new();
|
||||
|
||||
for &(id, _, _) in &self.quadtree.query(screen_bounds.as_bbox()) {
|
||||
if show_objs.show(*id) {
|
||||
match id {
|
||||
ID::Area(id) => areas.push(Box::new(self.get_a(*id))),
|
||||
ID::Parcel(id) => parcels.push(Box::new(self.get_p(*id))),
|
||||
ID::Lane(id) => {
|
||||
lanes.push(Box::new(self.get_l(*id)));
|
||||
if !show_objs.show_icons_for(map.get_l(*id).dst_i) {
|
||||
let on = Traversable::Lane(*id);
|
||||
if !self.agents.borrow().has(sim.tick(), on) {
|
||||
let mut list: Vec<Box<Renderable>> = Vec::new();
|
||||
for c in sim.get_draw_cars(on, map).into_iter() {
|
||||
list.push(draw_vehicle(c, map));
|
||||
}
|
||||
for p in sim.get_draw_peds(on, map).into_iter() {
|
||||
list.push(Box::new(DrawPedestrian::new(p, map)));
|
||||
}
|
||||
self.agents.borrow_mut().put(sim.tick(), on, list);
|
||||
}
|
||||
agents_on.push(on);
|
||||
}
|
||||
}
|
||||
ID::Intersection(id) => {
|
||||
intersections.push(Box::new(self.get_i(*id)));
|
||||
for t in &map.get_i(*id).turns {
|
||||
if show_objs.show_icons_for(*id) {
|
||||
turn_icons.push(Box::new(self.get_t(*t)));
|
||||
} else {
|
||||
let on = Traversable::Turn(*t);
|
||||
if !self.agents.borrow().has(sim.tick(), on) {
|
||||
let mut list: Vec<Box<Renderable>> = Vec::new();
|
||||
for c in sim.get_draw_cars(on, map).into_iter() {
|
||||
list.push(draw_vehicle(c, map));
|
||||
}
|
||||
for p in sim.get_draw_peds(on, map).into_iter() {
|
||||
list.push(Box::new(DrawPedestrian::new(p, map)));
|
||||
}
|
||||
self.agents.borrow_mut().put(sim.tick(), on, list);
|
||||
}
|
||||
agents_on.push(on);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO front paths will get drawn over buildings, depending on quadtree order.
|
||||
// probably just need to make them go around other buildings instead of having
|
||||
// two passes through buildings.
|
||||
ID::Building(id) => buildings.push(Box::new(self.get_b(*id))),
|
||||
ID::ExtraShape(id) => extra_shapes.push(Box::new(self.get_es(*id))),
|
||||
ID::BusStop(id) => bus_stops.push(Box::new(self.get_bs(*id))),
|
||||
|
||||
ID::Turn(_) | ID::Car(_) | ID::Pedestrian(_) | ID::Trip(_) => {
|
||||
panic!("{:?} shouldn't be in the quadtree", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut borrows: Vec<Box<&Renderable>> = Vec::new();
|
||||
borrows.extend(areas);
|
||||
borrows.extend(parcels);
|
||||
borrows.extend(lanes);
|
||||
borrows.extend(intersections);
|
||||
borrows.extend(buildings);
|
||||
borrows.extend(extra_shapes);
|
||||
borrows.extend(bus_stops);
|
||||
borrows.extend(turn_icons);
|
||||
let cache = self.agents.borrow();
|
||||
for on in agents_on {
|
||||
for obj in cache.get(on) {
|
||||
borrows.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a stable sort.
|
||||
borrows.sort_by_key(|r| r.get_zorder());
|
||||
|
||||
if order == RenderOrder::FrontToBack {
|
||||
borrows.reverse();
|
||||
}
|
||||
|
||||
for r in borrows {
|
||||
if !callback(r) {
|
||||
break;
|
||||
}
|
||||
// Unsorted, unexpanded, raw result.
|
||||
pub fn get_matching_objects(&self, bounds: Bounds) -> Vec<ID> {
|
||||
let mut results: Vec<ID> = Vec::new();
|
||||
for &(id, _, _) in &self.quadtree.query(bounds.as_bbox()) {
|
||||
results.push(*id);
|
||||
}
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
struct AgentCache {
|
||||
pub struct AgentCache {
|
||||
tick: Option<Tick>,
|
||||
agents_per_on: HashMap<Traversable, Vec<Box<Renderable>>>,
|
||||
}
|
||||
|
||||
impl AgentCache {
|
||||
fn has(&self, tick: Tick, on: Traversable) -> bool {
|
||||
pub fn has(&self, tick: Tick, on: Traversable) -> bool {
|
||||
if Some(tick) != self.tick {
|
||||
return false;
|
||||
}
|
||||
@ -395,14 +289,14 @@ impl AgentCache {
|
||||
}
|
||||
|
||||
// Must call has() first.
|
||||
fn get(&self, on: Traversable) -> Vec<Box<&Renderable>> {
|
||||
pub fn get(&self, on: Traversable) -> Vec<Box<&Renderable>> {
|
||||
self.agents_per_on[&on]
|
||||
.iter()
|
||||
.map(|obj| Box::new(obj.borrow()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn put(&mut self, tick: Tick, on: Traversable, agents: Vec<Box<Renderable>>) {
|
||||
pub fn put(&mut self, tick: Tick, on: Traversable, agents: Vec<Box<Renderable>>) {
|
||||
if Some(tick) != self.tick {
|
||||
self.agents_per_on.clear();
|
||||
self.tick = Some(tick);
|
||||
|
@ -11,6 +11,7 @@ mod parcel;
|
||||
mod pedestrian;
|
||||
mod turn;
|
||||
|
||||
use crate::colors::ColorScheme;
|
||||
use crate::objects::{Ctx, ID};
|
||||
pub use crate::render::area::DrawArea;
|
||||
use crate::render::bike::DrawBike;
|
||||
@ -18,10 +19,10 @@ use crate::render::car::DrawCar;
|
||||
pub use crate::render::extra_shape::ExtraShapeID;
|
||||
pub use crate::render::intersection::{draw_signal_cycle, draw_signal_diagram};
|
||||
pub use crate::render::lane::DrawLane;
|
||||
pub use crate::render::map::{DrawMap, RenderOrder};
|
||||
pub use crate::render::map::DrawMap;
|
||||
pub use crate::render::pedestrian::DrawPedestrian;
|
||||
pub use crate::render::turn::{DrawCrosswalk, DrawTurn};
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use ezgui::{Color, GfxCtx, Prerender};
|
||||
use geom::{Bounds, Distance, Pt2D};
|
||||
use map_model::Map;
|
||||
use sim::{DrawCarInput, VehicleType};
|
||||
@ -61,6 +62,15 @@ pub struct RenderOptions {
|
||||
pub show_all_detail: bool,
|
||||
}
|
||||
|
||||
pub fn new_draw_vehicle(
|
||||
input: DrawCarInput,
|
||||
map: &Map,
|
||||
_prerender: &Prerender,
|
||||
_cs: &ColorScheme,
|
||||
) -> Box<Renderable> {
|
||||
draw_vehicle(input, map)
|
||||
}
|
||||
|
||||
pub fn draw_vehicle(input: DrawCarInput, map: &Map) -> Box<Renderable> {
|
||||
if input.vehicle_type == VehicleType::Bike {
|
||||
Box::new(DrawBike::new(input))
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::colors::ColorScheme;
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::render::{RenderOptions, Renderable};
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use ezgui::{Color, GfxCtx, Prerender};
|
||||
use geom::{Bounds, Circle, Distance, Line, Pt2D};
|
||||
use map_model::Map;
|
||||
use sim::{DrawPedestrianInput, PedestrianID};
|
||||
@ -16,6 +17,15 @@ pub struct DrawPedestrian {
|
||||
}
|
||||
|
||||
impl DrawPedestrian {
|
||||
pub fn new_new(
|
||||
input: DrawPedestrianInput,
|
||||
map: &Map,
|
||||
_prerender: &Prerender,
|
||||
_cs: &ColorScheme,
|
||||
) -> DrawPedestrian {
|
||||
DrawPedestrian::new(input, map)
|
||||
}
|
||||
|
||||
pub fn new(input: DrawPedestrianInput, map: &Map) -> DrawPedestrian {
|
||||
let turn_arrow = if let Some(t) = input.waiting_for_turn {
|
||||
// TODO this isn't quite right, but good enough for now
|
||||
|
@ -376,6 +376,7 @@ impl UIState for DefaultUIState {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Doesn't need to be a trait anymore
|
||||
pub trait ShowObjects {
|
||||
fn show_icons_for(&self, id: IntersectionID) -> bool;
|
||||
fn show(&self, obj: ID) -> bool;
|
||||
|
201
editor/src/ui.rs
201
editor/src/ui.rs
@ -1,15 +1,15 @@
|
||||
use abstutil;
|
||||
//use cpuprofiler;
|
||||
use crate::objects::{Ctx, RenderingHints, ID};
|
||||
use crate::render::{RenderOptions, RenderOrder, Renderable};
|
||||
use crate::state::UIState;
|
||||
use crate::render::{new_draw_vehicle, DrawPedestrian, RenderOptions, Renderable};
|
||||
use crate::state::{ShowObjects, UIState};
|
||||
use ezgui::{
|
||||
Canvas, Color, EventCtx, EventLoopMode, Folder, GfxCtx, Key, ModalMenu, Text, TopMenu,
|
||||
BOTTOM_LEFT, GUI,
|
||||
Canvas, Color, EventCtx, EventLoopMode, Folder, GfxCtx, Key, ModalMenu, Prerender, Text,
|
||||
TopMenu, BOTTOM_LEFT, GUI,
|
||||
};
|
||||
use geom::{Bounds, Circle, Distance};
|
||||
use kml;
|
||||
use map_model::{BuildingID, LaneID};
|
||||
use map_model::{BuildingID, LaneID, Traversable};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sim::GetDrawAgents;
|
||||
use std::collections::HashSet;
|
||||
@ -237,27 +237,38 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
fn draw(&self, _: &mut GfxCtx, _: &RenderingHints) {}
|
||||
|
||||
fn new_draw(&self, g: &mut GfxCtx, hints: &RenderingHints, screencap: bool) -> Option<String> {
|
||||
let state = self.state.get_state();
|
||||
|
||||
g.clear(
|
||||
self.state
|
||||
.get_state()
|
||||
state
|
||||
.cs
|
||||
.get_def("map background", Color::rgb(242, 239, 233)),
|
||||
);
|
||||
|
||||
let (mut borrows, agents_on) =
|
||||
self.get_renderables_back_to_front(g.get_screen_bounds(), &g.prerender());
|
||||
let cache = state.primary.draw_map.agents.borrow();
|
||||
for on in agents_on {
|
||||
for obj in cache.get(on) {
|
||||
borrows.push(obj);
|
||||
}
|
||||
}
|
||||
// This is a stable sort.
|
||||
borrows.sort_by_key(|r| r.get_zorder());
|
||||
|
||||
let ctx = Ctx {
|
||||
cs: &self.state.get_state().cs,
|
||||
map: &self.state.get_state().primary.map,
|
||||
draw_map: &self.state.get_state().primary.draw_map,
|
||||
sim: &self.state.get_state().primary.sim,
|
||||
cs: &state.cs,
|
||||
map: &state.primary.map,
|
||||
draw_map: &state.primary.draw_map,
|
||||
sim: &state.primary.sim,
|
||||
hints: &hints,
|
||||
};
|
||||
|
||||
let mut sample_intersection: Option<String> = None;
|
||||
self.handle_objects(g.get_screen_bounds(), RenderOrder::BackToFront, |obj| {
|
||||
for obj in borrows {
|
||||
let opts = RenderOptions {
|
||||
color: self.state.get_state().color_obj(obj.get_id(), &ctx),
|
||||
debug_mode: self.state.get_state().layers.debug_mode.is_enabled(),
|
||||
is_selected: self.state.get_state().primary.current_selection == Some(obj.get_id()),
|
||||
color: state.color_obj(obj.get_id(), &ctx),
|
||||
debug_mode: state.layers.debug_mode.is_enabled(),
|
||||
is_selected: state.primary.current_selection == Some(obj.get_id()),
|
||||
// TODO If a ToggleableLayer is currently off, this won't affect it!
|
||||
show_all_detail: screencap,
|
||||
};
|
||||
@ -268,9 +279,7 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
sample_intersection = Some(format!("_i{}", id.0));
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
if !screencap {
|
||||
self.state.draw(g, &ctx);
|
||||
@ -344,12 +353,21 @@ impl<S: UIState> UI<S> {
|
||||
fn mouseover_something(&self, ctx: &EventCtx) -> Option<ID> {
|
||||
let pt = ctx.canvas.get_cursor_in_map_space()?;
|
||||
|
||||
let mut id: Option<ID> = None;
|
||||
|
||||
self.handle_objects(
|
||||
let (mut borrows, agents_on) = self.get_renderables_back_to_front(
|
||||
Circle::new(pt, Distance::meters(3.0)).get_bounds(),
|
||||
RenderOrder::FrontToBack,
|
||||
|obj| {
|
||||
ctx.prerender,
|
||||
);
|
||||
let cache = self.state.get_state().primary.draw_map.agents.borrow();
|
||||
for on in agents_on {
|
||||
for obj in cache.get(on) {
|
||||
borrows.push(obj);
|
||||
}
|
||||
}
|
||||
// This is a stable sort.
|
||||
borrows.sort_by_key(|r| r.get_zorder());
|
||||
borrows.reverse();
|
||||
|
||||
for obj in borrows {
|
||||
// Don't mouseover parcels.
|
||||
// TODO Might get fancier rules in the future, so we can't mouseover irrelevant things
|
||||
// in intersection editor mode, for example.
|
||||
@ -357,43 +375,12 @@ impl<S: UIState> UI<S> {
|
||||
ID::Parcel(_) => {}
|
||||
_ => {
|
||||
if obj.contains_pt(pt) {
|
||||
id = Some(obj.get_id());
|
||||
return false;
|
||||
return Some(obj.get_id());
|
||||
}
|
||||
}
|
||||
};
|
||||
true
|
||||
},
|
||||
);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
fn handle_objects<F: FnMut(Box<&Renderable>) -> bool>(
|
||||
&self,
|
||||
bounds: Bounds,
|
||||
order: RenderOrder,
|
||||
callback: F,
|
||||
) {
|
||||
let state = self.state.get_state();
|
||||
|
||||
let draw_agent_source: &GetDrawAgents = {
|
||||
let tt = &state.primary_plugins.time_travel;
|
||||
if tt.is_active() {
|
||||
tt
|
||||
} else {
|
||||
&state.primary.sim
|
||||
}
|
||||
};
|
||||
|
||||
state.primary.draw_map.handle_objects(
|
||||
bounds,
|
||||
&state.primary.map,
|
||||
draw_agent_source,
|
||||
state,
|
||||
order,
|
||||
callback,
|
||||
)
|
||||
None
|
||||
}
|
||||
|
||||
fn save_editor_state(&self, canvas: &Canvas) {
|
||||
@ -407,6 +394,106 @@ impl<S: UIState> UI<S> {
|
||||
abstutil::write_json("../editor_state", &state).expect("Saving editor_state failed");
|
||||
info!("Saved editor_state");
|
||||
}
|
||||
|
||||
// TODO I guess this technically could go in DrawMap, but we have to pass lots of stuff again.
|
||||
fn get_renderables_back_to_front(
|
||||
&self,
|
||||
bounds: Bounds,
|
||||
prerender: &Prerender,
|
||||
) -> (Vec<Box<&Renderable>>, Vec<Traversable>) {
|
||||
let state = self.state.get_state();
|
||||
let map = &state.primary.map;
|
||||
let draw_map = &state.primary.draw_map;
|
||||
|
||||
let mut areas: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut parcels: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut lanes: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut intersections: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut buildings: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut extra_shapes: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut bus_stops: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut turn_icons: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut agents_on: Vec<Traversable> = Vec::new();
|
||||
|
||||
for id in draw_map.get_matching_objects(bounds) {
|
||||
if !state.show(id) {
|
||||
continue;
|
||||
}
|
||||
match id {
|
||||
ID::Area(id) => areas.push(Box::new(draw_map.get_a(id))),
|
||||
ID::Parcel(id) => parcels.push(Box::new(draw_map.get_p(id))),
|
||||
ID::Lane(id) => {
|
||||
lanes.push(Box::new(draw_map.get_l(id)));
|
||||
if !state.show_icons_for(map.get_l(id).dst_i) {
|
||||
agents_on.push(Traversable::Lane(id));
|
||||
}
|
||||
}
|
||||
ID::Intersection(id) => {
|
||||
intersections.push(Box::new(draw_map.get_i(id)));
|
||||
for t in &map.get_i(id).turns {
|
||||
if state.show_icons_for(id) {
|
||||
turn_icons.push(Box::new(draw_map.get_t(*t)));
|
||||
} else {
|
||||
agents_on.push(Traversable::Turn(*t));
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO front paths will get drawn over buildings, depending on quadtree order.
|
||||
// probably just need to make them go around other buildings instead of having
|
||||
// two passes through buildings.
|
||||
ID::Building(id) => buildings.push(Box::new(draw_map.get_b(id))),
|
||||
ID::ExtraShape(id) => extra_shapes.push(Box::new(draw_map.get_es(id))),
|
||||
ID::BusStop(id) => bus_stops.push(Box::new(draw_map.get_bs(id))),
|
||||
|
||||
ID::Turn(_) | ID::Car(_) | ID::Pedestrian(_) | ID::Trip(_) => {
|
||||
panic!("{:?} shouldn't be in the quadtree", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From background to foreground Z-order
|
||||
let mut borrows: Vec<Box<&Renderable>> = Vec::new();
|
||||
borrows.extend(areas);
|
||||
borrows.extend(parcels);
|
||||
borrows.extend(lanes);
|
||||
borrows.extend(intersections);
|
||||
borrows.extend(buildings);
|
||||
borrows.extend(extra_shapes);
|
||||
borrows.extend(bus_stops);
|
||||
borrows.extend(turn_icons);
|
||||
|
||||
// Make sure agents are cached, but we can't actually return the references to them here,
|
||||
// since the RefCell borrow can't outlive this function.
|
||||
{
|
||||
let sim: &GetDrawAgents = {
|
||||
let tt = &state.primary_plugins.time_travel;
|
||||
if tt.is_active() {
|
||||
tt
|
||||
} else {
|
||||
&state.primary.sim
|
||||
}
|
||||
};
|
||||
let tick = sim.tick();
|
||||
let mut agents = draw_map.agents.borrow_mut();
|
||||
|
||||
for on in &agents_on {
|
||||
if !agents.has(tick, *on) {
|
||||
let mut list: Vec<Box<Renderable>> = Vec::new();
|
||||
for c in sim.get_draw_cars(*on, map).into_iter() {
|
||||
list.push(new_draw_vehicle(c, map, prerender, &state.cs));
|
||||
}
|
||||
for p in sim.get_draw_peds(*on, map).into_iter() {
|
||||
list.push(Box::new(DrawPedestrian::new_new(
|
||||
p, map, prerender, &state.cs,
|
||||
)));
|
||||
}
|
||||
agents.put(tick, *on, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(borrows, agents_on)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
@ -56,6 +56,12 @@ impl<'a> GfxCtx<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prerender(&self) -> Prerender {
|
||||
Prerender {
|
||||
display: self.display,
|
||||
}
|
||||
}
|
||||
|
||||
// Up to the caller to call unfork()!
|
||||
// TODO Canvas doesn't understand this change, so things like text drawing that use
|
||||
// map_to_screen will just be confusing.
|
||||
@ -120,19 +126,13 @@ impl<'a> GfxCtx<'a> {
|
||||
}
|
||||
|
||||
pub fn draw_polygon(&mut self, color: Color, poly: &Polygon) {
|
||||
let obj = Prerender {
|
||||
display: self.display,
|
||||
}
|
||||
.upload_borrowed(vec![(color, poly)]);
|
||||
let obj = self.prerender().upload_borrowed(vec![(color, poly)]);
|
||||
self.num_new_uploads += 1;
|
||||
self.redraw(&obj);
|
||||
}
|
||||
|
||||
pub fn draw_polygon_batch(&mut self, list: Vec<(Color, &Polygon)>) {
|
||||
let obj = Prerender {
|
||||
display: self.display,
|
||||
}
|
||||
.upload_borrowed(list);
|
||||
let obj = self.prerender().upload_borrowed(list);
|
||||
self.num_new_uploads += 1;
|
||||
self.redraw(&obj);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user