1use geom::{ArrowCap, Circle, Distance, Line, PolyLine, Pt2D, Tessellation};
2use map_gui::colors::ColorScheme;
3use map_gui::render::{DrawOptions, OUTLINE_THICKNESS};
4use map_gui::AppLike;
5use map_model::Map;
6use sim::{CarID, DrawCarInput, Intent, Sim};
7use widgetry::{Drawable, GeomBatch, GfxCtx, Prerender};
8
9use crate::render::{grey_out_unhighlighted_people, GameRenderable};
10use crate::ID;
11
12pub struct DrawBike {
13 pub id: CarID,
14 body_circle: Circle,
15 zorder: isize,
17
18 draw_default: Drawable,
19}
20
21impl DrawBike {
22 pub fn new(
23 input: DrawCarInput,
24 map: &Map,
25 sim: &Sim,
26 prerender: &Prerender,
27 cs: &ColorScheme,
28 ) -> DrawBike {
29 let mut draw_default = GeomBatch::new();
30
31 let body_radius = sim::pedestrian_body_radius();
32 let body_color = grey_out_unhighlighted_people(
33 cs.rotating_color_agents(input.id.id),
34 &input.person,
35 sim,
36 );
37 draw_default.push(
38 cs.bike_frame,
39 input.body.make_polygons(Distance::meters(0.4)),
40 );
41
42 let err = format!("{} on {} has weird body", input.id, input.on);
43 let (body_pos, facing) = input
44 .body
45 .dist_along(0.4 * input.body.length())
46 .expect(&err);
47 let body_circle = Circle::new(body_pos, body_radius);
48 draw_default.push(body_color, body_circle.to_polygon());
49 draw_default.push(
50 cs.ped_head,
51 Circle::new(body_pos, 0.5 * body_radius).to_polygon(),
52 );
53
54 {
55 let (hand_pos, hand_angle) = input
57 .body
58 .dist_along(0.9 * input.body.length())
59 .expect(&err);
60 draw_default.push(
61 cs.bike_frame,
62 Line::must_new(
63 hand_pos.project_away(body_radius, hand_angle.rotate_degs(90.0)),
64 hand_pos.project_away(body_radius, hand_angle.rotate_degs(-90.0)),
65 )
66 .make_polygons(Distance::meters(0.1)),
67 );
68
69 draw_default.push(
71 body_color,
72 Line::must_new(
73 body_pos.project_away(0.9 * body_radius, facing.rotate_degs(-30.0)),
74 hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(-90.0)),
75 )
76 .make_polygons(Distance::meters(0.08)),
77 );
78 draw_default.push(
79 body_color,
80 Line::must_new(
81 body_pos.project_away(0.9 * body_radius, facing.rotate_degs(30.0)),
82 hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(90.0)),
83 )
84 .make_polygons(Distance::meters(0.08)),
85 );
86 }
87
88 if let Some(t) = input.waiting_for_turn {
89 let angle = map.get_t(t).angle();
90 draw_default.push(
91 cs.turn_arrow,
92 PolyLine::must_new(vec![
93 body_pos.project_away(body_radius / 2.0, (facing + angle).opposite()),
94 body_pos.project_away(body_radius / 2.0, facing + angle),
95 ])
96 .make_arrow(Distance::meters(0.15), ArrowCap::Triangle),
97 );
98 }
99
100 if input.intent == Some(Intent::SteepUphill) {
101 let bubble_z = -0.0001;
102 let mut bubble_batch =
103 GeomBatch::load_svg(prerender, "system/assets/map/thought_bubble.svg")
104 .scale(0.05)
105 .centered_on(input.body.middle())
106 .translate(2.0, -3.5)
107 .set_z_offset(bubble_z);
108 bubble_batch.append(
109 GeomBatch::load_svg(prerender, "system/assets/tools/uphill.svg")
110 .scale(0.05)
111 .centered_on(input.body.middle())
112 .translate(2.2, -4.2)
113 .set_z_offset(bubble_z),
114 );
115
116 draw_default.append(bubble_batch);
117 }
118
119 let zorder = input
120 .partly_on
121 .into_iter()
122 .chain(vec![input.on])
123 .map(|on| on.get_zorder(map))
124 .max()
125 .unwrap();
126 DrawBike {
127 id: input.id,
128 body_circle,
129 zorder,
130 draw_default: prerender.upload(draw_default),
131 }
132 }
133}
134
135impl GameRenderable for DrawBike {
136 fn get_id(&self) -> ID {
137 ID::Car(self.id)
138 }
139
140 fn draw(&self, g: &mut GfxCtx, _: &dyn AppLike, _: &DrawOptions) {
141 g.redraw(&self.draw_default);
142 }
143
144 fn get_outline(&self, _: &Map) -> Tessellation {
145 Tessellation::from(
146 Circle::new(self.body_circle.center, Distance::meters(2.0))
147 .to_outline(OUTLINE_THICKNESS)
148 .unwrap(),
149 )
150 }
151
152 fn contains_pt(&self, pt: Pt2D, _: &Map) -> bool {
153 Circle::new(self.body_circle.center, Distance::meters(2.0)).contains_pt(pt)
154 }
155
156 fn get_zorder(&self) -> isize {
157 self.zorder
158 }
159}