minor performance stuff
[carveJwlIkooP6JGAAIwe30JlM.git] / world_routes.c
index a66f93ffc00e3f3d8c97d0a9503b694850f29ad7..3e21df0def867a4187f0c776aad3b2116747715e 100644 (file)
@@ -6,6 +6,7 @@
 #define ROUTES_C
 
 #include <time.h>
+#include "entity.h"
 #include "world_routes.h"
 #include "world_gate.h"
 #include "world_load.h"
@@ -14,6 +15,7 @@
 #include "font.h"
 #include "pointcloud.h"
 #include "gui.h"
+#include "steam.h"
 
 #include "shaders/scene_route.h"
 #include "shaders/routeui.h"
@@ -21,7 +23,7 @@
 
 VG_STATIC 
 void world_routes_local_set_record( world_instance *world, ent_route *route,
-                                    double lap_time )
+                                    f64 lap_time )
 {
    vg_success( "  NEW LAP TIME: %f\n", lap_time );
 
@@ -30,25 +32,18 @@ void world_routes_local_set_record( world_instance *world, ent_route *route,
       if( time_centiseconds > (float)0xfffe )   /* skill issue */
          return;
 
-      highscore_record temp;
-      temp.trackid  = route->official_track_id;
-      temp.datetime = time(NULL);
-      temp.playerid = 0;
-      temp.points   = 0;
-      temp.time     = time_centiseconds;
-
-#if 0
-      highscores_push_record( &temp );
-#endif
-
       struct track_info *ti = &track_infos[ route->official_track_id ];
+      highscore_record *record = &ti->record;
+      record->trackid  = route->official_track_id;
+      record->datetime = time(NULL);
+      record->playerid = 0;
+      record->points   = 0;
+      record->time     = time_centiseconds;
       ti->push = 1;
       
       if( ti->achievement_id ){
-#if 0
          steam_set_achievement( ti->achievement_id );
          steam_store_achievements();
-#endif
       }
    }
    else{
@@ -138,7 +133,7 @@ VG_STATIC void world_routes_activate_entry_gate( world_instance *world,
    world_static.last_use = world_static.time;
 
    /* disable all routes and leave the world */
-   if( rg->type == k_gate_type_nonlocel ){
+   if( rg->flags & k_ent_gate_nonlocal ){
       for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
          ent_route *route = mdl_arritm( &world->ent_route, i );
          route->active_checkpoint = 0xffff;
@@ -184,7 +179,7 @@ VG_STATIC void world_routes_debug( world_instance *world )
 {
    for( u32 i=0; i<mdl_arrcount(&world->ent_route_node); i++ ){
       ent_route_node *rn = mdl_arritm(&world->ent_route_node,i);
-      vg_line_pt3( rn->co, 0.25f, VG__WHITE );
+      vg_line_point( rn->co, 0.25f, VG__WHITE );
    }
 
    for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
@@ -256,15 +251,56 @@ void world_routes_pointcloud_spot( world_instance *world,
       v3_sub( point, pcbuf->boundary[0], pos );
       v3_mul( pos, inv_ext, pos );
 
-      for( u32 i=0; i<3; i++ ){
-         vert->pos[i] = (pos[i]-0.5f) * 32767.0f;
-      }
-
       float dist = 1.0f-(v3_length(jitter));
 
-      for( u32 i=0; i<4; i++ ){
-         vert->colour[i] = colour[i] * 255.0f * dist*dist;
-      }
+      v4f final_colour;
+      v4_muls( colour, dist*dist, final_colour );
+
+      pointcloud_packvert( vert, pos, final_colour );
+   }
+}
+
+/* 
+ *    '
+ *    .
+ *    |
+ *    |
+ *   /#\
+ * -'###`-
+ */
+VG_STATIC 
+void world_routes_pointcloud_tower( world_instance *world, 
+                                    pointcloud_buffer *pcbuf, 
+                                    v3f co, f32 radius, f32 height,
+                                    u32 samples, v4f colour )
+{
+   v3f inv_ext;
+   v3_sub( pcbuf->boundary[1], pcbuf->boundary[0], inv_ext );
+   v3_div( (v3f){1.0f,1.0f,1.0f}, inv_ext, inv_ext );
+
+   for( u32 j=0; j<samples; j++ ){
+      if( pcbuf->count >= pcbuf->max )
+         return;
+
+      pointcloud_vert *vert = &pcbuf->buf[ pcbuf->count ++ ];
+      
+      v3f point;
+      point[0] = vg_randf64()*2.0f-1.0f;
+      point[1] = 0.0f;
+      point[2] = vg_randf64()*2.0f-1.0f;
+      v3_normalize( point );
+      v3_muls( point, sqrtf(vg_randf64()), point );
+
+      f32 h = vg_randf64();
+      point[1] = h*h*h*height;
+      point[0] *= radius;
+      point[2] *= radius;
+
+      v3_add( point, co, point );
+      v3_sub( point, pcbuf->boundary[0], point );
+      v3_mul( point, inv_ext, point );
+
+      pointcloud_packvert( vert, point, colour );
    }
 }
 
@@ -329,8 +365,8 @@ void world_routes_place_curve( world_instance *world, ent_route *route,
       ha.dist = 8.0f;
       hb.dist = 8.0f;
 
-      int resa = ray_world( world, sa, down, &ha ),
-          resb = ray_world( world, sb, down, &hb );
+      int resa = ray_world( world, sa, down, &ha, k_material_flag_ghosts ),
+          resb = ray_world( world, sb, down, &hb, k_material_flag_ghosts );
       
       if( pcbuf && resa ){
          world_routes_pointcloud_spot( world, pcbuf, ha.pos, 
@@ -617,10 +653,6 @@ VG_STATIC f64 world_routes_scatter_surface_points( world_instance *world,
          v3_sub( pt, pcbuf->boundary[0], pos );
          v3_mul( pos, inv_ext, pos );
 
-         for( u32 i=0; i<3; i++ ){
-            vert->pos[i] = (pos[i]-0.5f) * 32767.0f;
-         }
-
          static v4f colours[] = {
             [k_surface_prop_concrete] = { 0.13, 0.15, 0.17, 1.0 },
             [k_surface_prop_grass]    = { 0.07, 0.1, 0.14, 1.0 },
@@ -630,16 +662,13 @@ VG_STATIC f64 world_routes_scatter_surface_points( world_instance *world,
          };
 
          v4f col = {0.0f,0.0f,0.0f,0.0f};
-         if( surf->info.surface_prop < vg_list_size(colours) ){
+         if( surf->info.surface_prop < vg_list_size(colours) )
             v4_copy( colours[surf->info.surface_prop], col );
-         }
 
          f32 brightness = v3_dot(vn,light_dir)*0.5f+0.5f;
          v3_muls( col, brightness, col );
 
-         for( u32 j=0; j<4; j++ ){
-            vert->colour[j] = col[j] * 255.0f;
-         }
+         pointcloud_packvert( vert, pos, col );
       }
    }
 
@@ -683,6 +712,10 @@ VG_STATIC void world_routes_surface_grid( world_instance *world,
                u32 *tri = &world->scene_geo.arrindices[ idx*3 ];
                v3f vs[3];
 
+               u16 mask = k_material_flag_preview_visibile;
+               if( !(world->scene_geo.arrvertices[tri[0]].flags & mask) ) 
+                  continue;
+
                for( u32 i=0; i<3; i++ ){
                   v3_copy( world->scene_geo.arrvertices[tri[i]].co, vs[i] );
                }
@@ -690,11 +723,6 @@ VG_STATIC void world_routes_surface_grid( world_instance *world,
                f32 t;
                if( ray_tri( vs, ro, dir, &t ) ){
                   v3_muladds( ro, dir, t, hit );
-                  struct world_surface *m1 = 
-                     world_tri_index_surface( world, tri[0] );
-
-                  if( !(m1->info.flags & k_material_flag_preview_visibile) )
-                     continue;
 
                   if( world->water.enabled )
                      if( hit[1] < world->water.height )
@@ -708,13 +736,7 @@ VG_STATIC void world_routes_surface_grid( world_instance *world,
                   v3_sub( hit, pcbuf->boundary[0], co );
                   v3_mul( co, inv_ext, co );
 
-                  for( u32 i=0; i<3; i++ ){
-                     vert->pos[i] = (co[i]-0.5f) * 32767.0f;
-                  }
-
-                  for( u32 i=0; i<4; i++ ){
-                     vert->colour[i] = colour[i] * 255.0f;
-                  }
+                  pointcloud_packvert( vert, co, colour );
                }
             }
          }
@@ -722,12 +744,37 @@ VG_STATIC void world_routes_surface_grid( world_instance *world,
    }
 }
 
+VG_STATIC void world_write_preview( addon_reg *reg, pointcloud_buffer *pcbuf ){
+   if( reg->alias.workshop_id ) return;
+
+   /* 
+    * FIXME: BUG: cannot correctly handle workshop because there is a stalling
+    * call below, which deadlocks the scene upload. TODO: improve the async
+    * stack to handle out of order execution. MAYBE
+    */
+
+   char path_buf[4096];
+   vg_str path;
+   vg_strnull( &path, path_buf, 4096 );
+
+   addon_get_content_folder( reg, &path );
+   vg_strcat( &path, "/preview.bin" );
+
+   if( !vg_strgood( &path ) ) vg_fatal_error( "Path too long\n" );
+   FILE *fp = fopen( path_buf, "wb" );
+   if( !fp ) vg_fatal_error( "Cannot open '%s' for writing\n", path_buf );
+   
+   fwrite( pcbuf, sizeof(struct pointcloud_buffer) + 
+                  sizeof(struct pointcloud_vert)*pcbuf->count, 1, fp );
+   fclose( fp );
+   vg_info( "written %s\n", path_buf );
+}
+
 /* 
  * Create the strips of colour that run through the world along course paths
  */
-VG_STATIC void world_gen_routes_generate(void)
-{
-   world_instance *world = world_loading_instance();
+VG_STATIC void world_gen_routes_generate( u32 instance_id ){
+   world_instance *world = &world_static.instances[ instance_id ];
    vg_info( "Generating route meshes\n" );
    vg_async_stall();
 
@@ -739,7 +786,7 @@ VG_STATIC void world_gen_routes_generate(void)
    vg_async_item *call_pointcloud = NULL;
    pointcloud_buffer *pcbuf = NULL;
 
-   if( world_loader.generate_point_cloud ){
+   if( instance_id <= 1 /*world_loader.generate_point_cloud*/ ){
       call_pointcloud = vg_async_alloc( 
             sizeof(pointcloud_buffer) + 
             sizeof(pointcloud_vert)*POINTCLOUD_POINTS );
@@ -800,24 +847,37 @@ VG_STATIC void world_gen_routes_generate(void)
       world_routes_gen_meshes( world, i, &world->scene_lines, pcbuf );
    }
 
-   if( world_loader.generate_point_cloud ){
+   if( instance_id <= 1 /*world_loader.generate_point_cloud*/ ){
       f64 area = 0.0;
+
+#if VG_RELEASE
       area = world_routes_scatter_surface_points( world, pcbuf, 16.0f );
       world_routes_surface_grid( world, pcbuf );
-      vg_info( "Distrubuted %u points over %fkm^2!\n", 
+
+      for( u32 i=0; i<mdl_arrcount( &world->ent_gate ); i++ ){
+         ent_gate *gate = mdl_arritm( &world->ent_gate, i );
+
+         world_routes_pointcloud_tower( world, pcbuf, gate->co[0], 
+                                        2.0f, 50.0f, 128, 
+                                        (v4f){0.2f,0.2f,0.2f,1.0f} );
+      }
+#endif
+
+      vg_info( "Distributed %u points over %fkm^2!\n", 
                 pcbuf->count, area/1e6f );
+
+      world_write_preview( instance_id? world_static.addon_client:
+                                        world_static.addon_hub, 
+                                        pcbuf );
       vg_async_dispatch( call_pointcloud, async_pointcloud_sub );
    }
 
    vg_async_dispatch( call_scene, async_scene_upload );
-
    world_routes_clear( world );
 }
 
 /* load all routes from model header */
-VG_STATIC void world_gen_routes_ent_init(void)
-{
-   world_instance *world = world_loading_instance();
+VG_STATIC void world_gen_routes_ent_init( world_instance *world ){
    vg_info( "Initializing routes\n" );
 
    for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
@@ -852,7 +912,8 @@ VG_STATIC void world_gen_routes_ent_init(void)
             }
          }
 
-         if( gate->type == k_gate_type_teleport ){
+         if( (gate->flags & k_ent_gate_linked) &
+            !(gate->flags & k_ent_gate_nonlocal) ){
             gate = mdl_arritm(&world->ent_gate, gate->target );
 
             for( u32 k=0; k<4; k++ ){
@@ -921,7 +982,8 @@ VG_STATIC void world_routes_fixedupdate( world_instance *world )
 
          int l = rb_sphere__scene( particle->obj.rb.to_world,
                                    &particle->obj.inf.sphere,
-                                   NULL, &world->rb_geo.inf.scene, buf );
+                                   NULL, &world->rb_geo.inf.scene, buf,
+                                   k_material_flag_ghosts );
 
          for( int j=0; j<l; j++ ){
             buf[j].rba = &particle->obj.rb;
@@ -1050,12 +1112,15 @@ VG_STATIC void world_routes_update_timer_texts( world_instance *world )
             positions[0][1] = h1;
          }
 
-         m3x3_copy( gate->to_world, text->transform );
+         m4x3f mmdl;
+         ent_gate_get_mdl_mtx( gate, mmdl );
+
+         m3x3_copy( mmdl, text->transform );
          float ratio = v3_length(text->transform[0]) / 
                         v3_length(text->transform[1]);
 
          m3x3_scale( text->transform, (v3f){ size, size*ratio, 0.1f } );
-         m4x3_mulv( gate->to_world, positions[j], text->transform[3] );
+         m4x3_mulv( mmdl, positions[j], text->transform[3] );
       }
    }
 }
@@ -1183,7 +1248,8 @@ VG_STATIC void render_world_routes( world_instance *world, camera *cam,
          colour[3] = 1.0f-text->route->factive;
 
          shader_model_font_uColour( colour );
-         font3d_simple_draw( &gui.font, 0, text->text, cam, text->transform );
+         font3d_simple_draw( &gui.font, 0, k_font_shader_default,
+                              text->text, cam, text->transform );
       }
 
       shader_model_font_uOffset( (v4f){0.0f,0.0f,0.0f,1.0f} );
@@ -1245,7 +1311,10 @@ VG_STATIC void render_world_routes( world_instance *world, camera *cam,
 
          ent_checkpoint *cp = mdl_arritm( &world->ent_checkpoint, next );
          ent_gate *gate = mdl_arritm( &world->ent_gate, cp->gate_index );
-         shader_model_gate_uMdl( gate->to_world );
+
+         m4x3f mmdl;
+         ent_gate_get_mdl_mtx( gate, mmdl );
+         shader_model_gate_uMdl( mmdl );
 
          for( u32 j=0; j<4; j++ ){
             if( gate->routes[j] == i ){