now we're doing a bunch of them
[carveJwlIkooP6JGAAIwe30JlM.git] / world_routes.h
index 3aeaf05e931afe3885f880ee6772bcef1c9f7352..bd4ce0cf803fa91ac97eec10acfa429e31b1233d 100644 (file)
@@ -9,8 +9,11 @@
 #include "world.h"
 #include "world_gate.h"
 
+#if 0
 #include "shaders/vblend.h"
-#include "shaders/route.h"
+#endif
+
+#include "shaders/scene_route.h"
 #include "shaders/routeui.h"
 
 
@@ -50,7 +53,8 @@ VG_STATIC void debug_sbpath( struct route_node *rna, struct route_node *rnb,
 /*
  * Get a list of node ids in stack, and return how many there is
  */
-VG_STATIC u32 world_routes_get_path( u32 starter, u32 stack[64] )
+VG_STATIC u32 world_routes_get_path( world_instance *world,
+                                     u32 starter, u32 stack[64] )
 {
    u32 stack_i[64];
 
@@ -68,7 +72,7 @@ VG_STATIC u32 world_routes_get_path( u32 starter, u32 stack[64] )
          continue;
       }
 
-      struct route_node *rn = &world.nodes[stack[si-1]];
+      struct route_node *rn = &world->nodes[stack[si-1]];
       u32 nextid = rn->next[stack_i[si-1]];
       stack_i[si-1] ++;
 
@@ -221,7 +225,7 @@ VG_STATIC struct route_ui_segment *world_routes_ui_curseg(
  */
 VG_STATIC void world_routes_ui_newseg( u32 route )
 {
-   struct route_ui_bar *pui = &world.ui_bars[route];
+   struct route_ui_bar *pui = &world_global.ui_bars[route];
    
    glBindVertexArray( pui->vao );
    if( pui->segment_count )
@@ -276,7 +280,7 @@ VG_STATIC void world_routes_ui_newseg( u32 route )
  */
 VG_STATIC void world_routes_ui_updatetime( u32 route, float time )
 {
-   struct route_ui_bar *pui = &world.ui_bars[route];
+   struct route_ui_bar *pui = &world_global.ui_bars[route];
 
    v2f verts[2];
    verts[0][0] =  time;
@@ -308,20 +312,22 @@ VG_STATIC void world_routes_ui_draw_segment( struct route_ui_segment *segment )
 /*
  * Draws full bar at Y offset(offset).
  */
-VG_STATIC void world_routes_ui_draw( u32 route, v4f colour, float offset )
+VG_STATIC void world_routes_ui_draw( world_instance *world,
+                                     u32 route, v4f colour, float offset )
 {
    float const k_bar_height = 0.05f,
                k_bar_scale_x = 0.005f;
 
-   struct route *pr = &world.routes[route];
-   struct route_ui_bar *pui = &world.ui_bars[route];
+   /* FIXME(10) ID mishmatch */
+   struct route *pr = &world->routes[route];
+   struct route_ui_bar *pui = &world_global.ui_bars[route];
 
    float cx = pui->xpos;
 
    shader_routeui_use();
    glBindVertexArray( pui->vao );
 
-   float fade_amt = world.time - pui->fade_timer_start;
+   float fade_amt = world_global.time - pui->fade_timer_start;
    fade_amt = vg_clampf( fade_amt / 1.0f, 0.0f, 1.0f );
    
    float fade_block_size = 0.0f,
@@ -342,7 +348,7 @@ VG_STATIC void world_routes_ui_draw( u32 route, v4f colour, float offset )
    fade_colour[3] *= 1.0f-fade_amt;
 
    /* 1 minute timer */
-   float timer_delta = (world.time - world.last_use) * (1.0/45.0),
+   float timer_delta = (world_global.time - world_global.last_use) * (1.0/45.0),
          timer_scale = 1.0f - vg_minf( timer_delta, 1.0f );
 
    /* 
@@ -386,11 +392,13 @@ VG_STATIC void world_routes_ui_draw( u32 route, v4f colour, float offset )
    pui->xpos = vg_lerpf( pui->xpos, -main_block_size * 0.5f, 0.03f );
 }
 
-VG_STATIC void world_routes_local_set_record( u32 route, double lap_time )
+VG_STATIC void world_routes_local_set_record( world_instance *world,
+                                              u32 route, double lap_time )
 {
    vg_success( "  NEW LAP TIME: %f\n", lap_time );
 
-   struct route *pr = &world.routes[route];
+   /* FIXME(10): ID mishmatch */
+   struct route *pr = &world->routes[route];
 
    if( pr->track_id != 0xffffffff )
    {
@@ -428,13 +436,14 @@ VG_STATIC void world_routes_local_set_record( u32 route, double lap_time )
  *   2: the time of each segment will be recorded into the data buffer
  *       (not implemented: TODO)
  */
-VG_STATIC void world_routes_verify_run( u32 route )
+VG_STATIC void world_routes_verify_run( world_instance *world, u32 route )
 {
-   struct route *pr = &world.routes[route];
-   struct route_ui_bar *pui = &world.ui_bars[route];
+   /* FIXME(10): ID mishmatch */
+   struct route *pr = &world->routes[route];
+   struct route_ui_bar *pui = &world_global.ui_bars[route];
 
    u32 stack[64];
-   u32 si = world_routes_get_path( world.routes[route].start, stack );
+   u32 si = world_routes_get_path( world, world->routes[route].start, stack );
 
    /* 
     * we only care about gates that ref gates, so shuffle down the array
@@ -443,15 +452,15 @@ VG_STATIC void world_routes_verify_run( u32 route )
    u32 sj = 0, maxv = 0, begin = 0;
    for( u32 i=0; i<si; i++ )
    {
-      struct route_node *inode = &world.nodes[stack[i]];
+      struct route_node *inode = &world->nodes[stack[i]];
 
       if( inode->special_type == k_route_special_type_collector )
       {
-         timings[sj ++] = &world.collectors[ inode->special_id ].timing;
+         timings[sj ++] = &world->collectors[ inode->special_id ].timing;
       }
       else if( inode->special_type == k_route_special_type_gate )
       {
-         timings[sj ++] = &world.gates[inode->special_id].timing;
+         timings[sj ++] = &world->gates[inode->special_id].timing;
       }
    }
    
@@ -465,10 +474,10 @@ VG_STATIC void world_routes_verify_run( u32 route )
    }
 
    vg_info( "== begin verification (%u) ==\n", route );
-   vg_info( "  current version: %u\n", world.current_run_version );
+   vg_info( "  current version: %u\n", world_global.current_run_version );
 
    int verified = 0;
-   if( timings[begin]->version == world.current_run_version )
+   if( timings[begin]->version == world_global.current_run_version )
       verified = 1;
 
    int valid_segment_count = 0;
@@ -505,7 +514,7 @@ VG_STATIC void world_routes_verify_run( u32 route )
 
    pui->fade_start = pui->segment_start;
    pui->fade_count = 0;
-   pui->fade_timer_start = world.time;
+   pui->fade_timer_start = world_global.time;
 
    int orig_seg_count = pui->segment_count;
 
@@ -513,7 +522,7 @@ VG_STATIC void world_routes_verify_run( u32 route )
 
    if( verified )
    {
-      world_routes_local_set_record( route, lap_time );
+      world_routes_local_set_record( world, route, lap_time );
       world_routes_ui_popfirst( pui );
       pui->fade_count ++;
    }
@@ -528,40 +537,40 @@ VG_STATIC void world_routes_verify_run( u32 route )
       pui->fade_count ++;
    }
 
-   world.routes[route].latest_pass = world.time;
+   world->routes[route].latest_pass = world_global.time;
 }
 
-VG_STATIC void world_routes_clear(void)
+VG_STATIC void world_routes_clear( world_instance *world )
 {
-   for( u32 i=0; i<world.route_count; i++ )
+   for( u32 i=0; i<world->route_count; i++ )
    {
-      struct route *route = &world.routes[i];
+      struct route *route = &world->routes[i];
       route->active = 0;
    }
-   world.current_run_version += 4;
-   world.last_use = 0.0;
+   world_global.current_run_version += 4;
+   world_global.last_use = 0.0;
 }
 
 /*
  * When going through a gate this is called for bookkeeping purposes
  */
-VG_STATIC void world_routes_activate_gate( u32 id )
+VG_STATIC void world_routes_activate_gate( world_instance *world, u32 id )
 {
-   struct route_gate *rg = &world.gates[id];
-   struct route_node *pnode = &world.nodes[rg->node_id],
-                     *pdest = &world.nodes[pnode->next[0]];
+   struct route_gate *rg = &world->gates[id];
+   struct route_node *pnode = &world->nodes[rg->node_id],
+                     *pdest = &world->nodes[pnode->next[0]];
 
-   world.last_use = world.time;
+   world_global.last_use = world_global.time;
 
-   struct route_collector *rc = &world.collectors[ pdest->special_id ];
+   struct route_collector *rc = &world->collectors[ pdest->special_id ];
 
-   world.active_gate = id;
-   rg->timing.version = world.current_run_version;
-   rg->timing.time = world.time;
+   world_global.active_gate = id;
+   rg->timing.version = world_global.current_run_version;
+   rg->timing.time = world_global.time;
 
-   for( u32 i=0; i<world.route_count; i++ )
+   for( u32 i=0; i<world->route_count; i++ )
    {
-      struct route *route = &world.routes[i];
+      struct route *route = &world->routes[i];
       
       int was_active = route->active;
 
@@ -570,7 +579,7 @@ VG_STATIC void world_routes_activate_gate( u32 id )
       {
          if( pdest->route_ids[j] == i )
          {
-            world_routes_verify_run( i );
+            world_routes_verify_run( world, i );
             route->active = 1;
             break;
          }
@@ -578,10 +587,10 @@ VG_STATIC void world_routes_activate_gate( u32 id )
 
       if( was_active && !route->active )
       {
-         struct route_ui_bar *pui = &world.ui_bars[i];
+         struct route_ui_bar *pui = &world_global.ui_bars[i];
          pui->fade_start = pui->segment_start;
          pui->fade_count = pui->segment_count;
-         pui->fade_timer_start = world.time;
+         pui->fade_timer_start = world_global.time;
 
          world_routes_ui_clear( pui );
          vg_success( "CLEARING -> %u %u \n", pui->fade_start,
@@ -589,11 +598,11 @@ VG_STATIC void world_routes_activate_gate( u32 id )
       }
    }
    
-   world.current_run_version ++;
+   world_global.current_run_version ++;
 
-   rc->timing.version = world.current_run_version;
-   rc->timing.time = world.time;
-   world.current_run_version ++;
+   rc->timing.version = world_global.current_run_version;
+   rc->timing.time = world_global.time;
+   world_global.current_run_version ++;
 }
 
 /*
@@ -601,41 +610,32 @@ VG_STATIC void world_routes_activate_gate( u32 id )
  */
 VG_STATIC void world_routes_notify_reset(void)
 {
-   world.rewind_from = world.time;
-   world.rewind_to = world.last_use;
-
-#if 0
-   for( int i=0; i<r->route_count; i++ )
-   {
-      struct route *route = &r->routes[i];
-
-      if( route->active )
-         world_routes_ui_notch( i, r->time - route->latest_pass );
-   }
-#endif
+   world_global.rewind_from = world_global.time;
+   world_global.rewind_to = world_global.last_use;
 }
 
 /* Rewind between the saved points in time */
 VG_STATIC void world_routes_rollback_time( double t )
 {
-   world.time = vg_lerp( world.rewind_to, world.rewind_from, t );
+   world_global.time = vg_lerp( world_global.rewind_to, 
+                                world_global.rewind_from, t );
 }
 
 /* draw lines along the paths */
-VG_STATIC void world_routes_debug(void)
+VG_STATIC void world_routes_debug( world_instance *world )
 {
-   for( int i=0; i<world.node_count; i++ )
+   for( int i=0; i<world->node_count; i++ )
    {
-      struct route_node *rn = &world.nodes[i];
+      struct route_node *rn = &world->nodes[i];
       vg_line_pt3( rn->co, 1.0f, rn->special_type? 0xffffff00: 0xff00b2ff );
    }
 
-   for( int i=0; i<world.route_count; i++ )
+   for( int i=0; i<world->route_count; i++ )
    {
-      struct route *route = &world.routes[i];
+      struct route *route = &world->routes[i];
 
       u32 stack[64];
-      u32 si = world_routes_get_path( route->start, stack );
+      u32 si = world_routes_get_path( world, route->start, stack );
 
       u32 colours[] = { 0xfff58142, 0xff42cbf5, 0xff42f56c, 0xfff542b3,
                         0xff5442f5 };
@@ -646,34 +646,34 @@ VG_STATIC void world_routes_debug(void)
       {
          int sk = (sj+1)%si;
 
-         struct route_node *pj = &world.nodes[stack[sj]],
-                           *pk = &world.nodes[stack[sk]];
+         struct route_node *pj = &world->nodes[stack[sj]],
+                           *pk = &world->nodes[stack[sk]];
          debug_sbpath( pj, pk, cc, (float)i );
       }
    }
 
-   for( int i=0; i<world.node_count; i++ )
+   for( int i=0; i<world->node_count; i++ )
    {
-      struct route_node *ri = &world.nodes[i],
+      struct route_node *ri = &world->nodes[i],
                         *rj = NULL;
       
       for( int j=0; j<2; j++ )
       {
          if( ri->next[j] != 0xffffffff )
          {
-            rj = &world.nodes[ri->next[j]];
+            rj = &world->nodes[ri->next[j]];
             vg_line( ri->co, rj->co, 0x20ffffff );
          }
       }
    }
 }
 
-VG_STATIC void world_routes_create_mesh( u32 route_id )
+VG_STATIC void world_routes_create_mesh( world_instance *world, u32 route_id )
 {
-   struct route *route = &world.routes[ route_id ];
+   struct route *route = &world->routes[ route_id ];
 
    u32 stack[64];
-   u32 si = world_routes_get_path( route->start, stack );
+   u32 si = world_routes_get_path( world, route->start, stack );
 
    u32 last_valid = 0;
 
@@ -681,8 +681,8 @@ VG_STATIC void world_routes_create_mesh( u32 route_id )
    {
       int sk=(sj+1)%si;
 
-      struct route_node *rnj = &world.nodes[ stack[sj] ],
-                        *rnk = &world.nodes[ stack[sk] ],
+      struct route_node *rnj = &world->nodes[ stack[sj] ],
+                        *rnk = &world->nodes[ stack[sk] ],
                         *rnl;
       
       if( rnj->special_type && rnk->special_type )
@@ -696,7 +696,7 @@ VG_STATIC void world_routes_create_mesh( u32 route_id )
 
       if( rnk->special_type )
       {
-         rnl = &world.nodes[ rnk->next[0] ];
+         rnl = &world->nodes[ rnk->next[0] ];
          base_x1 = (float)rnl->ref_count*-0.5f + (float)rnl->current_refs;
       }
 
@@ -743,31 +743,32 @@ VG_STATIC void world_routes_create_mesh( u32 route_id )
          ray_hit ha, hb;
          ha.dist = 8.0f;
          hb.dist = 8.0f;
-         if( ray_world( sa, down, &ha ) && 
-             ray_world( sb, down, &hb ))
+         if( ray_world( world, sa, down, &ha ) && 
+             ray_world( world, sb, down, &hb ))
          {
-            mdl_vert va, vb;
+            scene_vert va, vb;
             
             v3_muladds( ha.pos, up, 0.06f, va.co );
             v3_muladds( hb.pos, up, 0.06f, vb.co );
-            v3_copy( up, va.norm );
-            v3_copy( up, vb.norm );
+
+            scene_vert_pack_norm( &va, up );
+            scene_vert_pack_norm( &vb, up );
             v2_zero( va.uv );
             v2_zero( vb.uv );
 
-            scene_push_vert( world.scene_lines, &va );
-            scene_push_vert( world.scene_lines, &vb );
+            scene_push_vert( world->scene_lines, &va );
+            scene_push_vert( world->scene_lines, &vb );
 
             if( last_valid )
             {
                /* Connect them with triangles */
-               scene_push_tri( world.scene_lines, (u32[3]){ 
+               scene_push_tri( world->scene_lines, (u32[3]){ 
                      last_valid+0-2, last_valid+1-2, last_valid+2-2} );
-               scene_push_tri( world.scene_lines, (u32[3]){ 
+               scene_push_tri( world->scene_lines, (u32[3]){ 
                      last_valid+1-2, last_valid+3-2, last_valid+2-2} );
             }
             
-            last_valid = world.scene_lines->vertex_count;
+            last_valid = world->scene_lines->vertex_count;
          }
          else
             last_valid = 0;
@@ -785,38 +786,43 @@ VG_STATIC void world_routes_create_mesh( u32 route_id )
       rnj->current_refs ++;
    }
 
-   scene_copy_slice( world.scene_lines, &route->sm );
+   scene_copy_slice( world->scene_lines, &route->sm );
 }
 
+VG_STATIC void world_scene_compute_light_clusters( world_instance *world,
+                                                   scene *sc );
 /* 
  * Create the strips of colour that run through the world along course paths
  */
-VG_STATIC void world_routes_generate(void)
+VG_STATIC void world_routes_generate( world_instance *world )
 {
    vg_info( "Generating route meshes\n" );
-   world.scene_lines = scene_init( world.dynamic_vgl, 200000, 300000 );
+   world->scene_lines = scene_init( world_global.generic_heap, 200000, 300000 );
 
-   for( u32 i=0; i<world.route_count; i++ )
-      world_routes_create_mesh( i );
+   for( u32 i=0; i<world->route_count; i++ )
+      world_routes_create_mesh( world, i );
+
+   world_scene_compute_light_clusters( world, world->scene_lines );
 
    vg_acquire_thread_sync();
    {
-      scene_upload( world.scene_lines, &world.mesh_route_lines );
+      scene_upload( world->scene_lines, &world->mesh_route_lines );
    }
    vg_release_thread_sync();
-   vg_linear_del( world.dynamic_vgl, world.scene_lines );
+   vg_linear_del( world_global.generic_heap, world->scene_lines );
 }
 
 /* determine if special type is required for this gate */
-VG_STATIC enum route_special_type world_route_node_type( mdl_node *pnode )
+VG_STATIC enum route_special_type world_route_node_type( world_instance *world,
+                                                         mdl_node *pnode )
 {
    if( pnode->classtype == k_classtype_gate )
    {
-      struct classtype_gate *inf = mdl_get_entdata( world.meta, pnode );
+      struct classtype_gate *inf = mdl_get_entdata( world->meta, pnode );
 
       if( inf->target )
       {
-         mdl_node *pother = mdl_node_from_id( world.meta, inf->target );
+         mdl_node *pother = mdl_node_from_id( world->meta, inf->target );
          
          if( pother->classtype == k_classtype_gate )
          {
@@ -831,7 +837,7 @@ VG_STATIC enum route_special_type world_route_node_type( mdl_node *pnode )
 }
 
 /* count entities and allocate correct amount of memory in advance */
-VG_STATIC void world_routes_allocate(void)
+VG_STATIC void world_routes_allocate( world_instance *world )
 {
    vg_info( "Allocating routes\n" );
 
@@ -841,16 +847,16 @@ VG_STATIC void world_routes_allocate(void)
        gate_count       = 0,
        collector_count  = 0;
    
-   for( int i=0; i<world.meta->info.node_count; i++ )
+   for( int i=0; i<world->meta->info.node_count; i++ )
    {
-      mdl_node *pnode = mdl_node_from_id( world.meta, i );
+      mdl_node *pnode = mdl_node_from_id( world->meta, i );
 
       if( pnode->classtype == k_classtype_route_node ||
           pnode->classtype == k_classtype_gate )
       {
          pnode->sub_uid = node_count;
 
-         enum route_special_type type = world_route_node_type( pnode );
+         enum route_special_type type = world_route_node_type( world, pnode );
 
          if( type == k_route_special_type_gate )
             gate_count ++;
@@ -871,16 +877,18 @@ VG_STATIC void world_routes_allocate(void)
        gate_size        = gate_count      * sizeof(struct route_gate),
        collector_size   = collector_count * sizeof(struct route_collector);
 
-   world.nodes          = vg_linear_alloc( world.dynamic_vgl, node_size );
-   world.routes         = vg_linear_alloc( world.dynamic_vgl, route_size );
-   world.gates          = vg_linear_alloc( world.dynamic_vgl, gate_size );
-   world.collectors     = vg_linear_alloc( world.dynamic_vgl, collector_size );
+   world->nodes      = vg_linear_alloc( world_global.generic_heap, node_size );
+   world->routes     = vg_linear_alloc( world_global.generic_heap, route_size );
+   world->gates      = vg_linear_alloc( world_global.generic_heap, gate_size );
+   world->collectors = vg_linear_alloc( world_global.generic_heap, 
+                                        collector_size );
 }
 
 /* create node from mdl node */
-VG_STATIC struct route_node *world_routes_create_node( mdl_node *pnode )
+VG_STATIC struct route_node *world_routes_create_node( world_instance *world,
+                                                       mdl_node *pnode )
 {
-   struct route_node *rn = &world.nodes[ world.node_count ++ ];
+   struct route_node *rn = &world->nodes[ world->node_count ++ ];
 
    m4x3f transform;
    mdl_node_transform( pnode, transform );
@@ -904,12 +912,12 @@ VG_STATIC struct route_node *world_routes_create_node( mdl_node *pnode )
 }
 
 /* retrieve the correct node id from mdl subuid */
-VG_STATIC u32 world_routes_get_subuid( u32 target )
+VG_STATIC u32 world_routes_get_subuid( world_instance *world, u32 target )
 {
    if( target == 0 )
       return 0xffffffff;
    else
-      return mdl_node_from_id( world.meta, target )->sub_uid;
+      return mdl_node_from_id( world->meta, target )->sub_uid;
 }
 
 #if 0
@@ -923,26 +931,27 @@ VG_STATIC void world_id_fixup( u32 *uid, mdl_context *mdl )
 #endif
 
 /* process gate attachement onto node */
-VG_STATIC void world_routes_process_gate( struct route_node *rn, 
+VG_STATIC void world_routes_process_gate( world_instance *world,
+                                          struct route_node *rn, 
                                           mdl_node *pnode )
 {
-   struct classtype_gate *inf = mdl_get_entdata( world.meta, pnode );
+   struct classtype_gate *inf = mdl_get_entdata( world->meta, pnode );
 
    /* H is later scaled based on link distance */
    v3_normalize( rn->h );
 
-   rn->next[0] = world_routes_get_subuid( inf->target );
+   rn->next[0] = world_routes_get_subuid( world, inf->target );
    rn->next[1] = 0xffffffff;
-   rn->special_type = world_route_node_type( pnode );
+   rn->special_type = world_route_node_type( world, pnode );
 
    /* process gate type */
    if( rn->special_type == k_route_special_type_gate )
    {
-      mdl_node *pother = mdl_node_from_id( world.meta, inf->target );
+      mdl_node *pother = mdl_node_from_id( world->meta, inf->target );
       
-      struct route_gate *rg = &world.gates[ world.gate_count ];
+      struct route_gate *rg = &world->gates[ world->gate_count ];
 
-      rg->node_id = world.node_count-1;
+      rg->node_id = world->node_count-1;
       rg->timing.time = 0.0;
       rg->timing.version = 0;
 
@@ -953,34 +962,35 @@ VG_STATIC void world_routes_process_gate( struct route_node *rn,
       v2_copy( inf->dims,  rg->gate.dims );
 
       gate_transform_update( &rg->gate );
-      rn->special_id = world.gate_count;
+      rn->special_id = world->gate_count;
 
-      world.gate_count ++;
+      world->gate_count ++;
    }
 
    /* process collector type */
    else if( rn->special_type == k_route_special_type_collector )
    {
       struct route_collector *rc = 
-         &world.collectors[ world.collector_count ];
+         &world->collectors[ world->collector_count ];
 
       rc->timing.time = 0.0;
       rc->timing.version = 0;
 
-      rn->special_id = world.collector_count;
-      world.collector_count ++;
+      rn->special_id = world->collector_count;
+      world->collector_count ++;
    }
    else
       vg_fatal_exit_loop( "Invalid state" );
 }
 
 /* create route from node description */
-VG_STATIC void world_routes_create_route( mdl_node *pnode )
+VG_STATIC void world_routes_create_route( world_instance *world,
+                                          mdl_node *pnode )
 {
-   mdl_context *mdl = world.meta;
+   mdl_context *mdl = world->meta;
 
    struct classtype_route *inf = mdl_get_entdata( mdl, pnode );
-   struct route *route = &world.routes[ world.route_count ];
+   struct route *route = &world->routes[ world->route_count ];
    memset( route, 0, sizeof(struct route) );
 
    v3_copy( inf->colour, route->colour );
@@ -996,12 +1006,12 @@ VG_STATIC void world_routes_create_route( mdl_node *pnode )
       }
    }
 
-   route->start = world_routes_get_subuid( inf->id_start );
+   route->start = world_routes_get_subuid( world, inf->id_start );
    route->active = 0;
    route->factive = 0.0f;
    mdl_node_transform( pnode, route->scoreboard_transform );
 
-   struct route_ui_bar *pui = &world.ui_bars[ world.route_count ];
+   struct route_ui_bar *pui = &world_global.ui_bars[ world->route_count ];
    pui->indices_head = k_route_ui_max_indices - 9;
    pui->vertex_head = k_route_ui_max_verts - 200;
    pui->segment_start = 0;
@@ -1010,14 +1020,14 @@ VG_STATIC void world_routes_create_route( mdl_node *pnode )
    pui->fade_count = 0;
    pui->fade_timer_start = 0.0;
 
-   world.route_count ++;
+   world->route_count ++;
 }
 
 /* load all routes from model header */
-VG_STATIC void world_routes_process(void)
+VG_STATIC void world_routes_process( world_instance *world )
 {
    vg_info( "Initializing routes\n" );
-   mdl_context *mdl = world.meta;
+   mdl_context *mdl = world->meta;
 
    for( int i=0; i<mdl->info.node_count; i++ )
    {
@@ -1026,38 +1036,38 @@ VG_STATIC void world_routes_process(void)
       if( pnode->classtype == k_classtype_route_node ||
           pnode->classtype == k_classtype_gate )
       {
-         struct route_node *rn = world_routes_create_node( pnode );
+         struct route_node *rn = world_routes_create_node( world, pnode );
 
          if( pnode->classtype == k_classtype_gate )
          {
-            world_routes_process_gate( rn, pnode );
+            world_routes_process_gate( world, rn, pnode );
          }
          else
          {
             struct classtype_route_node *inf = mdl_get_entdata( mdl, pnode );
-            rn->next[0] = world_routes_get_subuid( inf->target  );
-            rn->next[1] = world_routes_get_subuid( inf->target1 );
+            rn->next[0] = world_routes_get_subuid( world, inf->target  );
+            rn->next[1] = world_routes_get_subuid( world, inf->target1 );
          }
       }
       else if( pnode->classtype == k_classtype_route )
       {
-         world_routes_create_route( pnode );
+         world_routes_create_route( world, pnode );
       }
    }
 
    /*
     * Gather references
     */
-   for( int i=0; i<world.route_count; i++ )
+   for( int i=0; i<world->route_count; i++ )
    {
-      struct route *route = &world.routes[i];
+      struct route *route = &world->routes[i];
 
       u32 stack[64];
-      u32 si = world_routes_get_path( route->start, stack );
+      u32 si = world_routes_get_path( world, route->start, stack );
 
       for( int sj=0; sj<si; sj++ )
       {
-         struct route_node *rn = &world.nodes[ stack[sj] ];
+         struct route_node *rn = &world->nodes[ stack[sj] ];
          rn->route_ids[ rn->ref_count ++ ] = i;
 
          if( rn->ref_count > 4 )
@@ -1074,20 +1084,20 @@ VG_STATIC void world_routes_process(void)
 
 VG_STATIC void world_routes_init(void)
 {
-   world.current_run_version = 2;
-   world.time = RESET_MAX_TIME*2.0;
-   world.last_use = 0.0;
+   world_global.current_run_version = 2;
+   world_global.time = RESET_MAX_TIME*2.0;
+   world_global.last_use = 0.0;
 
-   shader_route_register();
+   shader_scene_route_register();
    shader_routeui_register();
 
    vg_acquire_thread_sync();
    {
       /* UI buffers */
-      for( int i=0; i<vg_list_size(world.ui_bars); i++ )
+      for( int i=0; i<vg_list_size(world_global.ui_bars); i++ )
       {
          /* OpenGL strips */
-         struct route_ui_bar *pui = &world.ui_bars[i];
+         struct route_ui_bar *pui = &world_global.ui_bars[i];
 
          glGenVertexArrays( 1, &pui->vao );
          glGenBuffers( 1, &pui->vbo );
@@ -1114,67 +1124,75 @@ VG_STATIC void world_routes_init(void)
    vg_release_thread_sync();
 }
 
-VG_STATIC void world_routes_update(void)
+VG_STATIC void world_routes_update( world_instance *world )
 {
-   world.time += vg.time_delta;
+   world_global.time += vg.time_delta;
 
-   for( int i=0; i<world.route_count; i++ )
+   for( int i=0; i<world->route_count; i++ )
    {
-      struct route *route = &world.routes[i];
+      struct route *route = &world->routes[i];
       route->factive = vg_lerpf( route->factive, route->active, 
                                  0.6f*vg.time_delta );
 
       if( route->active )
       {
-         world_routes_ui_updatetime(i, world.time - route->latest_pass );
+         world_routes_ui_updatetime(i, world_global.time - route->latest_pass );
       }
    }
 }
 
 VG_STATIC void bind_terrain_noise(void);
-VG_STATIC void render_world_routes( camera *cam )
+VG_STATIC void world_bind_light_array( world_instance *world,
+                                       GLuint shader, GLuint location, 
+                                       int slot );
+
+VG_STATIC void render_world_routes( world_instance *world, camera *cam )
 {
    m4x3f identity_matrix;
    m4x3_identity( identity_matrix );
 
-   shader_route_use();
-   shader_route_uTexGarbage(0);
-   shader_link_standard_ub( _shader_route.id, 2 );
+   shader_scene_route_use();
+   shader_scene_route_uTexGarbage(0);
+   world_link_lighting_ub( world, _shader_scene_route.id );
+   world_bind_position_texture( world, _shader_scene_route.id, 
+                        _uniform_scene_route_g_world_depth, 2 );
+   world_bind_light_array( world, _shader_scene_route.id,
+                        _uniform_scene_route_uLightsArray, 3 );
    bind_terrain_noise();
 
-   shader_route_uPv( cam->mtx.pv );
-   shader_route_uPvmPrev( cam->mtx_prev.pv );
-   shader_route_uMdl( identity_matrix );
-   shader_route_uCamera( cam->transform[3] );
-   shader_route_uBoard0( TEMP_BOARD_0 );
-   shader_route_uBoard1( TEMP_BOARD_1 );
+   shader_scene_route_uPv( cam->mtx.pv );
+   shader_scene_route_uPvmPrev( cam->mtx_prev.pv );
+   shader_scene_route_uMdl( identity_matrix );
+   shader_scene_route_uCamera( cam->transform[3] );
+   shader_scene_route_uBoard0( TEMP_BOARD_0 );
+   shader_scene_route_uBoard1( TEMP_BOARD_1 );
 
-   mesh_bind( &world.mesh_route_lines );
+   mesh_bind( &world->mesh_route_lines );
 
-   for( int i=0; i<world.route_count; i++ )
+   for( int i=0; i<world->route_count; i++ )
    {
-      struct route *route = &world.routes[i];
+      struct route *route = &world->routes[i];
 
       v4f colour;
       v3_lerp( (v3f){0.7f,0.7f,0.7f}, route->colour, route->factive, colour );
       colour[3] = 1.0f;
 
-      shader_route_uColour( colour );
+      shader_scene_route_uColour( colour );
       mdl_draw_submesh( &route->sm );
    }
 }
 
-VG_STATIC void render_world_routes_ui(void)
+VG_STATIC void render_world_routes_ui( world_instance *world )
 {
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBlendEquation(GL_FUNC_ADD);
 
    float active_offset = 0.0f;
-   for( int i=0; i<world.route_count; i++ )
+   for( int i=0; i<world->route_count; i++ )
    {
-      struct route *route = &world.routes[i];
-      world_routes_ui_draw( i, route->colour, active_offset );
+      struct route *route = &world->routes[i];
+      world_routes_ui_draw( world, i, route->colour, active_offset );
       active_offset += route->factive;
    }