much improve
authorhgn <hgodden00@gmail.com>
Sat, 20 Aug 2022 00:29:44 +0000 (01:29 +0100)
committerhgn <hgodden00@gmail.com>
Sat, 20 Aug 2022 00:29:44 +0000 (01:29 +0100)
22 files changed:
main.c
shaders.sh
shaders/alphatest.h
shaders/blit.h
shaders/character.h
shaders/fscolour.h
shaders/gate.h
shaders/gatelq.h
shaders/gpos.h
shaders/planeinf.h
shaders/route.h
shaders/routeui.fs [new file with mode: 0644]
shaders/routeui.h [new file with mode: 0644]
shaders/routeui.vs [new file with mode: 0644]
shaders/scoretext.h
shaders/sky.h
shaders/standard.h
shaders/terrain.h
shaders/unlit.h
shaders/vblend.h
shaders/water.h
world_routes.h

diff --git a/main.c b/main.c
index 175f12efe879a4af4a8244c231bf57fd3f47117a..4610d5288ff09b88247b14901aaa440b13e6bad7 100644 (file)
--- a/main.c
+++ b/main.c
@@ -190,6 +190,8 @@ void vg_start(void)
    {
       physics_test_start();
    }
+
+   world_routes_ui_newseg( 0, 0.0f );
 }
 
 void vg_free(void)
@@ -425,4 +427,29 @@ void vg_ui(void)
 
       render_update_lighting_ub();
    }
+
+   static double last_b_press = 0.0;
+
+   double localtime = vg_time - last_b_press;
+
+   world_routes_ui_updatetime( 0, localtime );
+   world_routes_ui_draw( 0 );
+
+   if( glfwGetKey(vg_window,GLFW_KEY_B) )
+      world_routes_ui_notch( 0, localtime );
+
+   if( vg_time-last_b_press > 1.0 )
+      if( glfwGetKey(vg_window,GLFW_KEY_N) )
+      {
+         last_b_press = vg_time;
+         world_routes_ui_newseg( 0, localtime );
+      }
+
+   static double last_m_press;
+   if( vg_time-last_m_press > 1.0 )
+      if( glfwGetKey( vg_window, GLFW_KEY_M) )
+      {
+         last_m_press = vg_time;
+         world_routes_ui_popfirst(0);
+      }
 }
index 21beda41e00effb6a112eb1e2331ade993fb6ad8..b02baccf9ceb0dc3fb90a79e630cb7b8804c6b30 100755 (executable)
@@ -26,6 +26,7 @@ shader planeinf standard.vs planeinf.fs
 shader gpos standard.vs gpos.fs
 shader route standard.vs route.fs
 shader scoretext scoretext.vs vblend.fs
+shader routeui routeui.vs routeui.fs
 
 cd shaders
 ../bin/linux/tools/shader $target_shaders
index 3039b48b9397fb0428cca1c69e302ae85ed32df5..1d16ac7c87672133716962c68981972862da59c0 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_alphatest = {
    .link = shader_alphatest_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_alphatest = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/std_alphatest.fs",
+.orig_file = "../../shaders/std_alphatest.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 49e4c802ae25ea25aec799a4e15067d143a18e32..bd1ed41e540a4848298267f5eea344ad56189115 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_blit = {
    .link = shader_blit_link,
    .vs = 
 {
-.orig_file = "../shaders/blit.vs",
+.orig_file = "../../shaders/blit.vs",
 .static_src = 
 "layout (location=0) in vec2 a_co;\n"
 "out vec2 aUv;\n"
@@ -20,7 +20,7 @@ static struct vg_shader _shader_blit = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/blit.fs",
+.orig_file = "../../shaders/blit.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "uniform sampler2D uTexMain;\n"
index e592a94cddb753285badc6a66d3906bee818150d..2fc85a5d013983c99c2e81bf6a317835cbef4691 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_character = {
    .link = shader_character_link,
    .vs = 
 {
-.orig_file = "../shaders/character.vs",
+.orig_file = "../../shaders/character.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -43,7 +43,7 @@ static struct vg_shader _shader_character = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/character.fs",
+.orig_file = "../../shaders/character.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index ccef7b0a5a8a2f2d5530eb6c9e2f4255c640f54d..08fe21edb838ab280fde040862da9265845dd59f 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_fscolour = {
    .link = shader_fscolour_link,
    .vs = 
 {
-.orig_file = "../shaders/blit.vs",
+.orig_file = "../../shaders/blit.vs",
 .static_src = 
 "layout (location=0) in vec2 a_co;\n"
 "out vec2 aUv;\n"
@@ -20,7 +20,7 @@ static struct vg_shader _shader_fscolour = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/colour.fs",
+.orig_file = "../../shaders/colour.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "uniform vec4 uColour;\n"
index 58e80bc5aea9af734f86afaf7668b2382af1d7fc..53013d0c20d34d06ee31786134d2af7c51825880 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_gate = {
    .link = shader_gate_link,
    .vs = 
 {
-.orig_file = "../shaders/gate.vs",
+.orig_file = "../../shaders/gate.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -34,7 +34,7 @@ static struct vg_shader _shader_gate = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/gate.fs",
+.orig_file = "../../shaders/gate.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 0bedde22013fbb283972e5cde13a521c4f03f02f..4cff927bc7818953fba6145efe1a7e5f5ef64398 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_gatelq = {
    .link = shader_gatelq_link,
    .vs = 
 {
-.orig_file = "../shaders/gate.vs",
+.orig_file = "../../shaders/gate.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -34,7 +34,7 @@ static struct vg_shader _shader_gatelq = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/gate_lq.fs",
+.orig_file = "../../shaders/gate_lq.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index d140abbf36a45208faa2b9733aabc657000e47c0..87b5843ba0c098bc4d417fbdb2ebaa1fe4716778 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_gpos = {
    .link = shader_gpos_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_gpos = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/gpos.fs",
+.orig_file = "../../shaders/gpos.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index abd7a0caf67cb6466f392fcf00dca07dc65ce9d2..1054aa4541d76b54456c4cfe5c9755e9dde7d9d4 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_planeinf = {
    .link = shader_planeinf_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_planeinf = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/planeinf.fs",
+.orig_file = "../../shaders/planeinf.fs",
 .static_src = 
 "\n"
 "#line      2        0 \n"
index 650f8a957d0f583fb59567518ff3ed16b4e3cdb8..cbdbeb44740e3a835d31b62001c346f1b7308adb 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_route = {
    .link = shader_route_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_route = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/route.fs",
+.orig_file = "../../shaders/route.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
diff --git a/shaders/routeui.fs b/shaders/routeui.fs
new file mode 100644 (file)
index 0000000..bca7600
--- /dev/null
@@ -0,0 +1,6 @@
+out vec4 FragColor;
+
+void main()
+{
+   FragColor = vec4( 1.0, 1.0, 0.0, 1.0 );
+}
diff --git a/shaders/routeui.h b/shaders/routeui.h
new file mode 100644 (file)
index 0000000..659c040
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef SHADER_routeui_H
+#define SHADER_routeui_H
+static void shader_routeui_link(void);
+static void shader_routeui_register(void);
+static struct vg_shader _shader_routeui = {
+   .name = "routeui",
+   .link = shader_routeui_link,
+   .vs = 
+{
+.orig_file = "../../shaders/routeui.vs",
+.static_src = 
+"layout (location=0) in vec2 a_co;\n"
+"\n"
+"void main()\n"
+"{\n"
+"   gl_Position = vec4(a_co*0.01,0.0,1.0);\n"
+"}\n"
+""},
+   .fs = 
+{
+.orig_file = "../../shaders/routeui.fs",
+.static_src = 
+"out vec4 FragColor;\n"
+"\n"
+"void main()\n"
+"{\n"
+"   FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n"
+"}\n"
+""},
+};
+
+static void shader_routeui_register(void){
+   vg_shader_register( &_shader_routeui );
+}
+static void shader_routeui_use(void){ glUseProgram(_shader_routeui.id); }
+static void shader_routeui_link(void){
+}
+#endif /* SHADER_routeui_H */
diff --git a/shaders/routeui.vs b/shaders/routeui.vs
new file mode 100644 (file)
index 0000000..def0bb6
--- /dev/null
@@ -0,0 +1,6 @@
+layout (location=0) in vec2 a_co;
+
+void main()
+{
+   gl_Position = vec4(a_co*vec2(0.01,0.1),0.0,1.0);
+}
index 304715c39223e3f395e7719381b23b4989932317..3e499bb3ba6de382cab2904eba526c18c6e49332 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_scoretext = {
    .link = shader_scoretext_link,
    .vs = 
 {
-.orig_file = "../shaders/scoretext.vs",
+.orig_file = "../../shaders/scoretext.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -57,7 +57,7 @@ static struct vg_shader _shader_scoretext = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/vblend.fs",
+.orig_file = "../../shaders/vblend.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 09329f5aa8b1305196882faa08d72c6776412e99..aee87f4fea8fa9c5e1c189a258ec4505a76db31b 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_sky = {
    .link = shader_sky_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_sky = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/sky.fs",
+.orig_file = "../../shaders/sky.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 1b41b9aade599868d203300d7744aa4d5469014b..83f73c1ae377e31114fdfafa44253c234607ec1a 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_standard = {
    .link = shader_standard_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_standard = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/standard.fs",
+.orig_file = "../../shaders/standard.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 1c87e35d351d3ef02a3450aa76f131cfb1c819a1..4ad91ea8f6f864fd5d7d2dae5126a496be24673b 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_terrain = {
    .link = shader_terrain_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_terrain = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/terrain.fs",
+.orig_file = "../../shaders/terrain.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 8fbf00b17a293a9d8fa5d9a11b81941f84c7db32..25bca828df13c463fc4a846ae7717e591bb7c364 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_unlit = {
    .link = shader_unlit_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_unlit = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/unlit.fs",
+.orig_file = "../../shaders/unlit.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 53154f6370469c6ccc0518109af339d220d40f98..cc057627036fb630443fd21a8834903a26d92422 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_vblend = {
    .link = shader_vblend_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_vblend = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/vblend.fs",
+.orig_file = "../../shaders/vblend.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index 8a1d4df962f0e37088a409dd4cf231f1392f76fb..13a718f2eb2102bccefc8b83d2ad6a8d78ef4dd0 100644 (file)
@@ -7,7 +7,7 @@ static struct vg_shader _shader_water = {
    .link = shader_water_link,
    .vs = 
 {
-.orig_file = "../shaders/standard.vs",
+.orig_file = "../../shaders/standard.vs",
 .static_src = 
 "layout (location=0) in vec3 a_co;\n"
 "layout (location=1) in vec3 a_norm;\n"
@@ -38,7 +38,7 @@ static struct vg_shader _shader_water = {
 ""},
    .fs = 
 {
-.orig_file = "../shaders/water.fs",
+.orig_file = "../../shaders/water.fs",
 .static_src = 
 "out vec4 FragColor;\n"
 "\n"
index acb14ea84b7fe2aab24b91a577369f9edbaaa4f3..93fa2c0ce470eca9e98fba764361d14674afa86a 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "shaders/vblend.h"
 #include "shaders/route.h"
+#include "shaders/routeui.h"
 
 enum route_special_type
 {
@@ -14,6 +15,10 @@ enum route_special_type
    k_route_special_type_collector = 2
 };
 
+enum { k_max_ui_segments = 32 };
+enum { k_route_ui_max_verts = 2000 };
+enum { k_route_ui_max_indices = 3000 };
+
 struct subworld_routes
 {
    struct route_node
@@ -36,9 +41,33 @@ struct subworld_routes
 
       u32 start;
       mdl_submesh sm;
-
+      
       int active;
       float factive;
+
+      double best_lap; /* Session */
+
+      struct 
+      {
+         GLuint vao, vbo, ebo;
+
+         u32  indices_head;
+         u32  vertex_head;
+
+         float last_notch;
+
+         struct route_ui_segment
+         {
+            float time;
+
+            u32 vertex_start, vertex_count,
+                index_start, index_count;
+         }
+         segments[k_max_ui_segments];
+
+         u32 segment_start, segment_count;
+      }
+      ui;
    }
    *routes;
 
@@ -165,6 +194,284 @@ static u32 world_routes_get_path( u32 starter, u32 stack[64] )
    return 0;
 }
 
+/*
+ * Free a segment from the UI bar to be reused later
+ */
+static void world_routes_ui_popfirst( u32 route )
+{
+   struct subworld_routes *r = subworld_routes();
+   struct route *pr = &r->routes[route];
+
+   if( pr->ui.segment_count )
+   {
+      pr->ui.segment_start ++;
+
+      if( pr->ui.segment_start == 32 )
+         pr->ui.segment_start = 0;
+
+      pr->ui.segment_count --;
+   }
+}
+
+/*
+ * Break a index range into two pieces over the edge of the maximum it can
+ * store. s1 is 0 always, so its a ring buffer.
+ */
+static void world_routes_ui_split_indices( u32 s0, u32 count, u32 *c0, u32 *c1 )
+{
+   *c0 = (VG_MIN( s0+count, k_route_ui_max_indices )) - s0;
+   *c1 = count-(*c0);
+}
+
+/*
+ * Place a set of indices into gpu array automatically splits
+ * across bounds
+ */
+static void world_routes_ui_set_indices( struct route *pr, 
+                                          u16 *indices, u32 count )
+{
+   u32 c0, c1;
+   world_routes_ui_split_indices( pr->ui.indices_head, count, &c0, &c1 );
+
+   glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pr->ui.ebo );
+
+   if( c0 )
+   {
+      glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, pr->ui.indices_head*sizeof(u16),
+            c0*sizeof(u16), indices );
+   }
+
+   if( c1 )
+   {
+      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, float time )
+{
+   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;
+
+      v2f verts[2];
+      verts[0][0] =  time-k_gap_width;
+      verts[0][1] =  0.5f;
+      verts[1][0] =  time-k_gap_width;
+      verts[1][1] = -0.5f;
+
+      world_routes_ui_update_verts( pr, verts, 2 );
+   }
+
+   pr->ui.segment_count ++;
+   struct route_ui_segment *segment = world_routes_ui_curseg(pr);
+   
+   v2f verts[4];
+   verts[0][0] =  0.0f;
+   verts[0][1] =  0.5f;
+   verts[1][0] =  0.0f;
+   verts[1][1] = -0.5f;
+   verts[2][0] =  0.0f;
+   verts[2][1] =  0.5f;
+   verts[3][0] =  0.0f;
+   verts[3][1] = -0.5f;
+
+   u32 vert_start = world_routes_ui_set_verts( pr, verts, 4 );
+
+   u16 indices[6];
+   indices[0] = vert_start + 0;
+   indices[1] = vert_start + 1;
+   indices[2] = vert_start + 3;
+   indices[3] = vert_start + 0;
+   indices[4] = vert_start + 3;
+   indices[5] = vert_start + 2;
+
+   segment->vertex_start = vert_start;
+   segment->vertex_count = 4;
+   segment->index_start  = pr->ui.indices_head;
+   segment->index_count  = 6;
+
+   world_routes_ui_set_indices( pr, indices, 6 );
+}
+
+/*
+ * Extend the end of the bar 
+ */
+static void world_routes_ui_updatetime( u32 route, float time )
+{
+   struct subworld_routes *r = subworld_routes();
+   struct route *pr = &r->routes[route];
+
+   v2f verts[2];
+   verts[0][0] =  time;
+   verts[0][1] =  0.5f;
+   verts[1][0] =  time;
+   verts[1][1] = -0.5f;
+
+   u32 vert_start = pr->ui.vertex_head-2;
+
+   glBindVertexArray( pr->ui.vao );
+   world_routes_ui_update_verts( pr, verts, 2 );
+}
+
+/*
+ * Create a notch in the bar, used when a reset is triggered by the user
+ */
+static void world_routes_ui_notch( u32 route, float time )
+{
+   struct subworld_routes *r = subworld_routes();
+   struct route *pr = &r->routes[route];
+
+   if( (time - pr->ui.last_notch) > 1.0 )
+   {
+      v2f verts[8];
+      
+      float const k_notch_width = 1.0f;
+
+      float xa = time-k_notch_width,
+            xb = time-k_notch_width * 0.5f,
+            xc = time;
+
+      verts[0][0] =  xa;
+      verts[0][1] =  0.5f;
+      verts[1][0] =  xa;
+      verts[1][1] = -0.5f;
+
+      verts[2][0] =  xb;
+      verts[2][1] =  0.25f;
+      verts[3][0] =  xb;
+      verts[3][1] = -0.25f;
+
+      verts[4][0] =  xc;
+      verts[4][1] =  0.5f;
+      verts[5][0] =  xc;
+      verts[5][1] = -0.5f;
+
+      verts[6][0] =  xc;
+      verts[6][1] =  0.5f;
+      verts[7][0] =  xc;
+      verts[7][1] = -0.5f;
+
+      glBindVertexArray( pr->ui.vao );
+      u32 vert_start_mod = world_routes_ui_update_verts( pr, verts, 2 ),
+          vert_start_new = world_routes_ui_set_verts( pr, verts+2, 6 );
+
+      u16 indices[18];
+      indices[ 0] = vert_start_mod+1;
+      indices[ 1] = vert_start_new+0;
+      indices[ 2] = vert_start_mod+0;
+      indices[ 3] = vert_start_mod+1;
+      indices[ 4] = vert_start_new+1;
+      indices[ 5] = vert_start_new+0;
+
+      indices[ 6] = vert_start_new+0;
+      indices[ 7] = vert_start_new+1;
+      indices[ 8] = vert_start_new+3;
+      indices[ 9] = vert_start_new+0;
+      indices[10] = vert_start_new+3;
+      indices[11] = vert_start_new+2;
+
+      indices[12] = vert_start_new+3;
+      indices[13] = vert_start_new+4;
+      indices[14] = vert_start_new+2;
+      indices[15] = vert_start_new+3;
+      indices[16] = vert_start_new+5;
+      indices[17] = vert_start_new+4;
+
+      world_routes_ui_set_indices( pr, indices, 18 );
+
+      pr->ui.last_notch = time;
+
+      struct route_ui_segment *segment = world_routes_ui_curseg(pr);
+      segment->vertex_count += 6;
+      segment->index_count  += 18;
+   }
+}
+
+static void world_routes_ui_draw( u32 route )
+{
+   //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+
+   struct subworld_routes *r = subworld_routes();
+   struct route *pr = &r->routes[route];
+
+   shader_routeui_use();
+   glBindVertexArray( pr->ui.vao );
+
+   for( u32 i=0; i<pr->ui.segment_count; i++ )
+   {
+      u32 j = (pr->ui.segment_start + i) % k_max_ui_segments;
+      struct route_ui_segment *segment = &pr->ui.segments[j];
+
+      u32 c0, c1;
+      world_routes_ui_split_indices( segment->index_start, 
+            segment->index_count, &c0, &c1 );
+
+      if( c0 )
+         glDrawElements( GL_TRIANGLES, c0, GL_UNSIGNED_SHORT,
+                           (void *)(segment->index_start*sizeof(u16)));
+      if( c1 )
+         glDrawElements( GL_TRIANGLES, c1, GL_UNSIGNED_SHORT, (void *)(0) );
+   }
+
+   //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+}
+
 /* 
  * Will scan the whole run for two things;
  *   1: we set a new record for the total, complete loop around the course
@@ -515,6 +822,7 @@ static void world_routes_register(void)
    r->current_run_version = 2;
 
    shader_route_register();
+   shader_routeui_register();
 }
 
 static void world_routes_loadfrom( mdl_header *mdl )
@@ -637,6 +945,33 @@ static void world_routes_loadfrom( mdl_header *mdl )
          route->active = 0;
          route->factive = 0.0f;
 
+         /* OpenGL strips */
+         glGenVertexArrays( 1, &route->ui.vao );
+         glGenBuffers( 1, &route->ui.vbo );
+         glGenBuffers( 1, &route->ui.ebo );
+         glBindVertexArray( route->ui.vao );
+
+         size_t stride = sizeof(v2f);
+
+         glBindBuffer( GL_ARRAY_BUFFER, route->ui.vbo );
+         glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride, 
+               NULL, GL_DYNAMIC_DRAW );
+         glBindVertexArray( route->ui.vao );
+         glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, route->ui.ebo );
+         glBufferData( GL_ELEMENT_ARRAY_BUFFER, 
+               k_route_ui_max_indices*sizeof(u16), NULL,
+               GL_DYNAMIC_DRAW );
+
+         glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)0 );
+         glEnableVertexAttribArray( 0 );
+         VG_CHECK_GL();
+
+         route->ui.indices_head = k_route_ui_max_indices - 9;
+         route->ui.vertex_head = k_route_ui_max_verts - 200;
+         route->ui.segment_start = 0;
+         route->ui.segment_count = 0;
+         route->ui.last_notch = 0.0;
+
          r->route_count ++;
       }
    }