+ glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, c1*sizeof(u16), indices+c0 );
+ pr->ui.indices_head = c1;
+ }
+ else
+ pr->ui.indices_head += c0;
+}
+
+/*
+ * Place a set of vertices into gpu array
+ */
+static u32 world_routes_ui_set_verts( struct route *pr, v2f *verts, u32 count )
+{
+ if( pr->ui.vertex_head + count >= k_route_ui_max_verts )
+ pr->ui.vertex_head = 0;
+
+ u32 vert_start = pr->ui.vertex_head;
+ pr->ui.vertex_head += count;
+
+ glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
+ glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
+ sizeof(v2f)*count, verts );
+
+ return vert_start;
+}
+
+/*
+ * Update the last (count) vertices positions, does not add any.
+ * Data must already be written to, and not cross either array boundaries.
+ */
+static u32 world_routes_ui_update_verts( struct route *pr,
+ v2f *verts, u32 count )
+{
+ u32 vert_start = pr->ui.vertex_head-count;
+
+ glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
+ glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
+ sizeof(v2f)*count, verts );
+
+ return vert_start;
+}
+
+/*
+ * Current/active segment of this UI bar
+ */
+static struct route_ui_segment *world_routes_ui_curseg( struct route *pr )
+{
+ u32 index = (pr->ui.segment_start+pr->ui.segment_count-1)%k_max_ui_segments;
+ return &pr->ui.segments[ index ];
+}
+
+/*
+ * Start a new segment in the UI bar, will create a split on the last one if
+ * there is one active currently. (api)
+ */
+static void world_routes_ui_newseg( u32 route )
+{
+ struct subworld_routes *r = subworld_routes();
+ struct route *pr = &r->routes[route];
+
+ pr->ui.last_notch = 0.0;
+
+ glBindVertexArray( pr->ui.vao );
+ if( pr->ui.segment_count )
+ {
+ float const k_gap_width = 1.0f;
+
+ struct route_ui_segment *cseg = world_routes_ui_curseg(pr);