well yeah i guess
authorhgn <hgodden00@gmail.com>
Tue, 25 Oct 2022 02:30:41 +0000 (03:30 +0100)
committerhgn <hgodden00@gmail.com>
Tue, 25 Oct 2022 02:30:41 +0000 (03:30 +0100)
51 files changed:
audio.h
blender_export.py
build.sh
bvh.h
camera.h
common.h
highscores.h
main.c
menu.h
model.h
models_src/alter.mdl
models_src/ch_default.mdl
models_src/ch_empty.mdl
models_src/ch_jordan.mdl
models_src/ch_mike.mdl
models_src/ch_new.mdl
models_src/ch_outlaw.001.mdl [new file with mode: 0644]
models_src/ch_outlaw.mdl
models_src/epic_scene.mdl
models_src/mp_dev.mdl
models_src/mp_test.mdl [new file with mode: 0644]
models_src/rs_cars.mdl
models_src/rs_chicken.mdl
models_src/rs_foliage.mdl
models_src/rs_gate.mdl
models_src/rs_menu.mdl
models_src/rs_scoretext.mdl
models_src/rs_skydome.mdl
models_src/rs_vig.mdl
network.h
network_msg.h
player.h
player_animation.h
player_audio.h
player_model.h
player_physics.h
player_ragdoll.h
render.h
rigidbody.h
scene.h
server.c
skeleton.h
steam.h
vg_config.h
world.h
world_gate.h
world_gen.h
world_render.h
world_routes.h
world_sfd.h
world_water.h

diff --git a/audio.h b/audio.h
index fd212868153367ca2c19c7aad147ffb1adc684e5..34ebb3a4ad3a7866468654fcc932a898d4337d76 100644 (file)
--- a/audio.h
+++ b/audio.h
@@ -16,69 +16,68 @@ static int   k_audio_debug_soundscape = 0;
 
 audio_clip audio_board[] =
 {
-   {.path="sound/skate.ogg", .source_mode=k_audio_source_compressed },
-   {.path="sound/wheel.ogg", .source_mode=k_audio_source_compressed },
-   {.path="sound/slide.ogg", .source_mode=k_audio_source_compressed },
-   {.path="sound/reverb.ogg",.source_mode=k_audio_source_compressed }
+   { .path="sound/skate.ogg" },
+   { .path="sound/wheel.ogg" },
+   { .path="sound/slide.ogg" },
+   { .path="sound/reverb.ogg" }
 };
 
 audio_clip audio_splash =
-{ .path = "sound/splash.ogg", .source_mode=k_audio_source_compressed };
+{ .path = "sound/splash.ogg" };
 
 audio_clip audio_jumps[] = {
-   { .path = "sound/jump0.ogg", .source_mode=k_audio_source_compressed, },
-   { .path = "sound/jump1.ogg", .source_mode=k_audio_source_compressed, },
+   { .path = "sound/jump0.ogg" },
+   { .path = "sound/jump1.ogg" },
 };
 
 audio_clip audio_footsteps[] = {
- {.path = "sound/step_concrete0.ogg", .source_mode=k_audio_source_compressed,},
- {.path = "sound/step_concrete1.ogg", .source_mode=k_audio_source_compressed,},
- {.path = "sound/step_concrete2.ogg", .source_mode=k_audio_source_compressed,},
- {.path = "sound/step_concrete3.ogg", .source_mode=k_audio_source_compressed,}
+ {.path = "sound/step_concrete0.ogg" },
+ {.path = "sound/step_concrete1.ogg" },
+ {.path = "sound/step_concrete2.ogg" },
+ {.path = "sound/step_concrete3.ogg" }
 };
 
 audio_clip audio_lands[] = {
-   { .path = "sound/land0.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/land1.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/land2.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/landsk0.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/landsk1.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/onto.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/outo.ogg", .source_mode=k_audio_source_compressed },
+   { .path = "sound/land0.ogg" },
+   { .path = "sound/land1.ogg" },
+   { .path = "sound/land2.ogg" },
+   { .path = "sound/landsk0.ogg" },
+   { .path = "sound/landsk1.ogg" },
+   { .path = "sound/onto.ogg" },
+   { .path = "sound/outo.ogg" },
 };
 
 audio_clip audio_water[] = {
-   { .path = "sound/wave0.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/wave1.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/wave2.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/wave3.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/wave4.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/wave5.ogg", .source_mode=k_audio_source_compressed }
+   { .path = "sound/wave0.ogg" },
+   { .path = "sound/wave1.ogg" },
+   { .path = "sound/wave2.ogg" },
+   { .path = "sound/wave3.ogg" },
+   { .path = "sound/wave4.ogg" },
+   { .path = "sound/wave5.ogg" }
 };
 
 audio_clip audio_grass[] = {
-   { .path = "sound/grass0.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/grass1.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/grass2.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/grass3.ogg", .source_mode=k_audio_source_compressed },
+   { .path = "sound/grass0.ogg" },
+   { .path = "sound/grass1.ogg" },
+   { .path = "sound/grass2.ogg" },
+   { .path = "sound/grass3.ogg" },
 };
 
 audio_clip audio_ambience[] =
 {
-   {.path="sound/town_generic.ogg", 
-      .source_mode=k_audio_source_compressed }
+   { .path="sound/town_generic.ogg" }
 };
 
 audio_clip audio_gate_pass = {
-   .path = "sound/gate_pass.ogg", .source_mode=k_audio_source_compressed
+   .path = "sound/gate_pass.ogg"
 };
 
 audio_clip audio_gate_lap = {
-   .path = "sound/gate_lap.ogg", .source_mode=k_audio_source_compressed
+   .path = "sound/gate_lap.ogg"
 };
 
 audio_clip audio_gate_ambient = {
-.path = "sound/gate_ambient.ogg", .source_mode=k_audio_source_compressed
+.path = "sound/gate_ambient.ogg"
 };
 
 audio_player ambient_player =
@@ -92,16 +91,16 @@ audio_player audio_rewind_player =
 };
 
 audio_clip audio_rewind[] = {
-{ .path = "sound/rewind_start.ogg", .source_mode=k_audio_source_compressed },
-{ .path = "sound/rewind_end_1.5.ogg", .source_mode=k_audio_source_compressed},
-{ .path = "sound/rewind_end_2.5.ogg", .source_mode=k_audio_source_compressed },
-{ .path = "sound/rewind_end_6.5.ogg", .source_mode=k_audio_source_compressed },
-{ .path = "sound/rewind_clack.ogg", .source_mode=k_audio_source_compressed },
+{ .path = "sound/rewind_start.ogg" },
+{ .path = "sound/rewind_end_1.5.ogg" },
+{ .path = "sound/rewind_end_2.5.ogg" },
+{ .path = "sound/rewind_end_6.5.ogg" },
+{ .path = "sound/rewind_clack.ogg" },
 };
 
 audio_clip audio_ui[] = {
-   { .path = "sound/ui_click.ogg", .source_mode=k_audio_source_compressed },
-   { .path = "sound/ui_ding.ogg", .source_mode=k_audio_source_compressed },
+   { .path = "sound/ui_click.ogg" },
+   { .path = "sound/ui_ding.ogg" },
 };
 
 audio_player ambient_sprites[4] =
@@ -322,13 +321,13 @@ static void audio_debug_soundscapes(void)
    char buf[64];
    snprintf( buf, 31, "occlusion: %.5f", audio_occlusion_current );
 
-   ui_global_ctx.cursor[0] = 450;
-   ui_global_ctx.cursor[1] = 10;
-   ui_global_ctx.cursor[2] = audio_occlusion_current * 200.0f;
-   ui_global_ctx.cursor[3] = 20;
+   vg_uictx.cursor[0] = 450;
+   vg_uictx.cursor[1] = 10;
+   vg_uictx.cursor[2] = audio_occlusion_current * 200.0f;
+   vg_uictx.cursor[3] = 20;
 
-   gui_fill_rect( ui_global_ctx.cursor, 0x55cccccc );
-   gui_text( ui_global_ctx.cursor, buf, 1, 0 );
+   ui_fill_rect( vg_uictx.cursor, 0x55cccccc );
+   ui_text( vg_uictx.cursor, buf, 1, 0 );
 }
 
 #endif /* AUDIO_H */
index c069d7f925fa5412562eadee4e9bc5e27dd1e38e..2ed183aa075b7708b8f3b8b021700ea1e7e49ea5 100644 (file)
@@ -47,6 +47,7 @@ class mdl_node(Structure):
    _fields_ = [("co",c_float*3),
                ( "q",c_float*4),
                ( "s",c_float*3),
+               ("sub_uid",c_uint32),        # dont use
                ("submesh_start",c_uint32),
                ("submesh_count",c_uint32),
                ("classtype",c_uint32),
@@ -59,6 +60,8 @@ class mdl_header(Structure):
    _fields_ = [("identifier",c_uint32),
                ("version",c_uint32),
                ("file_length",c_uint32),
+               ("pad0",c_uint32),
+
                ("vertex_count",c_uint32),
                ("vertex_offset",c_uint32),
 
@@ -76,11 +79,16 @@ class mdl_header(Structure):
 
                ("anim_count",c_uint32),
                ("anim_offset",c_uint32),
-
+               
+               ("strings_length",c_uint32),
                ("strings_offset",c_uint32),
+
+               ("entdata_length",c_uint32),
                ("entdata_offset",c_uint32),
-               ("animdata_offset",c_uint32)
-               ]
+
+               ("keyframe_count",c_uint32),
+               ("keyframe_offset",c_uint32)]
+               
 
 class mdl_animation(Structure):
    _pack_ = 1
@@ -187,6 +195,10 @@ def write_model(collection_name):
    header.node_count = 0
    header.material_count = 0
    header.file_length = 0
+
+   header.strings_length = 0
+   header.entdata_length = 0
+   header.keyframe_count = 0
    
    mesh_cache = {}
    string_cache = {}
@@ -200,10 +212,8 @@ def write_model(collection_name):
    indice_buffer = []
    node_buffer = []
    entdata_buffer = []
-   entdata_length = 0
 
    anim_buffer = []
-   animdata_length = 0
    animdata_buffer = []
 
    def emplace_string( s ):
@@ -596,7 +606,7 @@ def write_model(collection_name):
 
       # Process entity data
       # ==================================================================
-      node.offset = entdata_length
+      node.offset = header.entdata_length
 
       if classtype != 'k_classtype_none':
          disptype = classtype
@@ -629,7 +639,7 @@ def write_model(collection_name):
          node.classtype = 12
 
          armature = armature_def['obj']
-         entdata_length += sizeof( classtype_skin )
+         header.entdata_length += sizeof( classtype_skin )
 
          skin = classtype_skin()
          skin.skeleton = armature.cv_data.uid
@@ -637,7 +647,7 @@ def write_model(collection_name):
       
       elif classtype == 'k_classtype_skeleton':
          node.classtype = 11
-         entdata_length += sizeof( classtype_skeleton )
+         header.entdata_length += sizeof( classtype_skeleton )
          skeleton = classtype_skeleton()
 
          armature_def = graph_lookup[obj]
@@ -669,7 +679,7 @@ def write_model(collection_name):
                   anim = mdl_animation()
                   anim.pstr_name = emplace_string( NLAStrip.action.name )
                   anim.rate = 30.0
-                  anim.offset = animdata_length
+                  anim.offset = header.keyframe_count
                   anim.length = anim_end-anim_start
                   
                   # Export the fucking keyframes
@@ -723,7 +733,7 @@ def write_model(collection_name):
                               kf.s[2] = sca[1]
 
                               animdata_buffer += [kf]
-                              animdata_length += sizeof(mdl_keyframe)
+                              header.keyframe_count += 1
                               break
 
                   anim_buffer += [anim]
@@ -739,7 +749,7 @@ def write_model(collection_name):
 
       elif classtype == 'k_classtype_bone':
          node.classtype = 10
-         entdata_length += sizeof( classtype_bone )
+         header.entdata_length += sizeof( classtype_bone )
          
          bone = classtype_bone()
          bone.deform = node_def['deform']
@@ -789,7 +799,7 @@ def write_model(collection_name):
 
       elif classtype == 'k_classtype_gate':
          node.classtype = 1
-         entdata_length += sizeof( classtype_gate )
+         header.entdata_length += sizeof( classtype_gate )
 
          gate = classtype_gate()
          gate.target = 0
@@ -809,7 +819,7 @@ def write_model(collection_name):
 
       elif classtype == 'k_classtype_block':
          node.classtype = 2
-         entdata_length += sizeof( classtype_block )
+         header.entdata_length += sizeof( classtype_block )
 
          source = obj.data.cv_data
 
@@ -826,7 +836,7 @@ def write_model(collection_name):
       elif classtype == 'k_classtype_achievement_box':
          node.classtype = 13
 
-         entdata_length += sizeof( classtype_achievement_box )
+         header.entdata_length += sizeof( classtype_achievement_box )
          ach = classtype_achievement_box()
          ach.pstr_name = emplace_string( obj.cv_data.strp )
          ach.trigger = 0
@@ -839,7 +849,7 @@ def write_model(collection_name):
       elif classtype == 'k_classtype_audio':
          node.classtype = 14
 
-         entdata_length += sizeof( classtype_audio )
+         header.entdata_length += sizeof( classtype_audio )
          aud = classtype_audio()
          aud.pstr_file = emplace_string( obj.cv_data.strp )
          aud.flags = obj.cv_data.intp
@@ -855,7 +865,7 @@ def write_model(collection_name):
 
       elif classtype == 'k_classtype_car_path':
          node.classtype = 5
-         entdata_length += sizeof( classtype_car_path )
+         header.entdata_length += sizeof( classtype_car_path )
 
          pn = classtype_car_path()
          pn.target = 0
@@ -872,7 +882,7 @@ def write_model(collection_name):
          target = obj.instance_collection
 
          node.classtype = 6
-         entdata_length += sizeof( classtype_instance )
+         header.entdata_length += sizeof( classtype_instance )
 
          inst = classtype_instance()
          inst.pstr_file = emplace_string( F"models/{target.name}.mdl" )
@@ -883,7 +893,7 @@ def write_model(collection_name):
 
       elif classtype == 'k_classtype_route_node':
          node.classtype = 8
-         entdata_length += sizeof( classtype_route_node )
+         header.entdata_length += sizeof( classtype_route_node )
 
          rn = classtype_route_node()
          if obj.cv_data.target != None: 
@@ -895,7 +905,7 @@ def write_model(collection_name):
 
       elif classtype == 'k_classtype_route':
          node.classtype = 9
-         entdata_length += sizeof( classtype_route )
+         header.entdata_length += sizeof( classtype_route )
          r = classtype_route()
          r.colour[0] = obj.cv_data.colour[0]
          r.colour[1] = obj.cv_data.colour[1]
@@ -914,8 +924,7 @@ def write_model(collection_name):
       node_buffer += [node]
 
    # Write data arrays
-   #
-   header.anim_count = len(anim_buffer)
+   # TODO: 8 BYTE ALIGNMENT
 
    print( "Writing data" )
    fpos = sizeof(header)
@@ -932,13 +941,24 @@ def write_model(collection_name):
    header.material_offset = fpos
    fpos += sizeof(mdl_material)*header.material_count
 
-   print( F"Animation count: {header.anim_count}" )
+   print( F"Animation count: {len(anim_buffer)}" )
+   header.anim_count = len(anim_buffer)
    header.anim_offset = fpos
    fpos += sizeof(mdl_animation)*header.anim_count
 
-   print( F"Entdata length: {entdata_length}" )
+   print( F"Entdata length: {header.entdata_length}" )
    header.entdata_offset = fpos
-   fpos += entdata_length
+   fpos += header.entdata_length
+   
+   print( F"Strings length: {len(strings_buffer)}" )
+   header.strings_offset = fpos
+   header.strings_length = len(strings_buffer)
+   fpos += header.strings_length
+   
+   # Optional array things
+   print( F"Keyframe count: {header.keyframe_count}" )
+   header.keyframe_offset = fpos
+   fpos += sizeof(mdl_keyframe)*header.keyframe_count
    
    print( F"Vertex count: {header.vertex_count}" )
    header.vertex_offset = fpos
@@ -948,14 +968,6 @@ def write_model(collection_name):
    header.indice_offset = fpos
    fpos += sizeof(c_uint32)*header.indice_count
 
-   print( F"Keyframe count: {animdata_length}" )
-   header.animdata_offset = fpos
-   fpos += animdata_length
-   
-   print( F"Strings length: {len(strings_buffer)}" )
-   header.strings_offset = fpos
-   fpos += len(strings_buffer)
-
    header.file_length = fpos
 
    path = F"/home/harry/Documents/carve/models_src/{collection_name}.mdl"
@@ -973,14 +985,17 @@ def write_model(collection_name):
       fp.write( bytearray(a) )
    for ed in entdata_buffer:
       fp.write( bytearray(ed) )
+
+   fp.write( strings_buffer )
+
+   for kf in animdata_buffer:
+      fp.write( bytearray(kf) )
+
    for v in vertex_buffer:
       fp.write( bytearray(v) )
    for i in indice_buffer:
       fp.write( bytearray(i) )
-   for kf in animdata_buffer:
-      fp.write( bytearray(kf) )
 
-   fp.write( strings_buffer )
    fp.close()
 
    print( F"Completed {collection_name}.mdl" )
index 89208061a7ca6fed988a564a5eca8969bb3892bb..fad620190cce6a31a17c14c4b1dc5b418e1efe7f 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -23,7 +23,7 @@ _windows_asan=""
 _windows_linksteam="vg/dep/steam/steam_api.dll"
 _windows_folder="bin/win32"
 
-_options_debugmode="-O0 -ggdb3 -fno-omit-frame-pointer"
+_options_debugmode="-O0 -ggdb3 -fno-omit-frame-pointer -rdynamic"
 _options_release="-O3 -DVG_RELEASE"
 
 # Compiler lines
@@ -228,6 +228,11 @@ vg_command(){
       test)
          run_game
       ;;
+      gdb)
+         cd $_linux_folder
+         gdb -tui ./skaterift
+         cd ./../
+      ;;
       testserver)
          run_server
       ;;
diff --git a/bvh.h b/bvh.h
index c18bb3052d9ffa532231ae9bcfcba797dbad4814..9fdbe985040f51e0cadfd0a183b921240c82a036 100644 (file)
--- a/bvh.h
+++ b/bvh.h
  *   system: the system we created above which will deal with the data
  *
  * call bh_create( bh_tree *bh, u32 item_count )
- * static int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit )
- * static int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
+ * VG_STATIC int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit )
+ * VG_STATIC int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
  */
 
 typedef struct bh_node bh_node;
 typedef struct bh_tree bh_tree;
 typedef struct bh_system bh_system;
 
-struct bh_node
-{
-   boxf bbx;
-
-   /* if il is 0, this is a leaf */
-   u32 il, count;
-   union{ u32 ir, start; };
-};
-
 struct bh_tree
 {
-   bh_node *nodes;
    u32 node_count;
 
    bh_system *system;
    void *user;
+
+   struct bh_node
+   {
+      boxf bbx;
+
+      /* if il is 0, this is a leaf */
+      u32 il, count;
+      union{ u32 ir, start; };
+   } 
+   nodes[];
 };
 
 struct bh_system
@@ -61,7 +61,7 @@ struct bh_system
    int   (*cast_ray)( void *user, u32 index, v3f co, v3f dir, ray_hit *hit );
 };
 
-static void bh_update_bounds( bh_tree *bh, u32 inode )
+VG_STATIC void bh_update_bounds( bh_tree *bh, u32 inode )
 {
    bh_node *node = &bh->nodes[ inode ];
 
@@ -73,7 +73,7 @@ static void bh_update_bounds( bh_tree *bh, u32 inode )
    }
 }
 
-static void bh_subdivide( bh_tree *bh, u32 inode )
+VG_STATIC void bh_subdivide( bh_tree *bh, u32 inode )
 {
    bh_node *node = &bh->nodes[ inode ];
 
@@ -128,18 +128,19 @@ static void bh_subdivide( bh_tree *bh, u32 inode )
    node->ir = ir;
    node->count = 0;
 
-   /* TODO: Implement max depth, or stack */
    bh_update_bounds( bh, il );
    bh_update_bounds( bh, ir );
    bh_subdivide( bh, il );
    bh_subdivide( bh, ir );
 }
 
-static void bh_create( bh_tree *bh, bh_system *sys, void *user, u32 item_count )
+VG_STATIC bh_tree *bh_create( void *lin_alloc, bh_system *system, 
+                              void *user, u32 item_count )
 {
-   bh->system = sys;
+   u32 totsize = sizeof(bh_tree) + sizeof(bh_node)*(item_count*2-1);
+   bh_tree *bh = vg_linear_alloc( lin_alloc, totsize );
+   bh->system = system;
    bh->user = user;
-   bh->nodes = vg_alloc( sizeof(bh_node) * (item_count*2-1) );
 
    bh_node *root = &bh->nodes[0];
    bh->node_count = 1;
@@ -152,20 +153,14 @@ static void bh_create( bh_tree *bh, bh_system *sys, void *user, u32 item_count )
    bh_update_bounds( bh, 0 );
    bh_subdivide( bh, 0 );
 
-   bh->nodes = vg_realloc( bh->nodes, sizeof(bh_node) * bh->node_count );
-   vg_success( "BVH done, size: %u/%u\n", bh->node_count, (item_count*2-1) );
-
-#if 0
-   vg_fatal_exit_loop( "Test crash from loader" );
-#endif
-}
+   totsize = sizeof(bh_tree) + sizeof(bh_node) * bh->node_count;
+   bh = vg_linear_resize( lin_alloc, bh, totsize );
 
-static void bh_free( bh_tree *bh )
-{
-   vg_free( bh->nodes );
+   vg_success( "BVH done, size: %u/%u\n", bh->node_count, (item_count*2-1) );
+   return bh;
 }
 
-static void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour )
+VG_STATIC void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour )
 {
    bh_node *node = &bh->nodes[ inode ];
 
@@ -195,7 +190,7 @@ static void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour )
    }
 }
 
-static int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit )
+VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit )
 {
    int count = 0;
    u32 stack[100];
@@ -246,7 +241,7 @@ static int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit )
    return count;
 }
 
-static int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
+VG_STATIC int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
 {
    int count = 0;
    u32 stack[100];
index 07205de223417ce84a392b4a8406043f0a260248..1c265a7515dd3bdf3209c9b9e5f1e9f791940e3f 100644 (file)
--- a/camera.h
+++ b/camera.h
@@ -3,13 +3,13 @@
 
 #include "common.h"
 
-static v2f camera_angles;
-static v3f camera_pos;
+VG_STATIC v2f camera_angles;
+VG_STATIC v3f camera_pos;
 
-static m4x3f camera_mtx,
-             camera_mtx_inverse;
+VG_STATIC m4x3f camera_mtx,
+                camera_mtx_inverse;
 
-static void camera_update(void)
+VG_STATIC void camera_update(void)
 {
    /* Update camera matrices */
    v4f qyaw, qpitch, qcam;
index 0890ac4ef005d6ec3ccf6236fb0f117a80fc864f..fa6df751c03eea9c5cdec0cdb9d0943dffd6d83b 100644 (file)
--- a/common.h
+++ b/common.h
@@ -21,9 +21,9 @@ struct ray_hit
    v3f pos, normal;
 };
 
-static int network_scores_updated = 0;
+VG_STATIC int network_scores_updated = 0;
 
-static u32 utf8_byte0_byte_count( u8 char0 )
+VG_STATIC u32 utf8_byte0_byte_count( u8 char0 )
 {
    for( u32 k=2; k<4; k++ )
    {
@@ -34,7 +34,7 @@ static u32 utf8_byte0_byte_count( u8 char0 )
    return 0;
 }
 
-static void str_utf8_collapse( const char *str, char *buf, u32 length )
+VG_STATIC void str_utf8_collapse( const char *str, char *buf, u32 length )
 {
    u8 *ustr = (u8 *)str;
    u32 utf32_code = 0x00000000;
index f19f93a2fd2494ef4b6635a7d0a512d712e76365..f2c5eabc855b0654a1d3c3d5b6eca3dcdedf8b56 100644 (file)
@@ -80,7 +80,7 @@ struct highscore_database
 
 #pragma pack(pop)
 
-static struct highscore_system
+VG_STATIC struct highscore_system
 {
    highscore_database dbheader;
    aatree aainfo,
@@ -91,19 +91,20 @@ static struct highscore_system
           aainfo_playerinfo_playerid,
           aainfo_playerinfo;
 
-   void *data, *playerinfo_data;
+   void *data, 
+        *playerinfo_data;
 
    u32 pool_size, playerinfo_pool_size;
 }
 highscore_system;
 
-static int highscore_cmp_points( void *a, void *b )
+VG_STATIC int highscore_cmp_points( void *a, void *b )
 {
    highscore_record *pa = a, *pb = b;
    return (int)pa->points - (int)pb->points;
 }
 
-static int highscore_cmp_datetime( void *a, void *b )
+VG_STATIC int highscore_cmp_datetime( void *a, void *b )
 {
    highscore_record *pa = a, *pb = b;
    
@@ -111,52 +112,27 @@ static int highscore_cmp_datetime( void *a, void *b )
    return pa->datetime < pb->datetime? 1: -1;
 }
 
-static int highscore_cmp_time( void *a, void *b )
+VG_STATIC int highscore_cmp_time( void *a, void *b )
 {
    highscore_record *pa = a, *pb = b;
    return (int)pb->time - (int)pa->time;
 }
 
-static int highscore_cmp_playerid( void *a, void *b )
+VG_STATIC int highscore_cmp_playerid( void *a, void *b )
 {
    highscore_record *pa = a, *pb = b;
    if( pa->playerid == pb->playerid ) return 0;
    return pa->playerid < pb->playerid? -1: 1;
 }
 
-static int highscore_cmp_playerinfo_playerid( void *a, void *b )
+VG_STATIC int highscore_cmp_playerinfo_playerid( void *a, void *b )
 {
    highscore_playerinfo *pa = a, *pb = b;
    if( pa->playerid == pb->playerid ) return 0;
    return pa->playerid < pb->playerid? -1: 1;
 }
 
-static void *highscore_malloc( u32 count, u32 size )
-{
-   size_t requested_mem = size * count;
-   void *data = vg_alloc( requested_mem );
-
-   requested_mem /= 1024;
-   requested_mem /= 1024;
-
-   if( !data )
-   {
-      vg_error( "Could not allocated %dmb of memory\n", requested_mem );
-      return NULL;
-   }
-   else
-      vg_success( "Allocated %dmb for %u records\n", requested_mem, count );
-
-   return data;
-}
-
-static void highscores_free(void)
-{
-   vg_free( highscore_system.data );
-   vg_free( highscore_system.playerinfo_data );
-}
-
-static void highscores_create_db(void)
+VG_STATIC void highscores_create_db(void)
 {
    struct highscore_system *sys = &highscore_system;
 
@@ -183,7 +159,7 @@ static void highscores_create_db(void)
    sys->dbheader.playerinfo_root = AATREE_PTR_NIL;
 }
 
-static int highscores_read(void)
+VG_STATIC int highscores_read(void)
 {
    struct highscore_system *sys = &highscore_system;
 
@@ -200,7 +176,9 @@ static int highscores_read(void)
          return 0;
       }
 
-      count = fread( sys->data, sizeof(highscore_record), sys->pool_size, fp );
+      count = fread( sys->data, sizeof(highscore_record), 
+                     sys->pool_size, fp );
+
       if( count != sys->pool_size )
       {
          vg_error( "Unexpected EOF reading database contents;"
@@ -229,13 +207,17 @@ static int highscores_read(void)
    }
 }
 
-static void highscores_init( u32 pool_size, u32 playerinfo_pool_size )
+VG_STATIC void highscores_init( u32 pool_size, u32 playerinfo_pool_size )
 {
    struct highscore_system *sys = &highscore_system;
 
-   sys->data = highscore_malloc( pool_size, sizeof(highscore_record) );
-   sys->playerinfo_data = highscore_malloc( playerinfo_pool_size, 
-                                            sizeof(highscore_playerinfo));
+   sys->data = vg_linear_alloc( vg_mem.rtmemory, 
+                                pool_size*sizeof(highscore_record) );
+
+   sys->playerinfo_data = 
+      vg_linear_alloc( vg_mem.rtmemory,
+                       playerinfo_pool_size * sizeof(highscore_playerinfo) );
+
 
    /* This is ugly.. too bad! */
    sys->aainfo.base = highscore_system.data;
@@ -278,7 +260,7 @@ static void highscores_init( u32 pool_size, u32 playerinfo_pool_size )
    sys->pool_size = pool_size;
 }
 
-static int highscores_serialize_all(void)
+VG_STATIC int highscores_serialize_all(void)
 {
    struct highscore_system *sys = &highscore_system;
    vg_info( "Serializing database\n" );
@@ -301,7 +283,7 @@ static int highscores_serialize_all(void)
    return 1;
 }
 
-static highscore_record *highscore_find_user_record( u64 playerid, u32 trackid )
+VG_STATIC highscore_record *highscore_find_user_record( u64 playerid, u32 trackid )
 {
    struct highscore_system *sys = &highscore_system;
 
@@ -318,7 +300,7 @@ static highscore_record *highscore_find_user_record( u64 playerid, u32 trackid )
    return aatree_get_data( &sys->aainfo_playerid, find );
 }
 
-static aatree_ptr highscores_push_record( highscore_record *record )
+VG_STATIC aatree_ptr highscores_push_record( highscore_record *record )
 {
    struct highscore_system *sys = &highscore_system;
 
@@ -389,7 +371,7 @@ static aatree_ptr highscores_push_record( highscore_record *record )
    return index;
 }
 
-static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] )
+VG_STATIC aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] )
 {
    char name[17];
    for( int i=0; i<16; i++ )
@@ -429,8 +411,7 @@ static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] )
       info->playerid = steamid;
       sys->dbheader.playerinfo_root = aatree_insert( 
             &sys->aainfo_playerinfo_playerid,
-            sys->dbheader.playerinfo_root,
-            record );
+            sys->dbheader.playerinfo_root, record );
    }
 
    for( int i=0; i<16; i++ )
@@ -440,7 +421,7 @@ static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[16] )
 }
 
 /* Get the length of a string, bounded by '\0' or len, whichever is first */
-static int highscore_strlen( const char *str, int len )
+VG_STATIC int highscore_strlen( const char *str, int len )
 {
    int str_length;
    for( str_length=0; str_length<len; str_length++ )
@@ -451,7 +432,7 @@ static int highscore_strlen( const char *str, int len )
 }
 
 /* Print the string(max length:len) centered into buf (has width:width) */
-static void highscore_strc( char *buf, const char *str, int len, int width )
+VG_STATIC void highscore_strc( char *buf, const char *str, int len, int width )
 {
    int str_length = highscore_strlen( str, len ),
        offs = (width-str_length)/2;
@@ -468,7 +449,7 @@ static void highscore_strc( char *buf, const char *str, int len, int width )
 }
 
 /* Print the string(max length:len) left aligned into buf */
-static void highscore_strl( char *buf, const char *str, int len )
+VG_STATIC void highscore_strl( char *buf, const char *str, int len )
 {
    for( int i=0; i<len; i++ )
    {
@@ -480,7 +461,7 @@ static void highscore_strl( char *buf, const char *str, int len )
 }
 
 /* Print the string (max length:len) right aligned into buf (has width:width) */
-static void highscore_strr( char *buf, const char *str, int len, int width )
+VG_STATIC void highscore_strr( char *buf, const char *str, int len, int width )
 {
    int str_length = highscore_strlen( str, len );
    
@@ -494,7 +475,7 @@ static void highscore_strr( char *buf, const char *str, int len, int width )
 }
 
 /* Print integer (padded with: alt), right aligned into buf(width: len) */
-static void highscore_intr( char *buf, int value, int len, char alt )
+VG_STATIC void highscore_intr( char *buf, int value, int len, char alt )
 {
    int i=0;
    while(value)
@@ -511,7 +492,7 @@ static void highscore_intr( char *buf, int value, int len, char alt )
 }
 
 /* Print integer into buffer with max length len */
-static void highscore_intl( char *buf, int value, int len )
+VG_STATIC void highscore_intl( char *buf, int value, int len )
 {
    char temp[32];
 
@@ -535,7 +516,7 @@ static void highscore_intl( char *buf, int value, int len )
 }
 
 /* Clear buffer with length using clr character */
-static void highscore_clear( char *buf, char clr, int length )
+VG_STATIC void highscore_clear( char *buf, char clr, int length )
 {
    for( int i=0; i<length; i++ )
       buf[i] = clr;
@@ -559,7 +540,7 @@ static void highscore_clear( char *buf, char clr, int length )
 
 /* Generate a highscores board in text form, the width is always 27. Buffer 
  * must be (count+3)*27 in size. */
-static void highscores_board_generate( char *buf, u32 id, u32 count )
+VG_STATIC void highscores_board_generate( char *buf, u32 id, u32 count )
 {
    int w=27;
    highscore_clear( buf, ' ', (count+3)*w );
@@ -629,7 +610,7 @@ static void highscores_board_generate( char *buf, u32 id, u32 count )
 
 /* Print string out to file using newlines. Count is number of records 
  * ( this requires a buffer of (count+3)*27 size */
-static void highscores_board_printf( FILE *fp, const char *buf, u32 count )
+VG_STATIC void highscores_board_printf( FILE *fp, const char *buf, u32 count )
 {
    int w=27;
 
diff --git a/main.c b/main.c
index 61bd6dfcd15f94ad2dfbb8d6b672b11baa798eb0..9bfa794c51a1e0b1ad55668aa8ca29b1877fc366 100644 (file)
--- a/main.c
+++ b/main.c
  * 
  */
 
-#define SR_NETWORKED
 #define VG_3D
+#define VG_STATIC static
+
+//#define VG_MINIMAL_TEST
+#ifndef VG_MINIMAL_TEST
+
+#define SR_NETWORKED
+
 #include "common.h"
 #include "steam.h"
 #include "render.h"
@@ -33,16 +39,16 @@ static int cl_ui     = 1;
 
 int main( int argc, char *argv[] )
 {
+   vg_prealloc_quota( 128*1024*1024 );
    vg_enter( argc, argv, "Voyager Game Engine" ); 
 }
 
-static void highscores_save_at_exit(void*_)
+VG_STATIC void highscores_save_at_exit(void*_)
 {
    highscores_serialize_all();
-   highscores_free();
 }
 
-void vg_preload(void)
+VG_STATIC void vg_preload(void)
 {
    vg_convar_push( (struct vg_convar){
       .name = "cl_ui",
@@ -73,37 +79,34 @@ vg_info("            '        ' '--' [] '----- '----- '     ' '---'  "
    vg_loader_highwater( network_init, network_end, NULL );
 }
 
-void vg_load(void)
+VG_STATIC void vg_load(void)
 {
-   vg_loader_highwater( render_init, render_free, NULL );
-   vg_loader_highwater( menu_init, menu_free, NULL );
-   vg_loader_highwater( world_init, world_free, NULL );
+   vg_loader_highwater( render_init, NULL, NULL );
+   vg_loader_highwater( menu_init, NULL, NULL );
+   vg_loader_highwater( world_init, NULL, NULL );
    vg_loader_highwater( player_init, NULL, NULL );
 
-   if( !vg_bake_shaders() )
-      vg_fatal_exit_loop( "Did not load all shaders" );
-
+   vg_bake_shaders();
    vg_loader_highwater( audio_init, audio_free, NULL );
 
-   /* FInal step */
-   world_load();
+   /* 'systems' are completely loaded now */
+   world_load( "models/mp_dev.mdl" );
    vg_console_load_autos();
 }
 
-static void vg_start(void)
+VG_STATIC void vg_start(void)
 {
-   player_load_model( "ch_jordan", 0 );
    reset_player( 1, (const char *[]){ "start" } );
 }
 
-static void draw_origin_axis(void)
+VG_STATIC void draw_origin_axis(void)
 {
    vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
    vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
    vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
 }
 
-void vg_update( int loaded )
+VG_STATIC void vg_update( int loaded )
 {
    steam_update();
 
@@ -117,7 +120,7 @@ void vg_update( int loaded )
    }
 }
 
-static void vg_update_fixed( int loaded )
+VG_STATIC void vg_update_fixed( int loaded )
 {
    if( loaded )
    {
@@ -125,7 +128,7 @@ static void vg_update_fixed( int loaded )
    }
 }
 
-static void vg_update_post( int loaded )
+VG_STATIC void vg_update_post( int loaded )
 {
    if( loaded )
    {
@@ -134,14 +137,13 @@ static void vg_update_post( int loaded )
    }
 }
 
-static void vg_framebuffer_resize( int w, int h )
+VG_STATIC void vg_framebuffer_resize( int w, int h )
 {
    render_fb_resize();
-   gate_fb_resize();
    water_fb_resize();
 }
 
-static void render_main_game(void)
+VG_STATIC void render_main_game(void)
 {
    m4x4f world_4x4;
    m4x3_expand( camera_mtx_inverse, world_4x4 );
@@ -231,7 +233,7 @@ static void render_main_game(void)
    render_fsquad();
 }
 
-void vg_render(void)
+VG_STATIC void vg_render(void)
 {
    glBindFramebuffer( GL_FRAMEBUFFER, 0 );
    glViewport( 0,0, vg.window_x, vg.window_y );
@@ -250,7 +252,7 @@ void vg_render(void)
    glViewport( 0,0, vg.window_x, vg.window_y );
 }
 
-void vg_ui(void)
+VG_STATIC void vg_ui(void)
 {
 #if 0
    if( cl_menu )
@@ -333,7 +335,7 @@ void vg_ui(void)
 }
 
 #if 0
-static void run_light_widget( struct light_widget *lw )
+VG_STATIC void run_light_widget( struct light_widget *lw )
 {
    struct ui_checkbox c1 = { .data=&lw->enabled };
 
@@ -352,32 +354,104 @@ static void run_light_widget( struct light_widget *lw )
 }
 #endif
 
-static void run_debug_info(void)
+VG_STATIC void run_debug_info(void)
 {
    char buf[40];
    
    snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) );
-   gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
+   ui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
    
    snprintf( buf, 40, "%.2f %.2f %.2f m/s", 
          player.phys.a[0], player.phys.a[1], player.phys.a[2] );
-   gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
+   ui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
 
    snprintf( buf, 40, "pos %.2f %.2f %.2f", 
          player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] );
-   gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
+   ui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
 
    if( vg.gamepad_ready )
    {
       for( int i=0; i<6; i++ )
       {
          snprintf( buf, 40, "%.2f", vg.gamepad.axes[i] );
-         gui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
+         ui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
       }
    }
    else
    {
-      gui_text( (ui_px [2]){ 0, 60 }, 
+      ui_text( (ui_px [2]){ 0, 60 }, 
             "Gamepad not ready", 1, k_text_align_left );
    }
 }
+
+#else
+
+#define VG_TIMESTEP_FIXED (1.0/60.0)
+#define VG_3D
+#define VG_FRAMEBUFFER_RESIZE 1
+#include "vg/vg.h"
+
+int main( int argc, char *argv[] )
+{
+   vg_prealloc_quota( 512*1024*1024 );
+   vg_enter( argc, argv, "Voyager Game Engine" ); 
+}
+
+VG_STATIC void vg_preload(void)
+{
+vg_info(" Copyright  .        . .       -----, ,----- ,---.   .---.  \n" );
+vg_info(" 2021-2022  |\\      /| |           /  |      |    | |    /| \n" );
+vg_info("            | \\    / | +--        /   +----- +---'  |   / | \n" );
+vg_info("            |  \\  /  | |         /    |      |   \\  |  /  | \n" );
+vg_info("            |   \\/   | |        /     |      |    \\ | /   | \n" );
+vg_info("            '        ' '--' [] '----- '----- '     ' '---'  " 
+        "SOFTWARE\n" );
+}
+
+VG_STATIC void vg_load(void)
+{
+   vg_bake_shaders();
+   vg_console_load_autos();
+}
+
+VG_STATIC void vg_start(void)
+{
+}
+
+VG_STATIC void vg_update( int loaded )
+{
+}
+
+VG_STATIC void vg_update_fixed( int loaded )
+{
+}
+
+VG_STATIC void vg_update_post( int loaded )
+{
+}
+
+VG_STATIC void vg_framebuffer_resize( int w, int h )
+{
+}
+
+VG_STATIC void vg_render(void)
+{
+   glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+   glViewport( 0,0, vg.window_x, vg.window_y );
+   glDisable( GL_DEPTH_TEST );
+
+   glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
+   
+   /* Other shite */
+   glDisable(GL_BLEND);
+   glDisable( GL_DEPTH_TEST );
+   vg_lines_drawall( (float *)vg.pv );
+   glViewport( 0,0, vg.window_x, vg.window_y );
+}
+
+VG_STATIC void vg_ui(void)
+{
+}
+
+#endif
diff --git a/menu.h b/menu.h
index 7d8bf764441bb5fcfb01363c697759759c82171c..02ab25242a74c75837f862f20eb51fb6a230bf7b 100644 (file)
--- a/menu.h
+++ b/menu.h
@@ -8,32 +8,31 @@
 
 #include "shaders/menu.h"
 
-static mdl_header *menu_model;
-static glmesh      menu_glmesh;
-static m4x3f       menu_mdl_mtx;
-static float       menu_opacity = 0.0f;
-static float       menu_input_cooldown = 0.0f;
-static float       menu_fov_target = 97.0f;
-static v2f         menu_extra_angles;
-
-static int         menu_loc = 1,
+VG_STATIC mdl_context menu_model;
+VG_STATIC glmesh      menu_glmesh;
+VG_STATIC m4x3f       menu_mdl_mtx;
+VG_STATIC float       menu_opacity = 0.0f;
+VG_STATIC float       menu_input_cooldown = 0.0f;
+VG_STATIC float       menu_fov_target = 97.0f;
+VG_STATIC v2f         menu_extra_angles;
+
+VG_STATIC int         menu_loc = 1,
                    menu_loc_last = 1;
-static u32         menu_page     = 0;
+VG_STATIC u32         menu_page     = 0;
 
-static int         cl_menu         = 0,
+VG_STATIC int         cl_menu         = 0,
                    cl_menu_go_away = 0;
-static int         cl_playermdl_id = 0;
 
-static const char *playermodels[] = { "ch_new", "ch_jordan", "ch_outlaw" };
+VG_STATIC const char *playermodels[] = { "ch_new", "ch_jordan", "ch_outlaw" };
 
-static void menu_btn_paused( int event );
-static void menu_btn_quit( int event );
-static void menu_btn_skater( int event );
-static void menu_btn_map( int event );
-static void menu_btn_map_a( int event );
-static void menu_btn_map_b( int event );
-static void menu_btn_map_c( int event );
-static void menu_btn_fuckoff( int event );
+VG_STATIC void menu_btn_paused( int event );
+VG_STATIC void menu_btn_quit( int event );
+VG_STATIC void menu_btn_skater( int event );
+VG_STATIC void menu_btn_map( int event );
+VG_STATIC void menu_btn_map_a( int event );
+VG_STATIC void menu_btn_map_b( int event );
+VG_STATIC void menu_btn_map_c( int event );
+VG_STATIC void menu_btn_fuckoff( int event );
 
 struct menu_button
 {
@@ -46,7 +45,7 @@ struct menu_button
 
    float falpha, fsize;
 }
-static menu_buttons[] = 
+VG_STATIC menu_buttons[] = 
 {
 /*0*/{"text_paused",     1, menu_btn_paused },
 /*1*/{"text_quit",       9, menu_btn_quit,    {3,-1,4,2}},
@@ -64,69 +63,63 @@ static menu_buttons[] =
 /*d*/{"text_yes",        8, menu_btn_fuckoff,{-1,-1,-1,-1} },
 };
 
-static void menu_btn_map_a( int event ){}
-static void menu_btn_map_b( int event ){}
-static void menu_btn_map_c( int event ){}
+VG_STATIC void menu_btn_map_a( int event ){}
+VG_STATIC void menu_btn_map_b( int event ){}
+VG_STATIC void menu_btn_map_c( int event ){}
 
-static void menu_btn_paused( int event )
+VG_STATIC void menu_btn_paused( int event )
 {
 
 }
 
-static void menu_btn_fuckoff( int event )
+VG_STATIC void menu_btn_fuckoff( int event )
 {
    glfwSetWindowShouldClose( vg.window, 1 );
 }
 
-static void menu_btn_quit( int event )
+VG_STATIC void menu_btn_quit( int event )
 {
    menu_page = 0x8;
    menu_loc = 0xd;
 }
 
-static void menu_btn_map( int event )
+VG_STATIC void menu_btn_map( int event )
 {
    menu_page = 0x4;
    menu_loc = 7;
 }
 
-static void menu_btn_skater( int event )
+VG_STATIC void menu_btn_skater( int event )
 {
    menu_page = 0x2;
 }
 
-static void menu_init(void)
+VG_STATIC void menu_init(void)
 {
-   menu_model = mdl_load( "models/rs_menu.mdl" );
+   vg_linear_clear( vg_mem.scratch );
 
-   if( !menu_model )
-      vg_fatal_exit_loop( "No menu model" );
+   mdl_open( &menu_model, "models/rs_menu.mdl" );
+   mdl_load_metadata( &menu_model, vg_mem.rtmemory );
+   mdl_load_mesh_data( &menu_model, vg_mem.scratch );
+   mdl_close( &menu_model );
+
+   vg_acquire_thread_sync();
+   mdl_unpack_glmesh( &menu_model, &menu_glmesh );
+   vg_release_thread_sync();
 
    for( int i=0; i<vg_list_size(menu_buttons); i++ )
    {
       struct menu_button *btn = &menu_buttons[i];
-      btn->pnode = mdl_node_from_name( menu_model, btn->name );
+      btn->pnode = mdl_node_from_name( &menu_model, btn->name );
 
       if( !btn->pnode )
          vg_fatal_exit_loop( "Menu programming error" );
    }
 
-   vg_convar_push( (struct vg_convar){
-      .name = "cl_playermdl_id",
-      .data = &cl_playermdl_id,
-      .data_type = k_convar_dtype_i32,
-      .opt_i32 = { .min=0, .max=2, .clamp=1 },
-      .persistent = 1
-   });
-
-   vg_acquire_thread_sync();
-   mdl_unpack_glmesh( menu_model, &menu_glmesh );
-   vg_release_thread_sync();
-
    shader_menu_register();
 }
 
-static void menu_run_directional(void)
+VG_STATIC void menu_run_directional(void)
 {
    struct menu_button *btn = &menu_buttons[ menu_loc ];
 
@@ -174,18 +167,18 @@ static void menu_run_directional(void)
    }
 }
 
-static int menu_page_should_backout(void)
+VG_STATIC int menu_page_should_backout(void)
 {
    return vg_get_button_down( "break" );
 }
 
-static void menu_close(void)
+VG_STATIC void menu_close(void)
 {
    cl_menu_go_away = 1;
    menu_page = 0;
 }
 
-static void menu_page_main(void)
+VG_STATIC void menu_page_main(void)
 {
    if( menu_page_should_backout() )
    {
@@ -197,7 +190,7 @@ static void menu_page_main(void)
    menu_run_directional();
 }
 
-static void menu_page_map(void)
+VG_STATIC void menu_page_map(void)
 {
    if( menu_page_should_backout() )
    {
@@ -209,7 +202,7 @@ static void menu_page_map(void)
    menu_run_directional();
 }
 
-static void menu_page_quit(void)
+VG_STATIC void menu_page_quit(void)
 {
    if( menu_page_should_backout() )
    {
@@ -221,7 +214,7 @@ static void menu_page_quit(void)
    menu_run_directional();
 }
 
-static void menu_page_skater(void)
+VG_STATIC void menu_page_skater(void)
 {
    float h = vg_get_axis( "lookh" );
    menu_fov_target = 97.0f;
@@ -245,7 +238,6 @@ static void menu_page_skater(void)
          menu_buttons[5].falpha = 1.0f;
 
          menu_input_cooldown = 0.25f;
-         player_load_model( playermodels[ cl_playermdl_id ], 1 );
       }
       else
       {
@@ -257,12 +249,11 @@ static void menu_page_skater(void)
          menu_buttons[6].falpha = 1.0f;
 
          menu_input_cooldown = 0.25f;
-         player_load_model( playermodels[ cl_playermdl_id ], 1 );
       }
    }
 }
 
-static void menu_update(void)
+VG_STATIC void menu_update(void)
 {
    if( vg_get_button_down( "menu" ) )
    {
@@ -376,7 +367,7 @@ float expSustainedImpulse( float x, float f, float k )
     return fminf( x*x/(f*f), 1.0f+(2.0f/f)*s*expf(-k*s));
 }
 
-static void menu_render( m4x4f projection )
+VG_STATIC void menu_render( m4x4f projection )
 {
    glEnable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
@@ -431,7 +422,7 @@ static void menu_render( m4x4f projection )
       for( int j=0; j<btn->pnode->submesh_count; j++ )
       {
          mdl_submesh *sm = 
-            mdl_submesh_from_id( menu_model, btn->pnode->submesh_start+j );
+            &menu_model.submesh_buffer[ btn->pnode->submesh_start+j ];
          mdl_draw_submesh( sm );
       }
    }
@@ -456,9 +447,4 @@ static void menu_render( m4x4f projection )
    */
 }
 
-static void menu_free(void *_)
-{
-   mesh_free( &menu_glmesh );
-}
-
 #endif /* MENU_H */
diff --git a/model.h b/model.h
index faa9f5fd8988483bcc774ba4d70667b1a53d4f2e..b3650f8009c4a854dc383642c0391fea00fec311 100644 (file)
--- a/model.h
+++ b/model.h
@@ -13,9 +13,10 @@ typedef struct mdl_vert mdl_vert;
 typedef struct mdl_submesh mdl_submesh;
 typedef struct mdl_material mdl_material;
 typedef struct mdl_node mdl_node;
-typedef struct mdl_header mdl_header;
+typedef struct mdl_file_header mdl_file_header;
 typedef struct mdl_animation mdl_animation;
 typedef struct mdl_keyframe mdl_keyframe;
+typedef struct mdl_context mdl_context;
 
 #define MDL_SIZE_MAX          0x1000000
 #define MDL_VERT_MAX          1000000
@@ -41,7 +42,8 @@ enum classtype
    k_classtype_skeleton = 11,
    k_classtype_skin = 12,
    k_classtype_achievement_box = 13,
-   k_classtype_audio = 14
+   k_classtype_audio = 14,
+   k_classtype_trigger = 15
 };
 
 
@@ -79,9 +81,8 @@ struct mdl_node
    v4f q;
    v3f s;
    
-   union{ u32 submesh_start, sub_uid; };
-
-   u32 
+   u32 sub_uid,         /* allocated in-file... too bad. */
+       submesh_start,
        submesh_count,
        classtype,
        offset,
@@ -106,9 +107,9 @@ struct mdl_animation
    u32 offset;
 };
 
-struct mdl_header
+struct mdl_file_header
 {
-   u32 identifier, version, file_length;
+   u32 identifier, version, file_length, pad0;
 
    u32 vertex_count, vertex_offset,
        indice_count, indice_offset,
@@ -116,7 +117,9 @@ struct mdl_header
        material_count, material_offset,
        node_count, node_offset,
        anim_count, anim_offset,
-       strings_offset, entdata_offset, animdata_offset;
+       strings_length, strings_offset, 
+       entdata_length, entdata_offset, 
+       keyframe_count, keyframe_offset;
 };
 
 /* 
@@ -212,6 +215,26 @@ struct classtype_audio
 
 #pragma pack(pop)
 
+
+struct mdl_context
+{
+   FILE *file;
+   mdl_file_header info;
+
+   /* each buffer becomes availible after each _load function is called */
+   mdl_node       *node_buffer;     /* mdl_load_metadata() */
+   mdl_submesh    *submesh_buffer;
+   mdl_material   *material_buffer;
+   mdl_animation  *anim_buffer;
+   void           *entdata_buffer;
+   const char     *string_buffer;
+
+   mdl_keyframe   *keyframe_buffer; /* mdl_load_anim_data() */
+
+   mdl_vert       *vertex_buffer;   /* mdl_load_mesh_data() */
+   u32            *index_buffer;
+};
+
 /*
  * Simple mesh interface for OpenGL
  */
@@ -223,7 +246,7 @@ struct glmesh
    u32 loaded;
 };
 
-static void mesh_upload( glmesh *mesh,
+VG_STATIC void mesh_upload( glmesh *mesh,
                          mdl_vert *verts, u32 vert_count,
                          u32 *indices, u32 indice_count )
 {
@@ -279,23 +302,23 @@ static void mesh_upload( glmesh *mesh,
    mesh->loaded = 1;
 }
 
-static void mesh_bind( glmesh *mesh )
+VG_STATIC void mesh_bind( glmesh *mesh )
 {
    glBindVertexArray( mesh->vao );
 }
 
-static void mesh_drawn( u32 start, u32 count )
+VG_STATIC void mesh_drawn( u32 start, u32 count )
 {
    glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_INT, 
          (void *)(start*sizeof(u32)) );
 }
 
-static void mesh_draw( glmesh *mesh )
+VG_STATIC void mesh_draw( glmesh *mesh )
 {
    mesh_drawn( 0, mesh->indice_count );
 }
 
-static void mesh_free( glmesh *mesh )
+VG_STATIC void mesh_free( glmesh *mesh )
 {
    if( mesh->loaded )
    {
@@ -305,156 +328,177 @@ static void mesh_free( glmesh *mesh )
    }
 }
 
+VG_STATIC void mdl_load_fatal_corrupt( mdl_context *mdl )
+{
+   fclose( mdl->file );
+   vg_file_print_invalid( mdl->file );
+   vg_fatal_exit_loop( "Corrupt model" );
+}
 
 /*
  * Model implementation
+ *
+ * TODO.
+ *
+ * you have two api options for loading a model, first, the easy way:
+ *       mdl_load ...
+ *    will put the entire model straight into the linear_alloc
+ *
+ * or, to target different allocators:
+ *
+ *       mdl_open
+ *       mdl_load_metadata
+ *       mdl_load_vertex_data
+ *       mdl_load_indice_data
+ *       mdl_close
+ *
+ * these should ideally be called in quick succession to limit stalls.
  */
 
-static mdl_header *mdl_load( const char *path )
+/*
+ * if calling mdl_open, and the file does not exist, the game will fatal quit
+ */
+VG_STATIC void mdl_open( mdl_context *mdl, const char *path )
 {
-   i64 size;
-   mdl_header *header = vg_asset_read_s( path, &size );
+   memset( mdl, 0, sizeof( mdl_context ) );
+   mdl->file = fopen( path, "rb" );
 
-   /* 
-    * Check file is valid
-    */
-   if( !header )
+   if( !mdl->file )
    {
-      vg_error( "Could not open '%s'\n", path );
-      return NULL;
+      vg_error( "mdl_open('%s'): %s\n", path, strerror(errno) );
+      vg_fatal_exit_loop( "see above for details" );
    }
 
-   if( size < sizeof(mdl_header) )
-   {
-      vg_free( header );
-      vg_error( "Invalid file '%s' (too small for header)\n", path );
-      return NULL;
-   }
+   u64 l = fread( &mdl->info, sizeof(mdl_file_header), 1, mdl->file );
+   if( l != 1 )
+      mdl_load_fatal_corrupt( mdl );
+}
 
-   if( header->file_length != size )
-   {
-      vg_error( "Invalid file '%s'"
-                "(wrong .file_length, %ub != real file size %ub)\n", 
-                path, header->file_length, size );
-      vg_free( header );
-      return NULL;
-   }
+/*
+ * Load all metadata (everything up until the large buffers). Probs at most 50k
+ */
+VG_STATIC void mdl_load_metadata( mdl_context *mdl, void *lin_alloc )
+{
+   assert( mdl->file );
+   
+   u64 lheader  = sizeof(mdl_file_header),
+       ldata    = mdl->info.keyframe_offset - lheader;
 
-   /*
-    * Validate offsets and memory sections, to ensure all arrays are in-bounds,
-    * and that they do not overlap.
-    */
+   void *all_data = vg_linear_alloc( lin_alloc, ldata );
 
-   struct memregion
+   fseek( mdl->file, lheader, SEEK_SET );
+   u64 l = fread( all_data, ldata, 1, mdl->file );
+
+   if( l != 1 )
    {
-      const char *desc;
-      u32 count, max_count, size, offset;
+      vg_file_print_invalid( mdl->file );
+      vg_fatal_exit_loop( "Corrupt model" );
    }
-   regions[] = {
-      { 
-         "Vertices",
-         header->vertex_count, MDL_VERT_MAX, 
-         sizeof(mdl_vert), header->vertex_offset 
-      },
-      {
-         "Indices",
-         header->indice_count, MDL_INDICE_MAX,
-         sizeof(u32), header->indice_offset 
-      },
-      { 
-         "Submesh",
-         header->submesh_count, MDL_SUBMESH_MAX,
-         sizeof(mdl_submesh), header->submesh_offset 
-      },
-      { 
-         "Materials",
-         header->material_count, MDL_MATERIAL_MAX,
-         sizeof(mdl_material), header->material_offset
-      },
-      { 
-         "Nodes",
-         header->node_count, MDL_NODE_MAX,
-         sizeof(mdl_node), header->node_count
-      }
-   };
 
-   for( int i=0; i<vg_list_size(regions); i++ )
-   {
-      struct memregion *ri = &regions[i];
+   mdl->node_buffer     = all_data + (mdl->info.node_offset     - lheader);
+   mdl->submesh_buffer  = all_data + (mdl->info.submesh_offset  - lheader);
+   mdl->material_buffer = all_data + (mdl->info.material_offset - lheader);
+   mdl->anim_buffer     = all_data + (mdl->info.anim_offset     - lheader);
+   mdl->entdata_buffer  = all_data + (mdl->info.entdata_offset  - lheader);
+   mdl->string_buffer   = all_data + (mdl->info.strings_offset  - lheader);
+}
 
-      if( ri->count == 0 )
-         continue;
+/*
+ * Load just the mesh data
+ */
+VG_STATIC void mdl_load_mesh_data( mdl_context *mdl, void *lin_alloc )
+{
+   assert( mdl->file );
+   
+   u64 size_verts = mdl->info.vertex_count * sizeof(mdl_vert),
+       size_index = mdl->info.indice_count * sizeof(u32);
 
-      if( ri->count > ri->max_count )
-      {
-         vg_free( header );
-         vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n",
-               path, ri->desc, ri->count, ri->max_count );
-         return NULL;
-      }
+   mdl->vertex_buffer = vg_linear_alloc( lin_alloc, size_verts );
+   mdl->index_buffer  = vg_linear_alloc( lin_alloc, size_index );
+                                                    
+   {
+      fseek( mdl->file, mdl->info.vertex_offset, SEEK_SET );
+      u64 l = fread( mdl->vertex_buffer, size_verts, 1, mdl->file );
+      if( l != 1 )
+         mdl_load_fatal_corrupt( mdl );
+   }
+   {
+      fseek( mdl->file, mdl->info.indice_offset, SEEK_SET );
+      u64 l = fread( mdl->index_buffer, size_index, 1, mdl->file );
+      if( l != 1 )
+         mdl_load_fatal_corrupt( mdl );
+   }
+}
 
-      if( ri->offset >= header->file_length )
-      {
-         vg_free( header );
-         vg_error( "'%s': '%s' buffer offset is out of range\n",
-               path, ri->desc );
-         return NULL;
-      }
+/* 
+ * Load animation data
+ */
+VG_STATIC void mdl_load_anim_data( mdl_context *mdl, void *lin_alloc )
+{
+   assert( mdl->file );
 
-      if( ri->offset + ri->size*ri->count > header->file_length )
-      {
-         vg_free( header );
-         vg_error( "'%s': '%s' buffer size is out of range\n",
-               path, ri->desc );
-         return NULL;
-      }
+   if( mdl->info.keyframe_count == 0 )
+      return;
+   
+   u64 size_kf = mdl->info.keyframe_count * sizeof(mdl_keyframe);
+   mdl->keyframe_buffer = vg_linear_alloc( lin_alloc, size_kf );
+                                                    
+   fseek( mdl->file, mdl->info.keyframe_offset, SEEK_SET );
+   u64 l = fread( mdl->keyframe_buffer, size_kf, 1, mdl->file );
+   if( l != 1 )
+      mdl_load_fatal_corrupt( mdl );
+}
 
-      for( int j=0; j<vg_list_size(regions); j++ )
-      {
-         struct memregion *rj = &regions[j];
-         if( rj->count == 0 )
-            continue;
+/*
+ * close file handle
+ */
+VG_STATIC void mdl_close( mdl_context *mdl )
+{
+   fclose( mdl->file );
+   mdl->file = NULL;
+}
 
-         if( ri->offset >= rj->offset && 
-               (ri->offset+ri->size*ri->count < rj->offset+rj->size*rj->count))
-         {
-            vg_free( header );
-            vg_error( "'%s': '%s' buffer overlaps '%s'\n",
-                  path, ri->desc, rj->desc );
-            return NULL;
-         }
-      }
-   }
+/* open a model */
+VG_STATIC mdl_context *mdl_load_full( void *lin_alloc, const char *path )
+{
+   /* Inspect the header by opening it, give us the size needed */
+   mdl_context temp_ctx;
+   mdl_open( &temp_ctx, path );
 
-   /*
-    * Pointer validation TODO(workshop)
-    */
+   /* create allocator */
+   u32 tot_size = temp_ctx.info.file_length + sizeof( mdl_context );
+   void *data = vg_create_linear_allocator( lin_alloc, tot_size );
 
-   /*
-    * strings TODO(workshop)
-    */
+   /* copy context and load all other data */
+   mdl_context *ctx = vg_linear_alloc( data, sizeof(mdl_context) );
+   memcpy( ctx, &temp_ctx, sizeof(mdl_context) );
 
-   return header;
-}
+   mdl_load_metadata( ctx, data );
+   mdl_load_anim_data( ctx, data );
+   mdl_load_mesh_data( ctx, data );
+   mdl_close( ctx );
 
-static void *mdl_baseptr( mdl_header *mdl, u32 offset )
-{
-   return (void *)mdl + offset;
+   return ctx;
 }
 
-static const char *mdl_pstr( mdl_header *mdl, u32 pstr )
+/*
+ * Item getters
+ * ----------------------------------------------------------------------------
+ * TODO: Clamp access and oob errors
+ */
+VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr )
 {
-   return (const char *)(mdl_baseptr( mdl, mdl->strings_offset )) + pstr;
+   return mdl->string_buffer + pstr;
 }
 
-static mdl_node *mdl_node_from_id( mdl_header *mdl, u32 id )
+VG_STATIC mdl_node *mdl_node_from_id( mdl_context *mdl, u32 id )
 {
-   return ((mdl_node *)mdl_baseptr( mdl, mdl->node_offset )) + id;
+   return &mdl->node_buffer[id];
 }
 
-static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name )
+VG_STATIC mdl_node *mdl_node_from_name( mdl_context *mdl, const char *name )
 {
-   for( int i=0; i<mdl->node_count; i++ )
+   for( int i=0; i < mdl->info.node_count; i++ )
    {
       mdl_node *pnode = mdl_node_from_id( mdl, i );
       
@@ -465,43 +509,23 @@ static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name )
    return NULL;
 }
 
-static mdl_submesh *mdl_submesh_from_id( mdl_header *mdl, u32 id )
-{
-   if( id >= mdl->submesh_count )
-      return NULL;
-
-   return ((mdl_submesh *)mdl_baseptr( mdl, mdl->submesh_offset )) + id;
-}
-
-static mdl_submesh *mdl_node_submesh( mdl_header *mdl, mdl_node *node, u32 i )
-{
-   if( i >= node->submesh_count )
-      return NULL;
-
-   return mdl_submesh_from_id( mdl, node->submesh_start+i );
-}
-
-static u32 *mdl_submesh_indices( mdl_header *mdl, mdl_submesh *sm )
+VG_STATIC mdl_submesh *mdl_node_submesh( mdl_context *mdl, 
+                                         mdl_node *node, u32 i )
 {
-   return ((u32 *)mdl_baseptr( mdl, mdl->indice_offset )) + sm->indice_start;
+   return &mdl->submesh_buffer[ node->submesh_start+i ];
 }
 
-static mdl_vert *mdl_submesh_vertices( mdl_header *mdl, mdl_submesh *sm )
+VG_STATIC u32 *mdl_submesh_indices( mdl_context *mdl, mdl_submesh *sm )
 {
-   return ((mdl_vert *)mdl_baseptr(mdl,mdl->vertex_offset)) + sm->vertex_start;
+   return &mdl->index_buffer[ sm->indice_start ];
 }
 
-static mdl_material *mdl_material_from_id( mdl_header *mdl, u32 id )
+VG_STATIC mdl_vert *mdl_submesh_vertices( mdl_context *mdl, mdl_submesh *sm )
 {
-   return ((mdl_material *)mdl_baseptr(mdl,mdl->material_offset)) + id;
+   return &mdl->vertex_buffer[ sm->vertex_start ];
 }
 
-static mdl_animation *mdl_animation_from_id( mdl_header *mdl, u32 id )
-{
-   return ((mdl_animation *)mdl_baseptr(mdl,mdl->anim_offset)) + id;
-}
-
-static void mdl_node_transform( mdl_node *pnode, m4x3f transform )
+VG_STATIC void mdl_node_transform( mdl_node *pnode, m4x3f transform )
 {
    q_m3x3( pnode->q, transform );
    v3_muls( transform[0], pnode->s[0], transform[0] );
@@ -510,20 +534,23 @@ static void mdl_node_transform( mdl_node *pnode, m4x3f transform )
    v3_copy( pnode->co, transform[3] );
 }
 
-static void mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm )
+/* upload a mesh based on file submesh */
+VG_STATIC void mdl_unpack_submesh( mdl_context *mdl, glmesh *mesh, 
+                                mdl_submesh *sm )
 {
    mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count,
                       mdl_submesh_indices( mdl, sm ), sm->indice_count );
 }
 
-static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh )
+/* upload entire mesh from model */
+VG_STATIC void mdl_unpack_glmesh( mdl_context *mdl, glmesh *mesh )
 {
-   u32 offset = mdl_submesh_from_id( mdl, 0 )->vertex_count;
+   u32 offset = mdl->submesh_buffer[0].vertex_count;
 
-   for( int i=1; i< mdl->submesh_count; i++ )
+   for( int i=1; i< mdl->info.submesh_count; i++ )
    {
-      mdl_submesh *sm = mdl_submesh_from_id( mdl, i );
-      u32 *indices =    mdl_submesh_indices( mdl, sm );
+      mdl_submesh *sm = &mdl->submesh_buffer[i];
+      u32 *indices    =  mdl_submesh_indices( mdl, sm );
 
       for( u32 j=0; j<sm->indice_count; j++ )
          indices[j] += offset;
@@ -531,42 +558,39 @@ static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh )
       offset += sm->vertex_count;
    }
 
-   mdl_vert *vertex_base = mdl_baseptr( mdl, mdl->vertex_offset );
-   u32 *indice_base = mdl_baseptr( mdl, mdl->indice_offset );
-
-   mesh_upload( mesh, vertex_base, mdl->vertex_count,
-                      indice_base, mdl->indice_count ); 
+   mesh_upload( mesh, mdl->vertex_buffer, mdl->info.vertex_count,
+                      mdl->index_buffer,  mdl->info.indice_count ); 
 }
 
-static void mdl_draw_submesh( mdl_submesh *sm )
+VG_STATIC void mdl_draw_submesh( mdl_submesh *sm )
 {
    mesh_drawn( sm->indice_start, sm->indice_count );
 }
 
-static void *mdl_get_entdata( mdl_header *mdl, mdl_node *pnode )
+VG_STATIC void *mdl_get_entdata( mdl_context *mdl, mdl_node *pnode )
 {
-   return mdl_baseptr( mdl, mdl->entdata_offset ) + pnode->offset;
+   return mdl->entdata_buffer + pnode->offset;
 }
 
-static mdl_keyframe *mdl_get_animdata( mdl_header *mdl, mdl_animation *anim )
+VG_STATIC mdl_keyframe *mdl_get_animdata( mdl_context *mdl, mdl_animation *anim )
 {
-   return mdl_baseptr( mdl, mdl->animdata_offset ) + anim->offset;
+   return mdl->keyframe_buffer + anim->offset;
 }
 
-static void mdl_link_materials( mdl_header *root, mdl_header *child )
+VG_STATIC void mdl_link_materials( mdl_context *root, mdl_context *child )
 {
    u32 lookup[MDL_MATERIAL_MAX];
    
-   for( int i=0; i<child->material_count; i++ )
+   for( int i=0; i<child->info.material_count; i++ )
    {
-      mdl_material *mi = mdl_material_from_id( child, i );
+      mdl_material *mi = &child->material_buffer[i];
       const char *si = mdl_pstr( child, mi->pstr_name );
 
       lookup[i] = 0;
 
-      for( int j=0; j<root->material_count; j++ )
+      for( int j=0; j<root->info.material_count; j++ )
       {
-         mdl_material *mj = mdl_material_from_id( root, j );
+         mdl_material *mj = &root->material_buffer[j];
          const char *sj = mdl_pstr( root, mj->pstr_name );
          
          if( !strcmp( si, sj ) )
@@ -583,10 +607,10 @@ static void mdl_link_materials( mdl_header *root, mdl_header *child )
       }
    }
 
-   for( int i=0; i<child->submesh_count; i++ )
+   for( int i=0; i<child->info.submesh_count; i++ )
    {
-      mdl_submesh *sm = mdl_submesh_from_id( child, i );
-      sm->material_id = lookup[sm->material_id];
+      mdl_submesh *sm = &child->submesh_buffer[i];
+      sm->material_id =  lookup[sm->material_id];
    }
 }
 
index b5b0798bc89c92e05ca925a81c31bfecef4ae11e..502c98e5103299637a9e130228b277eedd8e60a2 100644 (file)
Binary files a/models_src/alter.mdl and b/models_src/alter.mdl differ
index 0d669618e2f47c90a23dd521b6289b8f57c1c3ee..7877bd285eea2e969acc6636748d91d024bf7c2a 100644 (file)
Binary files a/models_src/ch_default.mdl and b/models_src/ch_default.mdl differ
index 6448b33c8cdcf5ac11f8b04b0a18f9956020525d..ce85ad92e2e59dacde229a11309901c80de03b17 100644 (file)
Binary files a/models_src/ch_empty.mdl and b/models_src/ch_empty.mdl differ
index 80482dc745b6766d2fefbdcfa937ac5611253d54..0f65fb20133a08ce7d1980b317ef389f7f3a6f53 100644 (file)
Binary files a/models_src/ch_jordan.mdl and b/models_src/ch_jordan.mdl differ
index 6296030ba3e1462368c08a78540dea22b7d15d6b..44e128f0d177bb5e2b32ed53b429347052401dab 100644 (file)
Binary files a/models_src/ch_mike.mdl and b/models_src/ch_mike.mdl differ
index df1e23c0aff6a4df0acbe7bd2fafbcd5d2e1bcab..71c7a3f80fdb00f0aa4419d8696f2c3d2562d7cb 100644 (file)
Binary files a/models_src/ch_new.mdl and b/models_src/ch_new.mdl differ
diff --git a/models_src/ch_outlaw.001.mdl b/models_src/ch_outlaw.001.mdl
new file mode 100644 (file)
index 0000000..fa40549
Binary files /dev/null and b/models_src/ch_outlaw.001.mdl differ
index 0fffc5ccd801b41564f3970d45b76d615c383ba9..ee1bbb80d8f32a3c27c9dd50ab9ed22650f1be99 100644 (file)
Binary files a/models_src/ch_outlaw.mdl and b/models_src/ch_outlaw.mdl differ
index 858fe3d41a5d95f7424b1d985131f9e986ba7cf4..faabb16a3af229088b78ad217e64ee222975103b 100644 (file)
Binary files a/models_src/epic_scene.mdl and b/models_src/epic_scene.mdl differ
index 7a27b2518b05d8de2631ff81b97a5b7d4ea2451d..1f8a3dbf59e54a61bbf499d249b1fd3ff4621e52 100644 (file)
Binary files a/models_src/mp_dev.mdl and b/models_src/mp_dev.mdl differ
diff --git a/models_src/mp_test.mdl b/models_src/mp_test.mdl
new file mode 100644 (file)
index 0000000..28b0a8b
Binary files /dev/null and b/models_src/mp_test.mdl differ
index 6e751036969aa62f70dac513a0020372f51e3c0a..40ddec8bed9d8163a7d41c3f4ad8f3ac2bf6260d 100644 (file)
Binary files a/models_src/rs_cars.mdl and b/models_src/rs_cars.mdl differ
index 73c66867e328244b3196ddd028af308f780d1896..5e72b53cd1c91966ffe5f32b34487b9db353baa0 100644 (file)
Binary files a/models_src/rs_chicken.mdl and b/models_src/rs_chicken.mdl differ
index bac68665acb0599c436cdac03b2e201a8a60aef2..adfdd5bebc5837bf4df1d6e5fd2a36723dd2854a 100644 (file)
Binary files a/models_src/rs_foliage.mdl and b/models_src/rs_foliage.mdl differ
index 30c54bc22b46b7f9f73310a02d0fb7d612a032b6..07e5ab267d8e056b92ac8547326214a1431d1e09 100644 (file)
Binary files a/models_src/rs_gate.mdl and b/models_src/rs_gate.mdl differ
index 160d37e2dca6b25ca9086728525b6478d340c7b6..dcee13c02f039f08e4602fe352ea2814ea535eb9 100644 (file)
Binary files a/models_src/rs_menu.mdl and b/models_src/rs_menu.mdl differ
index 876dc580dcbd66c31c3d48fb47d180c66d39733c..637d1985e992f2ce4d05559a8a8361e93465dbd8 100644 (file)
Binary files a/models_src/rs_scoretext.mdl and b/models_src/rs_scoretext.mdl differ
index 9cc16f0671a8e01a1b55837586dc6e81768ae5bb..a3aea27c35f13f821893cf77ad8f7755b75f0d6c 100644 (file)
Binary files a/models_src/rs_skydome.mdl and b/models_src/rs_skydome.mdl differ
index 26cdd0dc0fba211c4b39bdfbcd24e0621375ea47..2e27cf3f7c70803c54348d3bbd0a422e4bbeddb9 100644 (file)
Binary files a/models_src/rs_vig.mdl and b/models_src/rs_vig.mdl differ
index e06027aa88b97cc7d56154dc3e3a4c0d74a133f3..b47f518dd514b5003923f523cb12d8fa9fc1866b 100644 (file)
--- a/network.h
+++ b/network.h
 //#define SR_USE_LOCALHOST
 
 /* Call it at start; Connects us to the gameserver */
-static void network_init(void);
+VG_STATIC void network_init(void);
 
 /* Run this from main loop */
-static void network_update(void);
+VG_STATIC void network_update(void);
 
 /* Call it at shutdown */
-static void network_end(void*_);
+VG_STATIC void network_end(void*_);
 
 /* 
  * Can buffer up a bunch of these by calling many times, they will be
  * sent at the next connection 
  */
-static void network_submit_highscore( u32 trackid, u16 points, u16 time );
+VG_STATIC void network_submit_highscore( u32 trackid, u16 points, u16 time );
 
 /*
  * Game endpoints are provided with the same names to allow running without a
@@ -40,21 +40,21 @@ static void network_submit_highscore( u32 trackid, u16 points, u16 time );
 /* 
  * Runtime connection stuff
  */
-static u8 steam_app_ticket[ 1024 ];
-static u32 steam_app_ticket_length;
-static int network_name_update = 1;
+VG_STATIC u8 steam_app_ticket[ 1024 ];
+VG_STATIC u32 steam_app_ticket_length;
+VG_STATIC int network_name_update = 1;
 
-static HSteamNetConnection cremote;
-static ESteamNetworkingConnectionState cremote_state = 
+VG_STATIC HSteamNetConnection cremote;
+VG_STATIC ESteamNetworkingConnectionState cremote_state = 
      k_ESteamNetworkingConnectionState_None;
 
 /* 
  * Implementation
  */
 
-static void scores_update(void);
+VG_STATIC void scores_update(void);
 
-static void on_auth_ticket_recieved( void *result, void *context )
+VG_STATIC void on_auth_ticket_recieved( void *result, void *context )
 {
    EncryptedAppTicketResponse_t *response = result;
 
@@ -82,7 +82,7 @@ static void on_auth_ticket_recieved( void *result, void *context )
    }
 }
 
-static void request_auth_ticket(void)
+VG_STATIC void request_auth_ticket(void)
 {
    /* 
     * TODO Check for one thats cached on the disk and load it.
@@ -97,7 +97,7 @@ static void request_auth_ticket(void)
                                                               NULL, 0 );
 }
 
-static void send_auth_ticket(void)
+VG_STATIC void send_auth_ticket(void)
 {
    u32 size = sizeof(netmsg_auth) + steam_app_ticket_length;
    netmsg_auth *auth = alloca(size);
@@ -112,7 +112,7 @@ static void send_auth_ticket(void)
          k_nSteamNetworkingSend_Reliable, NULL );
 }
 
-static void send_score_request(void)
+VG_STATIC void send_score_request(void)
 {
    vg_info( "Requesting scores\n" );
    netmsg_scores_request req;
@@ -123,7 +123,7 @@ static void send_score_request(void)
          k_nSteamNetworkingSend_Reliable, NULL );
 }
 
-static void send_score_update(void)
+VG_STATIC void send_score_update(void)
 {
    vg_info( "Sending scores\n" );
    u32 size = sizeof(netmsg_set_score) + 
@@ -166,7 +166,7 @@ static void send_score_update(void)
          k_nSteamNetworkingSend_Reliable, NULL );
 }
 
-static void send_nickname(void)
+VG_STATIC void send_nickname(void)
 {
    netmsg_set_nickname nick;
    nick.inetmsg_id = k_inetmsg_set_nickname;
@@ -181,7 +181,7 @@ static void send_nickname(void)
    network_name_update = 0;
 }
 
-static void server_routine_update(void)
+VG_STATIC void server_routine_update(void)
 {
    send_auth_ticket();
 
@@ -192,7 +192,7 @@ static void server_routine_update(void)
    send_score_request();
 }
 
-static void on_server_connect_status( CallbackMsg_t *msg )
+VG_STATIC void on_server_connect_status( CallbackMsg_t *msg )
 {
    SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
    vg_info( "  Connection status changed for %lu\n", info->m_hConn );
@@ -216,7 +216,7 @@ static void on_server_connect_status( CallbackMsg_t *msg )
    }
 }
 
-static void network_connect_gc(void)
+VG_STATIC void network_connect_gc(void)
 {
    /* Connect to server if not connected */
    SteamNetworkingIPAddr remoteAddr;
@@ -236,7 +236,7 @@ static void network_connect_gc(void)
                   hSteamNetworkingSockets, &remoteAddr, 0, NULL );
 }
 
-static void on_inet_scoreboard( SteamNetworkingMessage_t *msg )
+VG_STATIC void on_inet_scoreboard( SteamNetworkingMessage_t *msg )
 {
    netmsg_scoreboard *sb = msg->m_pData;
 
@@ -272,7 +272,7 @@ static void on_inet_scoreboard( SteamNetworkingMessage_t *msg )
    network_scores_updated = 1;
 }
 
-static void poll_connection(void)
+VG_STATIC void poll_connection(void)
 {
    SteamNetworkingMessage_t *messages[32];
    int len;
@@ -308,7 +308,7 @@ static void poll_connection(void)
 /*
  * Subroutine to be connected to main game loop, runs all routines on timers
  */
-static void network_update(void)
+VG_STATIC void network_update(void)
 {
    if( steam_ready )
    {
@@ -339,7 +339,7 @@ static void network_update(void)
    }
 }
 
-static void network_init(void)
+VG_STATIC void network_init(void)
 {
    if( steam_ready )
    {
@@ -349,7 +349,7 @@ static void network_init(void)
    }
 }
 
-static void network_end(void*_)
+VG_STATIC void network_end(void*_)
 {
    /* TODO: Fire off any buffered highscores that need to be setn */
    if( cremote_state == k_ESteamNetworkingConnectionState_Connected ||
@@ -362,9 +362,9 @@ static void network_end(void*_)
 
 #else /* SR_NETWORKED */
 
-static void network_init(void){}
-static void network_update(void){}
-static void network_end(void*_){}
+VG_STATIC void network_init(void){}
+VG_STATIC void network_update(void){}
+VG_STATIC void network_end(void*_){}
 
 #endif /* SR_NETWORKED */
 #endif /* NETWORK_H */
index 1e3e4754adefe39499a01b51697710e4d27f90e5..5f1bc416a67e96b82d72813d1a063a62344097cb 100644 (file)
@@ -73,7 +73,7 @@ struct netmsg_scoreboard
    }
    boards[ vg_list_size(track_infos) ];
 }
-static scoreboard_client_data = { 
+VG_STATIC scoreboard_client_data = { 
    .inetmsg_id = k_inetmsg_scoreboard,
    .board_count = vg_list_size(track_infos)
 }; 
index a7831b7e3b982e6182903e3ff3fd51bed6b1a222..5a21afe662a2248252ecc776ecb7f5820e5ed64b 100644 (file)
--- a/player.h
+++ b/player.h
@@ -13,7 +13,7 @@
 #include "skeleton.h"
 #include "bvh.h"
 
-static float 
+VG_STATIC float 
    k_walkspeed             = 20.0f,  /* no longer used */
    k_runspeed              = 20.0f,
    k_board_radius          = 0.3f,
@@ -38,9 +38,10 @@ static float
    k_walk_accel            = 150.0f,
    k_walk_friction         = 8.0f;
 
-static int freecam = 0;
-static int walk_grid_iterations = 1;
-static float fc_speed = 10.0f;
+VG_STATIC int cl_playermdl_id = 0;
+VG_STATIC int freecam = 0;
+VG_STATIC int walk_grid_iterations = 1;
+VG_STATIC float fc_speed = 10.0f;
 
 /* 
  * -----------------------------------------------------------------------------
@@ -48,7 +49,7 @@ static float fc_speed = 10.0f;
  * -----------------------------------------------------------------------------
  */
 
-static struct gplayer
+VG_STATIC struct gplayer
 {
    /* Physics */
    rigidbody collide_front, collide_back;
@@ -127,7 +128,9 @@ static struct gplayer
    /* player model */
    struct player_model
    {
-      glmesh mesh;
+      glmesh player_meshes[3];
+
+      mdl_context meta;
       struct skeleton sk;
       struct skeleton_anim *anim_stand,
                            *anim_highg,
@@ -159,7 +162,7 @@ static struct gplayer
          rigidbody  rb;
          u32 parent;
       }
-      *ragdoll;
+      ragdoll[32];
       u32 ragdoll_count;
 
       int shoes[2];
@@ -175,12 +178,12 @@ player =
 /* 
  * API 
  */
-static float *player_get_pos(void);
-static void player_kill(void);
-static float *player_cam_pos(void);
-static void player_save_frame(void);
-static void player_restore_frame(void);
-static void player_save_rewind_frame(void);
+VG_STATIC float *player_get_pos(void);
+VG_STATIC void player_kill(void);
+VG_STATIC float *player_cam_pos(void);
+VG_STATIC void player_save_frame(void);
+VG_STATIC void player_restore_frame(void);
+VG_STATIC void player_save_rewind_frame(void);
 
 /* 
  * Submodules
@@ -197,12 +200,20 @@ static void player_save_rewind_frame(void);
  * -----------------------------------------------------------------------------
  */
 
-static void player_init(void)                                            /* 1 */
+VG_STATIC void player_init(void)                                            /* 1 */
 {
    rb_init( &player.phys.rb );
    rb_init( &player.collide_front );
    rb_init( &player.collide_back  );
 
+   vg_convar_push( (struct vg_convar){
+      .name = "cl_playermdl_id",
+      .data = &cl_playermdl_id,
+      .data_type = k_convar_dtype_i32,
+      .opt_i32 = { .min=0, .max=2, .clamp=1 },
+      .persistent = 1
+   });
+
    vg_convar_push( (struct vg_convar){
       .name = "walk_speed",
       .data = &k_walkspeed,
@@ -249,14 +260,14 @@ static void player_init(void)                                            /* 1 */
        });
 
    player.rewind_length = 0;
-   player.rewind_buffer = vg_alloc( sizeof(struct rewind_frame) 
-                                       * PLAYER_REWIND_FRAMES );
+   player.rewind_buffer = 
+      vg_linear_alloc( vg_mem.rtmemory, 
+                       sizeof(struct rewind_frame) * PLAYER_REWIND_FRAMES );
 
-   /* other systems */
-   vg_loader_highwater( player_model_init, player_model_free, NULL );
+   player_model_init();
 }
 
-static void player_save_rewind_frame(void)
+VG_STATIC void player_save_rewind_frame(void)
 {
    if( player.rewind_length < PLAYER_REWIND_FRAMES )
    {
@@ -278,7 +289,7 @@ static void player_save_rewind_frame(void)
 }
 
 /* Deal with input etc */
-static void player_update_pre(void)
+VG_STATIC void player_update_pre(void)
 {
    struct player_phys *phys = &player.phys;
 
@@ -289,7 +300,7 @@ static void player_update_pre(void)
 
    if( vg_get_button_down( "reset" ) )
    {
-      double delta = world_routes.time - world_routes.last_use;
+      double delta = world.time - world.last_use;
 
       if( delta <= RESET_MAX_TIME )
       {
@@ -353,7 +364,7 @@ static void player_update_pre(void)
    }
 }
 
-static void player_update_fixed(void)                                    /* 2 */
+VG_STATIC void player_update_fixed(void)                                    /* 2 */
 {
    if( player.rewinding )
       return;
@@ -380,7 +391,7 @@ static void player_update_fixed(void)                                    /* 2 */
    }
 }
 
-static void player_update_post(void)
+VG_STATIC void player_update_post(void)
 {
    for( int i=0; i<player.land_log_count; i++ )
       vg_line_cross( player.land_target_log[i], 
@@ -539,7 +550,7 @@ static void player_update_post(void)
    player_audio();
 }
 
-static void draw_player( m4x3f cam )
+VG_STATIC void draw_player( m4x3f cam )
 {
    if( player.is_dead )
       player_model_copy_ragdoll();
@@ -555,8 +566,8 @@ static void draw_player( m4x3f cam )
                          0,
                          (float *)player.mdl.sk.final_mtx );
    
-   mesh_bind( &player.mdl.mesh );
-   mesh_draw( &player.mdl.mesh );
+   mesh_bind( &player.mdl.player_meshes[cl_playermdl_id] );
+   mesh_draw( &player.mdl.player_meshes[cl_playermdl_id] );
 }
 
 /* 
@@ -565,12 +576,12 @@ static void draw_player( m4x3f cam )
  * -----------------------------------------------------------------------------
  */
 
-static float *player_get_pos(void)
+VG_STATIC float *player_get_pos(void)
 {
    return player.phys.rb.co;
 }
 
-static void player_kill(void)
+VG_STATIC void player_kill(void)
 {
    if( player.death_tick_allowance == 0 )
    {
@@ -579,7 +590,7 @@ static void player_kill(void)
    }
 }
 
-static float *player_cam_pos(void)
+VG_STATIC float *player_cam_pos(void)
 {
    return player.camera_pos;
 }
index 9f0c0d536e832c7d39c8927d4589ec12c3685b6d..594f282c3be7e8917bcb111a98d84080dbc17c1d 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "player.h"
 
-static void player_animate_offboard(void)
+VG_STATIC void player_animate_offboard(void)
 {
    {
       float fly = player.phys.in_air,
@@ -83,7 +83,7 @@ static void player_animate_offboard(void)
    skeleton_debug( &player.mdl.sk );
 }
 
-static void player_animate(void)
+VG_STATIC void player_animate(void)
 {
    struct player_phys *phys = &player.phys;
    rb_extrapolate_transform( &player.phys.rb, player.visual_transform );
@@ -274,7 +274,7 @@ static void player_animate(void)
    skeleton_debug( &player.mdl.sk );
 }
 
-static void player_animate_death_cam(void)
+VG_STATIC void player_animate_death_cam(void)
 {
    v3f delta;
    v3f head_pos;
@@ -300,14 +300,17 @@ static void player_animate_death_cam(void)
    if( ray_world( sample, (v3f){0.0f,-1.0f,0.0f}, &hit ))
       v3_add( hit.pos, min_height, player.camera_pos );
 
-   player.camera_pos[1] = 
-      vg_maxf( wrender.height + 2.0f, player.camera_pos[1] );
+   if( world.water.enabled )
+   {
+      player.camera_pos[1] = 
+         vg_maxf( world.water.height + 2.0f, player.camera_pos[1] );
+   }
 
    player.angles[0] = atan2f( delta[0], -delta[2] ); 
    player.angles[1] = -asinf( delta[1] );
 }
 
-static void player_animate_camera(void)
+VG_STATIC void player_animate_camera(void)
 {
    struct player_phys *phys = &player.phys;
 
index 00bc9c440fb39540c54afc8611188b3e4efd1d74..298ce0f0dab5994bcdd6e0d1f62e70a996983b78 100644 (file)
@@ -10,7 +10,7 @@
 /* 
  * Audio
  */
-static void player_audio(void)
+VG_STATIC void player_audio(void)
 {
    struct player_phys *phys = &player.phys;
 
index 4766c1695951653828931bc91c1a39fcc3478d96..cab438e9d7c24afebffb36045a8486e0d5c441c1 100644 (file)
@@ -11,7 +11,7 @@
 
 vg_tex2d tex_characters = { .path = "textures/ch_gradient.qoi" };
 
-static void player_model_init(void)
+VG_STATIC void player_model_init(void)
 {
    shader_viewchar_register();
    vg_acquire_thread_sync();
@@ -19,112 +19,106 @@ static void player_model_init(void)
       vg_tex2d_init( (vg_tex2d *[]){ &tex_characters }, 1 );
    }
    vg_release_thread_sync();
-}
-
-static void player_model_free(void *_)
-{
-   mesh_free( &player.mdl.mesh );
-   vg_tex2d_free( (vg_tex2d *[]){ &tex_characters }, 1 );
-}
-
-/*
- * Load model from file (.mdl)
- */
-static void player_load_model( const char *name, int replace_mode )
-{
-   char buf[64];
-
-   snprintf( buf, sizeof(buf)-1, "models/%s.mdl", name );
-   mdl_header *src = mdl_load( buf );
 
-   if( !src )
+   /* load in reference player model, with animations and such */
+   mdl_open( &player.mdl.meta, "models/ch_new.mdl" );
+   mdl_load_metadata( &player.mdl.meta, vg_mem.rtmemory );
+   mdl_load_anim_data( &player.mdl.meta, vg_mem.rtmemory );
+
+   vg_linear_clear( vg_mem.scratch );
+   mdl_load_mesh_data( &player.mdl.meta, vg_mem.scratch );
+   mdl_close( &player.mdl.meta );
+
+   /* 
+    * load in other player models. This may need to be more sophisticated in
+    * the futre if we have more of these guys
+    */
+   mdl_context ctx_outlaw,
+               ctx_jordan;
+
+   mdl_open( &ctx_outlaw, "models/ch_outlaw.mdl" );
+   mdl_load_metadata( &ctx_outlaw, vg_mem.scratch );
+   mdl_load_mesh_data( &ctx_outlaw, vg_mem.scratch );
+   mdl_close( &ctx_outlaw );
+
+   mdl_open( &ctx_jordan, "models/ch_jordan.mdl" );
+   mdl_load_metadata( &ctx_jordan, vg_mem.scratch );
+   mdl_load_mesh_data( &ctx_jordan, vg_mem.scratch );
+   mdl_close( &ctx_jordan );
+   
+   vg_acquire_thread_sync();
    {
-      vg_error( "Could not load model\n" );
-      return;
+      mdl_unpack_glmesh( &player.mdl.meta, &player.mdl.player_meshes[0] );
+      mdl_unpack_glmesh( &ctx_outlaw, &player.mdl.player_meshes[1] );
+      mdl_unpack_glmesh( &ctx_jordan, &player.mdl.player_meshes[2] );
    }
+   vg_release_thread_sync();
 
-   mesh_free( &player.mdl.mesh );
-   mdl_unpack_glmesh( src, &player.mdl.mesh );
+   skeleton_setup( &player.mdl.sk, vg_mem.rtmemory, &player.mdl.meta );
+   player_init_ragdoll();
 
-   if( !replace_mode )
+   /* 
+    * Link animations
+    */
+   struct _load_anim
    {
-      if( !skeleton_setup( &player.mdl.sk, src ) )
-      {
-         vg_error( "Model: %s\n", buf );
-         vg_fatal_exit_loop( "No skeleton" );
-      }
-
-      /* 
-       * Link animations
-       */
-      struct _load_anim
-      {
-         const char *name;
-         struct skeleton_anim **anim;
-      }
-      anims[] = {
-         { "pose_stand",   &player.mdl.anim_stand },
-         { "pose_highg",   &player.mdl.anim_highg },
-         { "pose_slide",   &player.mdl.anim_slide },
-         { "pose_air",     &player.mdl.anim_air   },
-         { "push",         &player.mdl.anim_push  },
-         { "push_reverse", &player.mdl.anim_push_reverse },
-         { "ollie",        &player.mdl.anim_ollie },
-         { "ollie_reverse",&player.mdl.anim_ollie_reverse },
-         { "grabs",        &player.mdl.anim_grabs },
-         { "walk",         &player.mdl.anim_walk  },
-         { "run",          &player.mdl.anim_run   },
-         { "idle_cycle",   &player.mdl.anim_idle  },
-         { "jump",         &player.mdl.anim_jump  }
-      };
+      const char *name;
+      struct skeleton_anim **anim;
+   }
+   anims[] = {
+      { "pose_stand",   &player.mdl.anim_stand },
+      { "pose_highg",   &player.mdl.anim_highg },
+      { "pose_slide",   &player.mdl.anim_slide },
+      { "pose_air",     &player.mdl.anim_air   },
+      { "push",         &player.mdl.anim_push  },
+      { "push_reverse", &player.mdl.anim_push_reverse },
+      { "ollie",        &player.mdl.anim_ollie },
+      { "ollie_reverse",&player.mdl.anim_ollie_reverse },
+      { "grabs",        &player.mdl.anim_grabs },
+      { "walk",         &player.mdl.anim_walk  },
+      { "run",          &player.mdl.anim_run   },
+      { "idle_cycle",   &player.mdl.anim_idle  },
+      { "jump",         &player.mdl.anim_jump  }
+   };
+   
+   for( int i=0; i<vg_list_size(anims); i++ )
+   {
+      *anims[i].anim = skeleton_get_anim( &player.mdl.sk, anims[i].name );
       
-      for( int i=0; i<vg_list_size(anims); i++ )
+      if( !(*anims[i].anim) )
       {
-         *anims[i].anim = skeleton_get_anim( &player.mdl.sk, anims[i].name );
-         
-         if( !(*anims[i].anim) )
-         {
-            vg_error( "Animation '%s' is missing from character '%s'\n",
-                        anims[i].name, name );
-            vg_free( src );
-            return;
-         }
+         vg_error( "Animation '%s' is missing\n", anims[i].name );
+         vg_fatal_exit_loop( "Invalid character file" );
       }
+   }
 
-      /* 
-       * Link bones
-       */
-      struct _load_bone
-      {
-         const char *name;
-         u32 *bone_id;
-      }
-      bones[] = {
-         { "hips",      &player.mdl.id_hip },
-         { "hand.IK.L", &player.mdl.id_ik_hand_l },
-         { "hand.IK.R", &player.mdl.id_ik_hand_r },
-         { "elbow.L",   &player.mdl.id_ik_elbow_l },
-         { "elbow.R",   &player.mdl.id_ik_elbow_r },
-         { "head",      &player.mdl.id_head }
-      };
+   /* 
+    * Link bones
+    */
+   struct _load_bone
+   {
+      const char *name;
+      u32 *bone_id;
+   }
+   bones[] = {
+      { "hips",      &player.mdl.id_hip },
+      { "hand.IK.L", &player.mdl.id_ik_hand_l },
+      { "hand.IK.R", &player.mdl.id_ik_hand_r },
+      { "elbow.L",   &player.mdl.id_ik_elbow_l },
+      { "elbow.R",   &player.mdl.id_ik_elbow_r },
+      { "head",      &player.mdl.id_head }
+   };
+
+   for( int i=0; i<vg_list_size(bones); i++ )
+   {
+      *bones[i].bone_id = skeleton_bone_id( &player.mdl.sk, bones[i].name );
 
-      for( int i=0; i<vg_list_size(bones); i++ )
+      if( !(*bones[i].bone_id) )
       {
-         *bones[i].bone_id = skeleton_bone_id( &player.mdl.sk, bones[i].name );
-
-         if( !(*bones[i].bone_id) )
-         {
-            vg_error( "Required bone '%s' is missing from character '%s'\n",
-                        bones[i].name, name );
-            vg_free( src );
-            return;
-         }
+         vg_error( "Required bone '%s' is missing\n", bones[i].name );
+         vg_fatal_exit_loop( "Invalid character file" );
       }
-
-      player_init_ragdoll( src );
    }
-
-   vg_free( src );
 }
 
 #endif
index d5b112be60d51242f64a21e5d1c7f71eedd136fa..90ea030a7bd2adab89cd6dc61a9de61155b32f93 100644 (file)
@@ -8,7 +8,7 @@
 #include "player.h"
 #include "camera.h"
 
-static void apply_gravity( v3f vel, float const timestep )
+VG_STATIC void apply_gravity( v3f vel, float const timestep )
 {
    v3f gravity = { 0.0f, -9.6f, 0.0f };
    v3_muladds( vel, gravity, timestep, vel );
@@ -17,7 +17,7 @@ static void apply_gravity( v3f vel, float const timestep )
 /*
  * Called when launching into the air to predict and adjust trajectories
  */
-static void player_start_air(void)
+VG_STATIC void player_start_air(void)
 {
    struct player_phys *phys = &player.phys;
 
@@ -114,7 +114,7 @@ static void player_start_air(void)
 /*
  * Main friction interface model
  */
-static void player_physics_control(void)
+VG_STATIC void player_physics_control(void)
 {
    struct player_phys *phys = &player.phys;
 
@@ -206,7 +206,7 @@ static void player_physics_control(void)
 /*
  * Air control, no real physics
  */
-static void player_physics_control_air(void)
+VG_STATIC void player_physics_control_air(void)
 {
    struct player_phys *phys = &player.phys;
 
@@ -290,7 +290,7 @@ static void player_physics_control_air(void)
  * Entire Walking physics model
  * TODO: sleep when under certain velotiy
  */
-static void player_walk_physics(void)
+VG_STATIC void player_walk_physics(void)
 {
    struct player_phys *phys = &player.phys;
    rigidbody *rbf = &player.collide_front,
@@ -408,7 +408,7 @@ static void player_walk_physics(void)
 /*
  * Physics collision detection, and control
  */
-static void player_physics(void)
+VG_STATIC void player_physics(void)
 {
    struct player_phys *phys = &player.phys;
    /*
@@ -615,18 +615,18 @@ static void player_physics(void)
    phys->jump = vg_clampf( phys->jump, 0.0f, 1.0f );
 }
 
-static void player_save_frame(void)
+VG_STATIC void player_save_frame(void)
 {
    player.phys_gate_frame = player.phys;
 }
 
-static void player_restore_frame(void)
+VG_STATIC void player_restore_frame(void)
 {
    player.phys = player.phys_gate_frame;
    rb_update_transform( &player.phys.rb );
 }
 
-static void player_do_motion(void)
+VG_STATIC void player_do_motion(void)
 {
    struct player_phys *phys = &player.phys;
 
@@ -684,9 +684,9 @@ static void player_do_motion(void)
    /* 
     * Gate intersection, by tracing a line over the gate planes 
     */
-   for( int i=0; i<world_routes.gate_count; i++ )
+   for( int i=0; i<world.gate_count; i++ )
    {
-      struct route_gate *rg = &world_routes.gates[i];
+      struct route_gate *rg = &world.gates[i];
       teleport_gate *gate = &rg->gate;
 
       if( gate_intersect( gate, phys->rb.co, prevco ) )
@@ -732,9 +732,9 @@ static void player_do_motion(void)
 /*
  * Free camera movement
  */
-static void player_mouseview(void)
+VG_STATIC void player_mouseview(void)
 {
-   if( gui_want_mouse() )
+   if( ui_want_mouse() )
       return;
 
    static v2f mouse_last,
@@ -757,7 +757,7 @@ static void player_mouseview(void)
    player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
 }
 
-static void player_freecam(void)
+VG_STATIC void player_freecam(void)
 {
    player_mouseview();
 
@@ -782,7 +782,7 @@ static void player_freecam(void)
    v3_add( move_vel, player.camera_pos, player.camera_pos );
 }
 
-static int reset_player( int argc, char const *argv[] )
+VG_STATIC int reset_player( int argc, char const *argv[] )
 {
    struct player_phys *phys = &player.phys;
    struct respawn_point *rp = NULL, *r;
index 28776c3d683e487a4410541235315208e168f5b9..6193bf73e4f8bd4ca59fed263d1c6654fa05d670 100644 (file)
@@ -3,15 +3,16 @@
 
 #include "player.h"
 
-static float k_ragdoll_floatyiness = 20.0f,
+VG_STATIC float k_ragdoll_floatyiness = 20.0f,
              k_ragdoll_floatydrag  = 1.0f;
 
 /*
  * Setup ragdoll colliders 
  */
-static void player_init_ragdoll( mdl_header *src )
+VG_STATIC void player_init_ragdoll(void)
 {
    struct player_model *mdl = &player.mdl;
+   mdl_context *src = &mdl->meta;
 
    if( !mdl->sk.collider_count )
    {
@@ -19,7 +20,6 @@ static void player_init_ragdoll( mdl_header *src )
       return;
    }
 
-   mdl->ragdoll = vg_alloc(sizeof(struct ragdoll_part)*mdl->sk.collider_count);
    mdl->ragdoll_count = 0;
 
    for( u32 i=0; i<mdl->sk.bone_count; i ++ )
@@ -28,6 +28,9 @@ static void player_init_ragdoll( mdl_header *src )
       
       if( bone->collider )
       {
+         if( mdl->ragdoll_count > vg_list_size(player.mdl.ragdoll) )
+            vg_fatal_exit_loop( "Playermodel has too many colliders" );
+
          struct ragdoll_part *rp = &mdl->ragdoll[ mdl->ragdoll_count ++ ];
          rp->bone_id = i;
          
@@ -73,7 +76,7 @@ static void player_init_ragdoll( mdl_header *src )
 /*
  * Make the player model copy the ragdoll
  */
-static void player_model_copy_ragdoll(void)
+VG_STATIC void player_model_copy_ragdoll(void)
 {
    struct player_model *mdl = &player.mdl;
 
@@ -92,7 +95,7 @@ static void player_model_copy_ragdoll(void)
 /*
  * Make the ragdoll copy the player model
  */
-static void player_ragdoll_copy_model( v3f v )
+VG_STATIC void player_ragdoll_copy_model( v3f v )
 {
    struct player_model *mdl = &player.mdl;
 
@@ -117,7 +120,7 @@ static void player_ragdoll_copy_model( v3f v )
 /*
  * Draw rigidbody colliders for ragdoll
  */
-static void player_debug_ragdoll(void)
+VG_STATIC void player_debug_ragdoll(void)
 {
    struct player_model *mdl = &player.mdl;
 
@@ -128,7 +131,7 @@ static void player_debug_ragdoll(void)
 /*
  * Ragdoll physics step
  */
-static void player_ragdoll_iter(void)
+VG_STATIC void player_ragdoll_iter(void)
 {
    struct player_model *mdl = &player.mdl;
    rb_solver_reset();
index 8122b2ae8e41f18effe8dea39a9d5224ae8f2c93..209bed692d5bc5777fbb3db122b4410ab2a96b56 100644 (file)
--- a/render.h
+++ b/render.h
@@ -9,11 +9,11 @@
 #include "shaders/standard.h"
 #include "shaders/vblend.h"
 
-static void render_water_texture( m4x3f camera );
-static void render_water_surface( m4x4f pv, m4x3f camera );
-static void render_world( m4x4f projection, m4x3f camera );
-static void shader_link_standard_ub( GLuint shader, int texture_id );
-static void render_world_depth( m4x4f projection, m4x3f camera );
+VG_STATIC void render_water_texture( m4x3f camera );
+VG_STATIC void render_water_surface( m4x4f pv, m4x3f camera );
+VG_STATIC void render_world( m4x4f projection, m4x3f camera );
+VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id );
+VG_STATIC void render_world_depth( m4x4f projection, m4x3f camera );
 
 #ifndef RENDER_H
 #define RENDER_H
@@ -27,7 +27,7 @@ struct framebuffer
    int allocated;
 };
 
-static struct pipeline
+VG_STATIC struct pipeline
 {
    float fov;
    glmesh fsquad;
@@ -103,7 +103,7 @@ gpipeline =
 /* 
  * http://www.terathon.com/lengyel/Lengyel-Oblique.pdf 
  */
-static void plane_clip_projection( m4x4f mat, v4f plane )
+VG_STATIC void plane_clip_projection( m4x4f mat, v4f plane )
 {
    v4f c = 
    {
@@ -121,7 +121,7 @@ static void plane_clip_projection( m4x4f mat, v4f plane )
    mat[3][2] = c[3];
 }
 
-static void pipeline_projection( m4x4f mat, float nearz, float farz )
+VG_STATIC void pipeline_projection( m4x4f mat, float nearz, float farz )
 {
    m4x4_projection( mat,
          gpipeline.fov,
@@ -132,7 +132,7 @@ static void pipeline_projection( m4x4f mat, float nearz, float farz )
 /*
  * Shaders
  */
-static void shader_link_standard_ub( GLuint shader, int texture_id )
+VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id )
 {
    GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );   
    glUniformBlockBinding( shader, idx, 0 );
@@ -142,7 +142,7 @@ static void shader_link_standard_ub( GLuint shader, int texture_id )
    glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id );
 }
 
-static void render_update_lighting_ub(void)
+VG_STATIC void render_update_lighting_ub(void)
 {
    struct ub_world_lighting *winf = &gpipeline.ub_world_lighting;
    int c = 0;
@@ -178,7 +178,7 @@ static void render_update_lighting_ub(void)
  * Framebuffers
  */
 
-static void fb_use( struct framebuffer *fb )
+VG_STATIC void fb_use( struct framebuffer *fb )
 {
    if( !fb )
    {
@@ -192,7 +192,7 @@ static void fb_use( struct framebuffer *fb )
    }
 }
 
-static void fb_init( struct framebuffer *fb )
+VG_STATIC void fb_init( struct framebuffer *fb )
 {
    i32 ix = vg.window_x / fb->div,
        iy = vg.window_y / fb->div;
@@ -222,19 +222,19 @@ static void fb_init( struct framebuffer *fb )
    fb->allocated = 1;
 }
 
-static void fb_free( struct framebuffer *fb )
+VG_STATIC void fb_free( struct framebuffer *fb )
 {
    glDeleteTextures( 1, &fb->colour );
    glDeleteFramebuffers( 1, &fb->fb );
 }
 
-static void fb_bindtex( struct framebuffer *fb, int texture )
+VG_STATIC void fb_bindtex( struct framebuffer *fb, int texture )
 {
    glActiveTexture( GL_TEXTURE0 + texture );
    glBindTexture( GL_TEXTURE_2D, fb->colour );
 }
 
-static void fb_resize( struct framebuffer *fb )
+VG_STATIC void fb_resize( struct framebuffer *fb )
 {
    if( !fb->allocated )
       return;
@@ -250,7 +250,7 @@ static void fb_resize( struct framebuffer *fb )
    glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
 }
 
-static void render_fb_resize(void)
+VG_STATIC void render_fb_resize(void)
 {
    if( gpipeline.ready )
    {
@@ -261,7 +261,7 @@ static void render_fb_resize(void)
 }
 
 /* used for drawing player onto */
-static void render_init_temp_buffer(void)
+VG_STATIC void render_init_temp_buffer(void)
 {
    vg_info( "[render] Allocate temporary framebuffer\n" );
 
@@ -284,7 +284,7 @@ static void render_init_temp_buffer(void)
 
 /* used for drawing world depth from the top view, used in our water and
  * lighting calculations */
-static void render_init_depthmap_buffer(void)
+VG_STATIC void render_init_depthmap_buffer(void)
 {
    vg_info( "[render] Allocate depth map buffer\n" );
 
@@ -306,7 +306,7 @@ static void render_init_depthmap_buffer(void)
    VG_CHECK_GL_ERR();
 }
 
-static void render_init_fs_quad(void)
+VG_STATIC void render_init_fs_quad(void)
 {
    vg_info( "[render] Allocate quad\n" );
 
@@ -326,7 +326,7 @@ static void render_init_fs_quad(void)
    VG_CHECK_GL_ERR();
 }
 
-static void render_init_uniform_buffers(void)
+VG_STATIC void render_init_uniform_buffers(void)
 {
    vg_info( "[render] Allocate uniform buffer\n" );
 
@@ -341,7 +341,7 @@ static void render_init_uniform_buffers(void)
    VG_CHECK_GL_ERR();
 }
 
-static void render_init(void)
+VG_STATIC void render_init(void)
 {
    shader_blit_register();
    shader_standard_register();
@@ -361,24 +361,10 @@ static void render_init(void)
    vg_release_thread_sync();
 }
 
-static void render_free(void *_)
-{
-   glDeleteBuffers( 1, &gpipeline.ubo_world_lighting );
-
-   glDeleteVertexArrays( 1, &gpipeline.fsquad.vao );
-   glDeleteBuffers( 1, &gpipeline.fsquad.vbo );
-
-   glDeleteFramebuffers( 1, &gpipeline.fb_depthmap );
-   glDeleteTextures( 1, &gpipeline.rgb_depthmap );
-
-   glDeleteFramebuffers( 1, &gpipeline.fb_background );
-   glDeleteTextures( 1, &gpipeline.rgb_background );
-}
-
 /*
  * Utility
  */
-static void render_fsquad(void)
+VG_STATIC void render_fsquad(void)
 {
    glBindVertexArray( gpipeline.fsquad.vao );
    glDrawArrays( GL_TRIANGLES, 0, 6 );
index b9b863aad2db7c12ddbdb07ae5d15d4c95998204..94ad18142249a4f76d31f87af06efdfabc0c5572 100644 (file)
@@ -11,8 +11,8 @@
 #include "bvh.h"
 #include "scene.h"
 
-static void rb_tangent_basis( v3f n, v3f tx, v3f ty );
-static bh_system bh_system_rigidbodies;
+VG_STATIC void rb_tangent_basis( v3f n, v3f tx, v3f ty );
+VG_STATIC bh_system bh_system_rigidbodies;
 
 #ifndef RIGIDBODY_H
 #define RIGIDBODY_H
@@ -23,7 +23,7 @@ static bh_system bh_system_rigidbodies;
  * -----------------------------------------------------------------------------
  */
 
-static const float 
+VG_STATIC const float 
    k_rb_rate          = (1.0/VG_TIMESTEP_FIXED),
    k_rb_delta         = (1.0/k_rb_rate),
    k_friction         = 0.6f,
@@ -74,7 +74,7 @@ struct rigidbody
 
       struct rb_scene
       {
-         scene *pscene;
+         bh_tree *bh_scene;
       }
       scene;
    }
@@ -94,7 +94,7 @@ struct rigidbody
    m4x3f to_world, to_local;
 };
 
-static struct contact
+VG_STATIC struct contact
 {
    rigidbody *rba, *rbb;
    v3f co, n;
@@ -105,7 +105,7 @@ static struct contact
    u32 element_id;
 }
 rb_contact_buffer[256];
-static int rb_contact_count = 0;
+VG_STATIC int rb_contact_count = 0;
 
 /*
  * -----------------------------------------------------------------------------
@@ -113,13 +113,13 @@ static int rb_contact_count = 0;
  * -----------------------------------------------------------------------------
  */
 
-static float sphere_volume( float radius )
+VG_STATIC float sphere_volume( float radius )
 {
    float r3 = radius*radius*radius;
    return (4.0f/3.0f) * VG_PIf * r3;
 }
 
-static void rb_tangent_basis( v3f n, v3f tx, v3f ty )
+VG_STATIC void rb_tangent_basis( v3f n, v3f tx, v3f ty )
 {
    /* Compute tangent basis (box2d) */
    if( fabsf( n[0] ) >= 0.57735027f )
@@ -145,7 +145,7 @@ static void rb_tangent_basis( v3f n, v3f tx, v3f ty )
  * -----------------------------------------------------------------------------
  */
 
-static void rb_debug_contact( rb_ct *ct )
+VG_STATIC void rb_debug_contact( rb_ct *ct )
 {
    v3f p1;
    v3_muladds( ct->co, ct->n, 0.1f, p1 );
@@ -153,7 +153,7 @@ static void rb_debug_contact( rb_ct *ct )
    vg_line( ct->co, p1, 0xffffffff );
 }
 
-static void debug_sphere( m4x3f m, float radius, u32 colour )
+VG_STATIC void debug_sphere( m4x3f m, float radius, u32 colour )
 {
    v3f ly = { 0.0f, 0.0f, radius },
        lx = { 0.0f, radius, 0.0f },
@@ -187,7 +187,7 @@ static void debug_sphere( m4x3f m, float radius, u32 colour )
    }
 }
 
-static void debug_capsule( m4x3f m, float radius, float h, u32 colour )
+VG_STATIC void debug_capsule( m4x3f m, float radius, float h, u32 colour )
 {
    v3f ly = { 0.0f, 0.0f, radius },
        lx = { 0.0f, radius, 0.0f },
@@ -269,7 +269,7 @@ static void debug_capsule( m4x3f m, float radius, float h, u32 colour )
    }
 }
 
-static void rb_debug( rigidbody *rb, u32 colour )
+VG_STATIC void rb_debug( rigidbody *rb, u32 colour )
 {
    if( rb->type == k_rb_shape_box )
    {
@@ -303,7 +303,7 @@ static void rb_debug( rigidbody *rb, u32 colour )
 /*
  * Update world space bounding box based on local one
  */
-static void rb_update_bounds( rigidbody *rb )
+VG_STATIC void rb_update_bounds( rigidbody *rb )
 {
    box_copy( rb->bbx, rb->bbx_world );
    m4x3_transform_aabb( rb->to_world, rb->bbx_world );
@@ -312,7 +312,7 @@ static void rb_update_bounds( rigidbody *rb )
 /*
  * Commit transform to rigidbody. Updates matrices
  */
-static void rb_update_transform( rigidbody *rb )
+VG_STATIC void rb_update_transform( rigidbody *rb )
 {
    q_normalize( rb->q );
    q_m3x3( rb->q, rb->to_world );
@@ -334,7 +334,7 @@ static void rb_update_transform( rigidbody *rb )
  * Extrapolate rigidbody into a transform based on vg accumulator.
  * Useful for rendering
  */
-static void rb_extrapolate_transform( rigidbody *rb, m4x3f transform )
+VG_STATIC void rb_extrapolate_transform( rigidbody *rb, m4x3f transform )
 {
    float substep = vg_clampf( vg.accumulator / k_rb_delta, 0.0f, 1.0f );
 
@@ -367,7 +367,7 @@ static void rb_extrapolate_transform( rigidbody *rb, m4x3f transform )
 /*
  * Initialize rigidbody and calculate masses, inertia
  */
-static void rb_init( rigidbody *rb )
+VG_STATIC void rb_init( rigidbody *rb )
 {
    float volume = 1.0f;
 
@@ -397,7 +397,7 @@ static void rb_init( rigidbody *rb )
    else if( rb->type == k_rb_shape_scene )
    {
       rb->is_world = 1;
-      box_copy( rb->inf.scene.pscene->bbx, rb->bbx );
+      box_copy( rb->inf.scene.bh_scene->nodes[0].bbx, rb->bbx );
    }
 
    if( rb->is_world )
@@ -438,7 +438,7 @@ static void rb_init( rigidbody *rb )
    rb_update_transform( rb );
 }
 
-static void rb_iter( rigidbody *rb )
+VG_STATIC void rb_iter( rigidbody *rb )
 {
    v3f gravity = { 0.0f, -9.8f, 0.0f };
    v3_muladds( rb->v, gravity, k_rb_delta, rb->v );
@@ -475,7 +475,7 @@ static void rb_iter( rigidbody *rb )
  * These closest point tests were learned from Real-Time Collision Detection by 
  * Christer Ericson 
  */
-static float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2, 
+VG_STATIC float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2, 
    float *s, float *t, v3f c1, v3f c2)
 {
    v3f d1,d2,r;
@@ -552,13 +552,13 @@ static float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
    return v3_length2( v0 );
 }
 
-static void closest_point_aabb( v3f p, boxf box, v3f dest )
+VG_STATIC void closest_point_aabb( v3f p, boxf box, v3f dest )
 {
    v3_maxv( p, box[0], dest );
    v3_minv( dest, box[1], dest );
 }
 
-static void closest_point_obb( v3f p, rigidbody *rb, v3f dest )
+VG_STATIC void closest_point_obb( v3f p, rigidbody *rb, v3f dest )
 {
    v3f local;
    m4x3_mulv( rb->to_local, p, local );
@@ -566,7 +566,7 @@ static void closest_point_obb( v3f p, rigidbody *rb, v3f dest )
    m4x3_mulv( rb->to_world, local, dest );
 }
 
-static float closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
+VG_STATIC float closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
 {
    v3f v0, v1;
    v3_sub( b, a, v0 );
@@ -578,7 +578,7 @@ static float closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
    return t;
 }
 
-static void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
+VG_STATIC void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
 {
    v3f ab, ac, ap;
    float d1, d2;
@@ -667,7 +667,7 @@ static void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
    v3_muladds( dest, ac, w, dest );
 }
 
-static void closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
+VG_STATIC void closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
 {
    v3f ab, ac, ap;
    float d1, d2;
@@ -759,7 +759,7 @@ static void closest_on_triangle_1( v3f p, v3f tri[3], v3f dest )
 /* 
  * Project AABB, and triangle interval onto axis to check if they overlap
  */
-static int rb_box_triangle_interval( v3f extent, v3f axis, v3f tri[3] )
+VG_STATIC int rb_box_triangle_interval( v3f extent, v3f axis, v3f tri[3] )
 {
    float 
 
@@ -780,7 +780,7 @@ static int rb_box_triangle_interval( v3f extent, v3f axis, v3f tri[3] )
 /*
  * Seperating axis test box vs triangle
  */
-static int rb_box_triangle_sat( rigidbody *rba, v3f tri_src[3] )
+VG_STATIC int rb_box_triangle_sat( rigidbody *rba, v3f tri_src[3] )
 {
    v3f tri[3];
 
@@ -870,7 +870,7 @@ struct capsule_manifold
  * Expand a line manifold with a new pair. t value is the time along segment
  * on the oriented object which created this pair.
  */
-static void rb_capsule_manifold( v3f pa, v3f pb, float t, float r, 
+VG_STATIC void rb_capsule_manifold( v3f pa, v3f pb, float t, float r, 
                                  capsule_manifold *manifold )
 {
    v3f delta;
@@ -894,13 +894,13 @@ static void rb_capsule_manifold( v3f pa, v3f pb, float t, float r,
    }
 }
 
-static void rb_capsule_manifold_init( capsule_manifold *manifold )
+VG_STATIC void rb_capsule_manifold_init( capsule_manifold *manifold )
 {
    manifold->t0 =  INFINITY;
    manifold->t1 = -INFINITY;
 }
 
-static int rb_capsule_manifold_done( rigidbody *rba, rigidbody *rbb, 
+VG_STATIC int rb_capsule_manifold_done( rigidbody *rba, rigidbody *rbb, 
                                      capsule_manifold *manifold, rb_ct *buf )
 {
    float h = rba->inf.capsule.height,
@@ -959,7 +959,7 @@ static int rb_capsule_manifold_done( rigidbody *rba, rigidbody *rbb,
    return count;
 }
 
-static int rb_capsule_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_capsule_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    float h = rba->inf.capsule.height,
         ra = rba->inf.capsule.radius,
@@ -999,7 +999,7 @@ static int rb_capsule_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return 0;
 }
 
-static int rb_capsule_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_capsule_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    float ha = rba->inf.capsule.height,
          hb = rbb->inf.capsule.height,
@@ -1037,7 +1037,7 @@ static int rb_capsule_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 /*
  * Generates up to two contacts; optimised for the most stable manifold
  */
-static int rb_capsule_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_capsule_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    float h = rba->inf.capsule.height,
          r = rba->inf.capsule.radius;
@@ -1161,7 +1161,7 @@ static int rb_capsule_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return rb_capsule_manifold_done( rba, rbb, &manifold, buf );
 }
 
-static int rb_sphere_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    v3f co, delta;
 
@@ -1218,7 +1218,7 @@ static int rb_sphere_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return 0;
 }
 
-static int rb_sphere_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    v3f delta;
    v3_sub( rba->co, rbb->co, delta );
@@ -1247,7 +1247,7 @@ static int rb_sphere_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return 0;
 }
 
-static int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb, 
+VG_STATIC int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb, 
                                   v3f tri[3], rb_ct *buf )
 {
    v3f delta, co;
@@ -1284,22 +1284,22 @@ static int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb,
    return 0;
 }
 
-static int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
-   scene *sc = rbb->inf.scene.pscene;
+   scene *sc = rbb->inf.scene.bh_scene->user;
    
    u32 geo[128];
    v3f tri[3];
-   int len = bh_select( &sc->bhtris, rba->bbx_world, geo, 128 );
+   int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
 
    int count = 0;
 
    for( int i=0; i<len; i++ )
    {
-      u32 *ptri = &sc->indices[ geo[i]*3 ];
+      u32 *ptri = &sc->arrindices[ geo[i]*3 ];
 
       for( int j=0; j<3; j++ )
-         v3_copy( sc->verts[ptri[j]].co, tri[j] );
+         v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
 
       vg_line(tri[0],tri[1],0xff00ff00 );
       vg_line(tri[1],tri[2],0xff00ff00 );
@@ -1318,22 +1318,22 @@ static int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return count;
 }
 
-static int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
-   scene *sc = rbb->inf.scene.pscene;
+   scene *sc = rbb->inf.scene.bh_scene->user;
    
    u32 geo[128];
    v3f tri[3];
-   int len = bh_select( &sc->bhtris, rba->bbx_world, geo, 128 );
+   int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
 
    int count = 0;
 
    for( int i=0; i<len; i++ )
    {
-      u32 *ptri = &sc->indices[ geo[i]*3 ];
+      u32 *ptri = &sc->arrindices[ geo[i]*3 ];
 
       for( int j=0; j<3; j++ )
-         v3_copy( sc->verts[ptri[j]].co, tri[j] );
+         v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
 
       if( rb_box_triangle_sat( rba, tri ) )
       {
@@ -1458,7 +1458,7 @@ static int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return count;
 }
 
-static int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    vg_error( "Collision type is unimplemented between types %d and %d\n",
              rba->type, rbb->type );
@@ -1466,27 +1466,27 @@ static int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
    return 0;
 }
 
-static int rb_sphere_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_sphere_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    return rb_capsule_sphere( rbb, rba, buf );
 }
 
-static int rb_box_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_box_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    return rb_capsule_box( rbb, rba, buf );
 }
 
-static int rb_box_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_box_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    return rb_sphere_box( rbb, rba, buf );
 }
 
-static int rb_scene_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+VG_STATIC int rb_scene_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
 {
    return rb_box_scene( rbb, rba, buf );
 }
 
-static int (*rb_jump_table[4][4])( rigidbody *a, rigidbody *b, rb_ct *buf ) = 
+VG_STATIC int (*rb_jump_table[4][4])( rigidbody *a, rigidbody *b, rb_ct *buf ) = 
 {
     /* box */        /* Sphere */       /* Capsule */       /* Mesh */
   { RB_MATRIX_ERROR, rb_box_sphere,     rb_box_capsule,     rb_box_scene    },
@@ -1495,7 +1495,7 @@ static int (*rb_jump_table[4][4])( rigidbody *a, rigidbody *b, rb_ct *buf ) =
   { rb_scene_box,    RB_MATRIX_ERROR,   RB_MATRIX_ERROR,    RB_MATRIX_ERROR }
 };
 
-static int rb_collide( rigidbody *rba, rigidbody *rbb )
+VG_STATIC int rb_collide( rigidbody *rba, rigidbody *rbb )
 {
    int (*collider_jump)(rigidbody *rba, rigidbody *rbb, rb_ct *buf ) 
       = rb_jump_table[rba->type][rbb->type];
@@ -1530,12 +1530,12 @@ static int rb_collide( rigidbody *rba, rigidbody *rbb )
  * -----------------------------------------------------------------------------
  */
 
-static void rb_solver_reset(void)
+VG_STATIC void rb_solver_reset(void)
 {
    rb_contact_count = 0;
 }
 
-static rb_ct *rb_global_ct(void)
+VG_STATIC rb_ct *rb_global_ct(void)
 {
    return rb_contact_buffer + rb_contact_count;
 }
@@ -1543,7 +1543,7 @@ static rb_ct *rb_global_ct(void)
 /*
  * Initializing things like tangent vectors
  */
-static void rb_presolve_contacts( rb_ct *buffer, int len )
+VG_STATIC void rb_presolve_contacts( rb_ct *buffer, int len )
 {
    for( int i=0; i<len; i++ )
    {
@@ -1592,7 +1592,7 @@ static void rb_presolve_contacts( rb_ct *buffer, int len )
 /*
  * Creates relative contact velocity vector, and offsets between each body
  */
-static void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
+VG_STATIC void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
 {
    rigidbody *rba = ct->rba,
              *rbb = ct->rbb;
@@ -1612,7 +1612,7 @@ static void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
 /*
  * Apply impulse to object
  */
-static void rb_linear_impulse( rigidbody *rb, v3f delta, v3f impulse )
+VG_STATIC void rb_linear_impulse( rigidbody *rb, v3f delta, v3f impulse )
 {
    /* linear */
    v3_muladds( rb->v, impulse,  rb->inv_mass, rb->v );
@@ -1628,7 +1628,7 @@ static void rb_linear_impulse( rigidbody *rb, v3f delta, v3f impulse )
 /*
  * One iteration to solve the contact constraint
  */
-static void rb_solve_contacts( rb_ct *buf, int len )
+VG_STATIC void rb_solve_contacts( rb_ct *buf, int len )
 {
    for( int i=0; i<len; i++ )
    {
@@ -1681,7 +1681,7 @@ static void rb_solve_contacts( rb_ct *buf, int len )
  * -----------------------------------------------------------------------------
  */
 
-static void draw_angle_limit( v3f c, v3f major, v3f minor, 
+VG_STATIC void draw_angle_limit( v3f c, v3f major, v3f minor, 
                               float amin, float amax, float measured,
                               u32 colour )
 {
@@ -1717,7 +1717,7 @@ static void draw_angle_limit( v3f c, v3f major, v3f minor,
    vg_line( c, p2, colour );
 }
 
-static void rb_debug_constraint_limits( rigidbody *ra, rigidbody *rb, v3f lca,
+VG_STATIC void rb_debug_constraint_limits( rigidbody *ra, rigidbody *rb, v3f lca,
                                         v3f limits[2] )
 {
    v3f ax, ay, az, bx, by, bz;
@@ -1749,7 +1749,7 @@ static void rb_debug_constraint_limits( rigidbody *ra, rigidbody *rb, v3f lca,
    draw_angle_limit( c, ax, ay, limits[0][2], limits[1][2], r2, 0xffff0000 );
 }
 
-static void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d )
+VG_STATIC void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d )
 {
    if( d != 0.0f )
    {
@@ -1770,7 +1770,7 @@ static void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d )
    }
 }
 
-static void rb_constraint_limits( rigidbody *ra, v3f lca, 
+VG_STATIC void rb_constraint_limits( rigidbody *ra, v3f lca, 
                                   rigidbody *rb, v3f lcb, v3f limits[2] )
 {
    v3f ax, ay, az, bx, by, bz;
@@ -1814,7 +1814,7 @@ static void rb_constraint_limits( rigidbody *ra, v3f lca,
    rb_limit_cure( ra, rb, az, dz );
 }
 
-static void rb_debug_constraint_position( rigidbody *ra, v3f lca,
+VG_STATIC void rb_debug_constraint_position( rigidbody *ra, v3f lca,
                                           rigidbody *rb, v3f lcb )
 {
    v3f wca, wcb;
@@ -1829,7 +1829,7 @@ static void rb_debug_constraint_position( rigidbody *ra, v3f lca,
    vg_line( p0, p1, 0xffffff00 );
 }
 
-static void rb_constraint_position( rigidbody *ra, v3f lca,
+VG_STATIC void rb_constraint_position( rigidbody *ra, v3f lca,
                                     rigidbody *rb, v3f lcb )
 {
    /* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */
@@ -1893,7 +1893,7 @@ static void rb_constraint_position( rigidbody *ra, v3f lca,
  * Effectors
  */
 
-static void rb_effect_simple_bouyency( rigidbody *ra, v4f plane, 
+VG_STATIC void rb_effect_simple_bouyency( rigidbody *ra, v4f plane, 
                                        float amt, float drag )
 {
    /* float */
@@ -1908,24 +1908,24 @@ static void rb_effect_simple_bouyency( rigidbody *ra, v4f plane,
 
 /*
  * -----------------------------------------------------------------------------
- * BVH implementation, this is ONLY for static rigidbodies, its to slow for
+ * BVH implementation, this is ONLY for VG_STATIC rigidbodies, its to slow for
  * realtime use.
  * -----------------------------------------------------------------------------
  */
 
-static void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
+VG_STATIC void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
 {
    rigidbody *rb = &((rigidbody *)user)[ item_index ];
    box_concat( bound, rb->bbx_world );
 }
 
-static float rb_bh_centroid( void *user, u32 item_index, int axis )
+VG_STATIC float rb_bh_centroid( void *user, u32 item_index, int axis )
 {
    rigidbody *rb = &((rigidbody *)user)[ item_index ];
    return (rb->bbx_world[axis][0] + rb->bbx_world[1][axis]) * 0.5f;
 }
 
-static void rb_bh_swap( void *user, u32 ia, u32 ib )
+VG_STATIC void rb_bh_swap( void *user, u32 ia, u32 ib )
 {
    rigidbody temp, *rba, *rbb;
    rba = &((rigidbody *)user)[ ia ];
@@ -1936,13 +1936,13 @@ static void rb_bh_swap( void *user, u32 ia, u32 ib )
    *rbb = temp;
 }
 
-static void rb_bh_debug( void *user, u32 item_index )
+VG_STATIC void rb_bh_debug( void *user, u32 item_index )
 {
    rigidbody *rb = &((rigidbody *)user)[ item_index ];
    rb_debug( rb, 0xff00ffff );
 }
 
-static bh_system bh_system_rigidbodies =
+VG_STATIC bh_system bh_system_rigidbodies =
 {
    .expand_bound = rb_bh_expand_bound,
    .item_centroid = rb_bh_centroid,
diff --git a/scene.h b/scene.h
index a4f6bd1f005e02cfcc221a7d426df3344eebd6bb..51ce10315c38fdcb47fe84f49eaec103e8445266 100644 (file)
--- a/scene.h
+++ b/scene.h
@@ -9,70 +9,89 @@ typedef struct scene scene;
 
 struct scene
 {
-   glmesh mesh;
+   mdl_vert *arrvertices;
+   u32 *arrindices;
 
-   mdl_vert *verts;
-   u32 *indices;
-   
-   bh_tree bhtris;
-   u32 vertex_count,
-       indice_count,
-       vertex_cap,
-       indice_cap;
+   u32 vertex_count, indice_count,
+       max_vertices, max_indices;
 
    boxf bbx;
-
-   u32 shadower_count,
-       shadower_cap;
-
    mdl_submesh submesh;
 };
 
-static void scene_init( scene *pscene )
+/* Initialize a scene description with bounded buffers */
+VG_STATIC scene *scene_init( void *lin_alloc, u32 max_verts, u32 max_indices )
 {
-   pscene->verts = NULL;
-   pscene->indices = NULL;
+   u32 vertex_length = max_verts   * sizeof(mdl_vert),
+       index_length  = max_indices * sizeof(u32),
+       tot_size = sizeof(scene) + vertex_length + index_length;
+
+   scene *pscene = vg_linear_alloc( lin_alloc, tot_size );
+
+   pscene->arrvertices = (mdl_vert *)(pscene+1);
+   pscene->arrindices  = (u32 *)( pscene->arrvertices + max_verts );
+
    pscene->vertex_count = 0;
    pscene->indice_count = 0;
-   pscene->shadower_count = 0;
-   pscene->shadower_cap = 0;
+   pscene->max_vertices = max_verts;
+   pscene->max_indices  = max_indices;
+
    pscene->submesh.indice_start = 0;
    pscene->submesh.indice_count = 0;
 
    v3_fill( pscene->bbx[0],  999999.9f );
    v3_fill( pscene->bbx[1], -999999.9f );
+
+   return pscene;
 }
 
 /* 
  * Append a model into the scene with a given transform
  */
-static void scene_add_submesh( scene *pscene, mdl_header *mdl, 
-                               mdl_submesh *sm, m4x3f transform )
+VG_STATIC void scene_add_submesh( scene *pscene, mdl_context *mdl, 
+                                  mdl_submesh *sm, m4x3f transform )
 {
-   pscene->verts  = buffer_reserve( pscene->verts, pscene->vertex_count, 
-                    &pscene->vertex_cap, sm->vertex_count, sizeof(mdl_vert) );
+   if( pscene->vertex_count + sm->vertex_count > pscene->max_vertices )
+   {
+      vg_error( "%u(current) + %u > %u\n", pscene->vertex_count,
+                                           sm->vertex_count,
+                                           pscene->max_vertices );
 
-   pscene->indices = buffer_reserve( pscene->indices, pscene->indice_count,
-                     &pscene->indice_cap, sm->indice_count, sizeof(u32) );
+      vg_warn( "%p ... %p\n", pscene, sm );
+      vg_fatal_exit_loop( "Scene vertex buffer overflow" );
+   }
 
-   m3x3f normal_matrix;
-   m3x3_copy( transform, normal_matrix );
-   v3_normalize( normal_matrix[0] );
-   v3_normalize( normal_matrix[1] );
-   v3_normalize( normal_matrix[2] );
+   if( pscene->indice_count + sm->indice_count > pscene->max_indices )
+   {
+      vg_error( "%u(current) + %u > %u\n", pscene->indice_count,
+                                           sm->indice_count,
+                                           pscene->max_indices );
+      vg_warn( "%p ... %p\n", pscene, sm );
+
+      vg_fatal_exit_loop( "Scene index buffer overflow" );
+   }
+
+   mdl_vert *src_verts =  mdl_submesh_vertices( mdl, sm ),
+            *dst_verts = &pscene->arrvertices[ pscene->vertex_count ];
+
+   u32 *src_indices    =  mdl_submesh_indices( mdl, sm ),
+       *dst_indices    = &pscene->arrindices[ pscene->indice_count ];
    
    /* Transform and place vertices */
-   mdl_vert *src_verts = mdl_submesh_vertices( mdl, sm );
-   u32 *src_indices    = mdl_submesh_indices( mdl, sm );
-   
    boxf bbxnew;
    box_copy( sm->bbx, bbxnew );
    m4x3_transform_aabb( transform, bbxnew );
    box_concat( pscene->bbx, bbxnew );
+
+   m3x3f normal_matrix;
+   m3x3_copy( transform, normal_matrix );
+   v3_normalize( normal_matrix[0] );
+   v3_normalize( normal_matrix[1] );
+   v3_normalize( normal_matrix[2] );
    
    for( u32 i=0; i<sm->vertex_count; i++ )
    {
-      mdl_vert *pvert = &pscene->verts[ pscene->vertex_count+i ],
+      mdl_vert *pvert = &dst_verts[ i ],
                *src = &src_verts[ i ];
 
       m4x3_mulv( transform, src->co, pvert->co );
@@ -87,23 +106,24 @@ static void scene_add_submesh( scene *pscene, mdl_header *mdl,
 
    for( u32 i=0; i<sm->indice_count; i++ )
    {
-      u32 *pidx = &pscene->indices[ pscene->indice_count+i ];
-      *pidx = src_indices[i] + pscene->vertex_count;
+      dst_indices[i] = src_indices[i] + pscene->vertex_count;
    }
 
    pscene->vertex_count += sm->vertex_count;
    pscene->indice_count += sm->indice_count;
+
 }
 
 /*
  * One by one adders for simplified access (mostly procedural stuff)
  */
-static void scene_push_tri( scene *pscene, u32 tri[3] )
+VG_STATIC void scene_push_tri( scene *pscene, u32 tri[3] )
 {
-   pscene->indices = buffer_reserve( pscene->indices, pscene->indice_count,
-                                    &pscene->indice_cap, 3, sizeof(u32) );
+   if( pscene->indice_count + 3 > pscene->max_indices )
+      vg_fatal_exit_loop( "Scene vertex buffer overflow" );
+
+   u32 *dst = &pscene->arrindices[ pscene->indice_count ];
 
-   u32 *dst = &pscene->indices[pscene->indice_count];
    dst[0] = tri[0];
    dst[1] = tri[1];
    dst[2] = tri[2];
@@ -111,14 +131,18 @@ static void scene_push_tri( scene *pscene, u32 tri[3] )
    pscene->indice_count += 3;
 }
 
-static void scene_push_vert( scene *pscene, mdl_vert *v )
+VG_STATIC void scene_push_vert( scene *pscene, mdl_vert *v )
 {
-   pscene->verts = buffer_reserve( pscene->verts, pscene->vertex_count, 
-                                  &pscene->vertex_cap, 1, sizeof(mdl_vert) );
-   pscene->verts[pscene->vertex_count ++] = *v;
+   if( pscene->vertex_count + 1 > pscene->max_vertices )
+      vg_fatal_exit_loop( "Scene vertex buffer overflow" );
+
+   mdl_vert *dst = &pscene->arrvertices[ pscene->vertex_count ];
+   *dst = *v;
+
+   pscene->vertex_count ++;
 }
 
-static void scene_copy_slice( scene *pscene, mdl_submesh *sm )
+VG_STATIC void scene_copy_slice( scene *pscene, mdl_submesh *sm )
 {
    sm->indice_start = pscene->submesh.indice_start;
    sm->indice_count = pscene->indice_count - sm->indice_start;
@@ -130,79 +154,99 @@ static void scene_copy_slice( scene *pscene, mdl_submesh *sm )
    pscene->submesh.vertex_start = pscene->vertex_count;
 }
 
-static void scene_fix( scene *pscene )
+/* finalization: tightly pack data */
+__attribute__((warn_unused_result))
+VG_STATIC scene *scene_fix( void *lin_alloc, scene *pscene )
 {
-   buffer_fix( pscene->verts, pscene->vertex_count, 
-         &pscene->vertex_cap, sizeof( mdl_vert ));
+   u32 vertex_length = pscene->vertex_count * sizeof(mdl_vert),
+       index_length  = pscene->indice_count * sizeof(u32),
+       tot_size = sizeof(scene) + vertex_length + index_length;
 
-   buffer_fix( pscene->indices, pscene->indice_count, 
-         &pscene->indice_cap, sizeof( mdl_vert ));
-}
+   scene    *src_scene   = pscene;
+   mdl_vert *src_verts   = pscene->arrvertices;
+   u32      *src_indices = pscene->arrindices;
 
-static void scene_upload( scene *pscene )
-{
-   mesh_upload( &pscene->mesh,
-                pscene->verts, pscene->vertex_count,
-                pscene->indices, pscene->indice_count );
+   scene *dst_scene = vg_linear_resize( lin_alloc, pscene, tot_size );
+   memcpy( dst_scene, src_scene, sizeof(scene) );
 
-   vg_info( "Scene upload\n" );
-   vg_info( "   indices:%u\n", pscene->indice_count );
-   vg_info( "   verts:%u\n", pscene->vertex_count );
-}
+   void *dst_verts   = dst_scene+1,
+        *dst_indices = dst_verts + vertex_length;
 
-static void scene_bind( scene *pscene )
-{
-   mesh_bind( &pscene->mesh );
-}
+   memcpy( dst_verts, src_verts, vertex_length );
+   memcpy( dst_indices, src_indices, index_length );
 
-static void scene_draw( scene *pscene )
-{
-   mesh_drawn( 0, pscene->indice_count );
+   dst_scene->arrvertices = dst_verts;
+   dst_scene->arrindices  = dst_indices;
+   dst_scene->max_vertices = pscene->vertex_count;
+   dst_scene->max_indices  = pscene->indice_count;
+
+   return dst_scene;
 }
 
-static void scene_free_offline_buffers( scene *pscene )
+#if 0
+/* finalization: delete any offline buffers and reduce size */
+__attribute__((warn_unused_result))
+VG_STATIC scene *scene_free_offline_buffers( void *lin_alloc, scene *pscene )
 {
-   vg_free( pscene->verts );
-   vg_free( pscene->indices );
+   u32 tot_size = sizeof(scene);
+
+   scene    *src_scene   = pscene;
+   mdl_vert *src_verts   = pscene->arrvertices;
+   u32      *src_indices = pscene->arrindices;
+
+   scene *dst_scene = vg_linear_resize( lin_alloc, pscene, tot_size );
+   memcpy( dst_scene, src_scene, sizeof(scene) );
+
+   dst_scene->arrindices = NULL;
+   dst_scene->arrvertices = NULL;
+
+   return dst_scene;
 }
+#endif
 
-static void scene_free( scene *pscene )
+VG_STATIC void scene_upload( scene *pscene, glmesh *mesh )
 {
-   scene_free_offline_buffers( pscene );
+   mesh_upload( mesh,
+                pscene->arrvertices, pscene->vertex_count,
+                pscene->arrindices,  pscene->indice_count );
+
+   vg_info( "Scene upload\n" );
+   vg_info( "   indices:%u\n", pscene->indice_count );
+   vg_info( "   verts:%u\n", pscene->vertex_count );
 }
 
 /*
  * BVH implementation
  */
 
-static void scene_bh_expand_bound( void *user, boxf bound, u32 item_index )
+VG_STATIC void scene_bh_expand_bound( void *user, boxf bound, u32 item_index )
 {
    scene *s = user;
-   mdl_vert *pa = &s->verts[ s->indices[item_index*3+0] ],
-            *pb = &s->verts[ s->indices[item_index*3+1] ],
-            *pc = &s->verts[ s->indices[item_index*3+2] ];
+   mdl_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ],
+            *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ],
+            *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ];
    
   box_addpt( bound, pa->co );
   box_addpt( bound, pb->co );
   box_addpt( bound, pc->co );
 }
 
-static float scene_bh_centroid( void *user, u32 item_index, int axis )
+VG_STATIC float scene_bh_centroid( void *user, u32 item_index, int axis )
 {
    scene *s = user;
-   mdl_vert *pa = &s->verts[ s->indices[item_index*3+0] ],
-            *pb = &s->verts[ s->indices[item_index*3+1] ],
-            *pc = &s->verts[ s->indices[item_index*3+2] ];
+   mdl_vert *pa = &s->arrvertices[ s->arrindices[item_index*3+0] ],
+            *pb = &s->arrvertices[ s->arrindices[item_index*3+1] ],
+            *pc = &s->arrvertices[ s->arrindices[item_index*3+2] ];
 
    return (pa->co[axis] + pb->co[axis] + pc->co[axis]) * (1.0f/3.0f);
 }
 
-static void scene_bh_swap( void *user, u32 ia, u32 ib )
+VG_STATIC void scene_bh_swap( void *user, u32 ia, u32 ib )
 {
    scene *s = user;
 
-   u32 *ti = &s->indices[ia*3];
-   u32 *tj = &s->indices[ib*3];
+   u32 *ti = &s->arrindices[ia*3];
+   u32 *tj = &s->arrindices[ib*3];
 
    u32 temp[3];
    temp[0] = ti[0];
@@ -218,28 +262,29 @@ static void scene_bh_swap( void *user, u32 ia, u32 ib )
    tj[2] = temp[2];
 }
 
-static void scene_bh_debug( void *user, u32 item_index )
+VG_STATIC void scene_bh_debug( void *user, u32 item_index )
 {
    scene *s = user;
    u32 idx = item_index*3;
-   mdl_vert *pa = &s->verts[ s->indices[ idx+0 ] ],
-            *pb = &s->verts[ s->indices[ idx+1 ] ],
-            *pc = &s->verts[ s->indices[ idx+2 ] ];
+   mdl_vert *pa = &s->arrvertices[ s->arrindices[ idx+0 ] ],
+            *pb = &s->arrvertices[ s->arrindices[ idx+1 ] ],
+            *pc = &s->arrvertices[ s->arrindices[ idx+2 ] ];
 
    vg_line( pa->co, pb->co, 0xff0000ff );
    vg_line( pb->co, pc->co, 0xff0000ff );
    vg_line( pc->co, pa->co, 0xff0000ff );
 }
 
-static int scene_bh_ray( void *user, u32 index, v3f co, v3f dir, ray_hit *hit )
+VG_STATIC int scene_bh_ray( void *user, u32 index, v3f co, 
+                            v3f dir, ray_hit *hit )
 {
    scene *s = user;
    v3f positions[3];
    
-   u32 *tri = &s->indices[ index*3 ];
+   u32 *tri = &s->arrindices[ index*3 ];
 
    for( int i=0; i<3; i++ )
-      v3_copy( s->verts[tri[i]].co, positions[i] );
+      v3_copy( s->arrvertices[tri[i]].co, positions[i] );
    
    float t;
    if(ray_tri( positions, co, dir, &t ))
@@ -255,7 +300,7 @@ static int scene_bh_ray( void *user, u32 index, v3f co, v3f dir, ray_hit *hit )
    return 0;
 }
 
-static bh_system bh_system_scene = 
+VG_STATIC bh_system bh_system_scene = 
 {
    .expand_bound = scene_bh_expand_bound,
    .item_centroid = scene_bh_centroid,
@@ -267,17 +312,18 @@ static bh_system bh_system_scene =
 /*
  * An extra step is added onto the end to calculate the hit normal
  */
-static int scene_raycast( scene *s, v3f co, v3f dir, ray_hit *hit )
+VG_STATIC int scene_raycast( scene *s, bh_tree *bh, 
+                             v3f co, v3f dir, ray_hit *hit )
 {
-   int count = bh_ray( &s->bhtris, 0, co, dir, hit );
+   int count = bh_ray( bh, co, dir, hit );
 
    if( count )
    {
       v3f v0, v1;
       
-      float *pa = s->verts[hit->tri[0]].co,
-            *pb = s->verts[hit->tri[1]].co,
-            *pc = s->verts[hit->tri[2]].co;
+      float *pa = s->arrvertices[hit->tri[0]].co,
+            *pb = s->arrvertices[hit->tri[1]].co,
+            *pc = s->arrvertices[hit->tri[2]].co;
 
       v3_sub( pa, pb, v0 );
       v3_sub( pc, pb, v1 );
@@ -289,10 +335,10 @@ static int scene_raycast( scene *s, v3f co, v3f dir, ray_hit *hit )
    return count;
 }
 
-static void scene_bh_create( scene *s )
+VG_STATIC bh_tree *scene_bh_create( void *lin_alloc, scene *s )
 {
    u32 triangle_count = s->indice_count / 3;
-   bh_create( &s->bhtris, &bh_system_scene, s, triangle_count );
+   return bh_create( lin_alloc, &bh_system_scene, s, triangle_count );
 }
 
 #endif
index d5d5d91f10291c708a6faa28c75ae27573a36f49..dfe8be870a25ad55f0ac084c7d92709391b0b3c3 100644 (file)
--- a/server.c
+++ b/server.c
@@ -36,6 +36,7 @@ static void  *hSteamHTTP,
 static u8 steam_symetric_key[ k_nSteamEncryptedAppTicketSymmetricKeyLen ];
 static HSteamNetPollGroup client_pollgroup;
 
+#if 0
 static void recieve_http( void *callresult, void *context )
 {
    HTTPRequestCompleted_t *result = callresult;
@@ -55,6 +56,7 @@ static void recieve_http( void *callresult, void *context )
    vg_free( buffer );
    SteamAPI_ISteamHTTP_ReleaseHTTPRequest( hSteamHTTP, result->m_hRequest );
 }
+#endif
 
 static u64_steamid get_connection_authsteamid( SteamNetworkingMessage_t *msg )
 {
@@ -335,7 +337,9 @@ int main( int argc, char *argv[] )
    
    /* TODO: Options to override, ammend, remove etc */
 
+   vg_prealloc_quota( 80*1024*1024 );
    highscores_init( 250000, 10000 );
+   
    if( !highscores_read() )
       highscores_create_db();
 
@@ -424,7 +428,6 @@ int main( int argc, char *argv[] )
    }
    
    highscores_serialize_all();
-   highscores_free();
    
    SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( hSteamNetworkingSockets,
          client_pollgroup );
index 78a0b5604d5fd0facb8b903ece0631d5fcf35a15..9f715efa0e8391127df9169051b984171024d59c 100644 (file)
@@ -24,9 +24,22 @@ struct skeleton
       int collider;
       boxf hitbox;
 
-      char name[16];
+      const char *name;
    }
    *bones;
+   u32 bone_count;
+
+   struct skeleton_anim
+   {
+      const char *name;
+      u32 length;
+
+      float rate;
+      mdl_keyframe *anim_data;
+   }
+   *anims;
+   u32 anim_count;
+
    m4x3f *final_mtx;
 
    struct skeleton_ik
@@ -35,28 +48,16 @@ struct skeleton
       m3x3f ia, ib;
    }
    *ik;
+   u32 ik_count;
 
-   struct skeleton_anim
-   {
-      float rate;
-      u32 length;
-      struct mdl_keyframe *anim_data;
-      char name[32];
-   }
-   *anims;
-
-   u32 bone_count,
-       ik_count,
+   u32 
        collider_count,
-       anim_count,
-       bindable_count;  /* TODO: try to place IK last in the rig from export
-                                 so that we dont always upload transforms for
-                                 useless cpu IK bones. */
+       bindable_count;
 };
 
-static u32 skeleton_bone_id( struct skeleton *skele, const char *name )
+VG_STATIC u32 skeleton_bone_id( struct skeleton *skele, const char *name )
 {
-   for( u32 i=0; i<skele->bone_count; i++ )
+   for( u32 i=1; i<skele->bone_count; i++ )
    {
       if( !strcmp( skele->bones[i].name, name ))
          return i;
@@ -65,7 +66,7 @@ static u32 skeleton_bone_id( struct skeleton *skele, const char *name )
    return 0;
 }
 
-static void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num )
+VG_STATIC void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num )
 {
    for( int i=0; i<num; i++ )
       kfb[i] = kfa[i];
@@ -74,7 +75,7 @@ static void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num )
 /*
  * Lerp between two sets of keyframes and store in dest. Rotations use Nlerp.
  */
-static void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
+VG_STATIC void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
                                 mdl_keyframe *kfd, int count )
 {
    if( t <= 0.01f )
@@ -96,7 +97,7 @@ static void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
    }
 }
 
-static void skeleton_lerp_pose( struct skeleton *skele,
+VG_STATIC void skeleton_lerp_pose( struct skeleton *skele,
                                 mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
                                 mdl_keyframe *kfd )
 {
@@ -107,7 +108,7 @@ static void skeleton_lerp_pose( struct skeleton *skele,
  * Sample animation between 2 closest frames using time value. Output is a
  * keyframe buffer that is allocated with an appropriate size
  */
-static void skeleton_sample_anim( struct skeleton *skele,
+VG_STATIC void skeleton_sample_anim( struct skeleton *skele,
                                   struct skeleton_anim *anim,
                                   float time,
                                   mdl_keyframe *output )
@@ -125,7 +126,7 @@ static void skeleton_sample_anim( struct skeleton *skele,
    skeleton_lerp_pose( skele, base, nbase, t, output );
 }
 
-static int skeleton_sample_anim_clamped( struct skeleton *skele,
+VG_STATIC int skeleton_sample_anim_clamped( struct skeleton *skele,
                                          struct skeleton_anim *anim,
                                          float time,
                                          mdl_keyframe *output )
@@ -147,7 +148,7 @@ typedef enum anim_apply
 }
 anim_apply;
 
-static int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type )
+VG_STATIC int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type )
 {
    struct skeleton_bone *sb = &skele->bones[ id ],
                         *sp = &skele->bones[ sb->parent ];
@@ -179,7 +180,7 @@ static int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type )
 /*
  * Apply block of keyframes to skeletons final pose
  */
-static void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose,
+VG_STATIC void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose,
                                  anim_apply passtype )
 {
    m4x3_identity( skele->final_mtx[0] );
@@ -217,7 +218,7 @@ static void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose,
  * creates the reference inverse matrix for an IK bone, as it has an initial 
  * intrisic rotation based on the direction that the IK is setup..
  */
-static void skeleton_inverse_for_ik( struct skeleton *skele,
+VG_STATIC void skeleton_inverse_for_ik( struct skeleton *skele,
                                      v3f ivaxis,
                                      u32 id, m3x3f inverse )
 {
@@ -231,7 +232,7 @@ static void skeleton_inverse_for_ik( struct skeleton *skele,
 /*
  * Creates inverse rotation matrices which the IK system uses.
  */
-static void skeleton_create_inverses( struct skeleton *skele )
+VG_STATIC void skeleton_create_inverses( struct skeleton *skele )
 {
    /* IK: inverse 'plane-bone space' axis '(^axis,^bone,...)[base] */
    for( int i=0; i<skele->ik_count; i++ )
@@ -241,7 +242,7 @@ static void skeleton_create_inverses( struct skeleton *skele )
       m4x3f inverse;
       v3f iv0, iv1, ivaxis;
       v3_sub( skele->bones[ik->target].co, skele->bones[ik->lower].co, iv0 );
-      v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 );
+      v3_sub( skele->bones[ik->pole].co,   skele->bones[ik->lower].co, iv1 );
       v3_cross( iv0, iv1, ivaxis );
       v3_normalize( ivaxis );
 
@@ -253,7 +254,7 @@ static void skeleton_create_inverses( struct skeleton *skele )
 /*
  * Apply a model matrix to all bones, should be done last
  */
-static void skeleton_apply_transform( struct skeleton *skele, m4x3f transform )
+VG_STATIC void skeleton_apply_transform( struct skeleton *skele, m4x3f transform )
 {
    for( int i=0; i<skele->bone_count; i++ )
    {
@@ -266,7 +267,7 @@ static void skeleton_apply_transform( struct skeleton *skele, m4x3f transform )
  * Apply an inverse matrix to all bones which maps vertices from bind space into
  * bone relative positions
  */
-static void skeleton_apply_inverses( struct skeleton *skele )
+VG_STATIC void skeleton_apply_inverses( struct skeleton *skele )
 {
    for( int i=0; i<skele->bone_count; i++ )
    {
@@ -282,7 +283,7 @@ static void skeleton_apply_inverses( struct skeleton *skele )
 /*
  * Apply all IK modifiers (2 bone ik reference from blender is supported)
  */
-static void skeleton_apply_ik_pass( struct skeleton *skele )
+VG_STATIC void skeleton_apply_ik_pass( struct skeleton *skele )
 {
    for( int i=0; i<skele->ik_count; i++ )
    {
@@ -362,7 +363,7 @@ static void skeleton_apply_ik_pass( struct skeleton *skele )
  * Applies the typical operations that you want for an IK rig: 
  *    Pose, IK, Pose(deferred), Inverses, Transform
  */
-static void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose,
+VG_STATIC void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose,
                                      m4x3f transform )
 {
    skeleton_apply_pose( skele, pose, k_anim_apply_defer_ik );
@@ -375,7 +376,7 @@ static void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose,
 /*
  * Get an animation by name
  */
-static struct skeleton_anim *skeleton_get_anim( struct skeleton *skele,
+VG_STATIC struct skeleton_anim *skeleton_get_anim( struct skeleton *skele,
                                                 const char *name )
 {
    for( int i=0; i<skele->anim_count; i++ )
@@ -389,8 +390,34 @@ static struct skeleton_anim *skeleton_get_anim( struct skeleton *skele,
    return NULL;
 }
 
-/* Setup an animated skeleton from model */
-static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
+VG_STATIC void skeleton_alloc_from( struct skeleton *skele,
+                                 void *lin_alloc,
+                                 struct classtype_skeleton *inf )
+{
+   skele->bone_count     = inf->channels;
+   skele->ik_count       = inf->ik_count;
+   skele->collider_count = inf->collider_count;
+   skele->anim_count     = inf->anim_count;
+
+   u32 bone_size = sizeof(struct skeleton_bone) * skele->bone_count,
+       ik_size   = sizeof(struct skeleton_ik)   * skele->ik_count,
+       mtx_size  = sizeof(m4x3f)                * skele->bone_count,
+       anim_size = sizeof(struct skeleton_anim) * skele->anim_count;
+
+   skele->bones      = vg_linear_alloc( lin_alloc, bone_size );
+   skele->ik         = vg_linear_alloc( lin_alloc, ik_size );
+   skele->final_mtx  = vg_linear_alloc( lin_alloc, mtx_size );
+   skele->anims      = vg_linear_alloc( lin_alloc, anim_size );
+}
+
+VG_STATIC void skeleton_fatal_err(void)
+{
+   vg_fatal_exit_loop( "Skeleton setup failed" );
+}
+
+/* Setup an animated skeleton from model. mdl's metadata should stick around */
+VG_STATIC void skeleton_setup( struct skeleton *skele,
+                               void *lin_alloc, mdl_context *mdl )
 {
    u32 bone_count = 1, skeleton_root = 0, ik_count = 0, collider_count = 0;
    skele->bone_count = 0;
@@ -400,24 +427,14 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
 
    struct classtype_skeleton *inf = NULL;
 
-   for( u32 i=0; i<mdl->node_count; i++ )
+   for( u32 i=0; i<mdl->info.node_count; i++ )
    {
       mdl_node *pnode = mdl_node_from_id( mdl, i );
 
       if( pnode->classtype == k_classtype_skeleton )
       {
          inf = mdl_get_entdata( mdl, pnode );
-         if( skele->bone_count )
-         {
-            vg_error( "Multiple skeletons in model file\n" );
-            goto error_dealloc;
-         }
-         
-         skele->bone_count = inf->channels;
-         skele->ik_count = inf->ik_count;
-         skele->collider_count = inf->collider_count;
-         skele->bones =vg_alloc(sizeof(struct skeleton_bone)*skele->bone_count);
-         skele->ik = vg_alloc(sizeof(struct skeleton_ik)*skele->ik_count);
+         skeleton_alloc_from( skele, lin_alloc, inf );
          skeleton_root = i;
       }
       else if( skele->bone_count )
@@ -432,7 +449,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
                            bone_count, skele->bone_count,
                            mdl_pstr( mdl, pnode->pstr_name ));
 
-               goto error_dealloc;
+               skeleton_fatal_err();
             }
 
             struct skeleton_bone *sb = &skele->bones[bone_count];
@@ -442,7 +459,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
             v3_copy( pnode->co, sb->co );
             v3_copy( pnode->s, sb->end );
             sb->parent = pnode->parent-skeleton_root;
-            strncpy( sb->name, mdl_pstr(mdl,pnode->pstr_name), 15 );
+            sb->name   = mdl_pstr( mdl, pnode->pstr_name );
             sb->deform = bone_inf->deform;
 
             if( is_ik )
@@ -453,7 +470,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
                if( ik_count == skele->ik_count )
                {
                   vg_error( "Too many ik bones, corrupt model file\n" );
-                  goto error_dealloc;
+                  skeleton_fatal_err();
                }
 
                struct skeleton_ik *ik = &skele->ik[ ik_count ++ ];
@@ -476,7 +493,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
                if( collider_count == skele->collider_count )
                {
                   vg_error( "Too many collider bones\n" );
-                  goto error_dealloc;
+                  skeleton_fatal_err();
                }
 
                collider_count ++;
@@ -494,26 +511,27 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
    if( !inf )
    {
       vg_error( "No skeleton in model\n" );
-      return 0;
+      skeleton_fatal_err();
    }
 
    if( collider_count != skele->collider_count )
    {
       vg_error( "Loaded %u colliders out of %u\n", collider_count,
-                                                      skele->collider_count );
-      goto error_dealloc;
+                                                   skele->collider_count );
+      skeleton_fatal_err();
    }
 
    if( bone_count != skele->bone_count )
    {
       vg_error( "Loaded %u bones out of %u\n", bone_count, skele->bone_count );
-      goto error_dealloc;
+      vg_fatal_exit_loop( "Skeleton setup failed" );
+      skeleton_fatal_err();
    }
 
    if( ik_count != skele->ik_count )
    {
       vg_error( "Loaded %u ik bones out of %u\n", ik_count, skele->ik_count );
-      goto error_dealloc;
+      skeleton_fatal_err();
    }
 
    /* fill in implicit root bone */
@@ -521,40 +539,29 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
    v3_copy( (v3f){0.0f,1.0f,0.0f}, skele->bones[0].end );
    skele->bones[0].parent = 0xffffffff;
    skele->bones[0].collider = 0;
+   skele->bones[0].name = "[root]";
    
-   skele->final_mtx = vg_alloc( sizeof(m4x3f) * skele->bone_count );
-   skele->anim_count = inf->anim_count;
-   skele->anims = vg_alloc( sizeof(struct skeleton_anim) * inf->anim_count);
-   
-   for( int i=0; i<inf->anim_count; i++ )
+   /* process animation quick refs */
+   for( int i=0; i<skele->anim_count; i++ )
    {
-      mdl_animation *anim = 
-         mdl_animation_from_id( mdl, inf->anim_start+i );
-
-      skele->anims[i].rate = anim->rate;
-      skele->anims[i].length = anim->length;
-      strncpy( skele->anims[i].name, mdl_pstr(mdl, anim->pstr_name), 31 );
+      mdl_animation *anim = &mdl->anim_buffer[ inf->anim_start + i ];
 
-      u32 total_keyframes = (skele->bone_count-1)*anim->length;
-      size_t block_size = sizeof(mdl_keyframe) * total_keyframes;
-      mdl_keyframe *dst = vg_alloc( block_size );
+      skele->anims[i].rate       = anim->rate;
+      skele->anims[i].length     = anim->length;
+      skele->anims[i].name       = mdl_pstr(mdl, anim->pstr_name);
+      skele->anims[i].anim_data  = &mdl->keyframe_buffer[ anim->offset ];
 
-      skele->anims[i].anim_data = dst;
-      memcpy( dst, mdl_get_animdata( mdl, anim ), block_size );
+      vg_info( "animation[ %f, %u ] '%s'\n", anim->rate,
+                                             anim->length,
+                                             skele->anims[i].name );
    }
 
    skeleton_create_inverses( skele );
    vg_success( "Loaded skeleton with %u bones\n", skele->bone_count );
    vg_success( "                     %u colliders\n", skele->collider_count );
-   return 1;
-
-error_dealloc:
-   vg_free( skele->bones );
-   vg_free( skele->ik );
-   return 0;
 }
 
-static void skeleton_debug( struct skeleton *skele )
+VG_STATIC void skeleton_debug( struct skeleton *skele )
 {
    for( int i=0; i<skele->bone_count; i ++ )
    {
diff --git a/steam.h b/steam.h
index a2132223b2c9db9ae154e331ce57664a10d390ac..a92c3252e66b1b503b993ecaf1afd32db88798aa 100644 (file)
--- a/steam.h
+++ b/steam.h
@@ -25,9 +25,9 @@
  * nothing.
  */
 
-static char steam_username_at_startup[128];
+VG_STATIC char steam_username_at_startup[128];
 
-static void recv_steam_warning( int severity, const char *msg )
+VG_STATIC void recv_steam_warning( int severity, const char *msg )
 {
    if( severity == 0 )
       vg_low( "%s\n", msg );
@@ -35,23 +35,23 @@ static void recv_steam_warning( int severity, const char *msg )
       vg_info( "%s\n", msg );
 }
 
-static int steam_ready = 0,
+VG_STATIC int steam_ready = 0,
            steam_stats_ready = 0;
 
-static void *hSteamNetworkingSockets,
+VG_STATIC void *hSteamNetworkingSockets,
             *hSteamUser;
 
-static ISteamUserStats *hSteamUserStats;
-static HSteamPipe hSteamClientPipe;
+VG_STATIC ISteamUserStats *hSteamUserStats;
+VG_STATIC HSteamPipe hSteamClientPipe;
 
-static const char *steam_achievement_names[] = 
+VG_STATIC const char *steam_achievement_names[] = 
 {
    "ALBERT", "MARC", 
    "ROUTE_MPY", "ROUTE_MPG", "ROUTE_MPB", "ROUTE_MPR",
    "ROUTE_TO", "ROUTE_TC"
 };
 
-static void steam_store_achievements(void)
+VG_STATIC void steam_store_achievements(void)
 {
    if( steam_ready && steam_stats_ready )
    {
@@ -59,7 +59,7 @@ static void steam_store_achievements(void)
    }
 }
 
-static void steam_set_achievement( const char *name )
+VG_STATIC void steam_set_achievement( const char *name )
 {
    if( steam_ready && steam_stats_ready )
    {
@@ -78,7 +78,7 @@ static void steam_set_achievement( const char *name )
    }
 }
 
-static void steam_clear_achievement( const char *name )
+VG_STATIC void steam_clear_achievement( const char *name )
 {
    if( steam_ready && steam_stats_ready )
    {
@@ -98,7 +98,7 @@ static void steam_clear_achievement( const char *name )
 }
 
 
-static int steam_list_achievements( int argc, char const *argv[] )
+VG_STATIC int steam_list_achievements( int argc, char const *argv[] )
 {
    vg_info( "Achievements: \n" );
 
@@ -128,7 +128,7 @@ static int steam_list_achievements( int argc, char const *argv[] )
    return 0;
 }
 
-static int steam_clear_all_achievements( int argc, char const *argv[] )
+VG_STATIC int steam_clear_all_achievements( int argc, char const *argv[] )
 {
    if( steam_ready && steam_stats_ready )
    {
@@ -147,7 +147,7 @@ static int steam_clear_all_achievements( int argc, char const *argv[] )
    return 0;
 }
 
-static int steam_set_achievemnt_test( int argc, char const *argv[] )
+VG_STATIC int steam_set_achievemnt_test( int argc, char const *argv[] )
 {
    if( argc < 2 )
       return 0;
@@ -161,7 +161,7 @@ static int steam_set_achievemnt_test( int argc, char const *argv[] )
    return 0;
 }
 
-static void steam_on_recieve_current_stats( CallbackMsg_t *msg )
+VG_STATIC void steam_on_recieve_current_stats( CallbackMsg_t *msg )
 {
    UserStatsReceived_t *rec = (UserStatsReceived_t *)msg->m_pubParam;
 
@@ -177,7 +177,7 @@ static void steam_on_recieve_current_stats( CallbackMsg_t *msg )
    }
 }
 
-static int steam_init(void)
+VG_STATIC int steam_init(void)
 {
    const char *username = NULL;
 
@@ -249,13 +249,13 @@ static int steam_init(void)
    return 1;
 }
 
-static void steam_update(void)
+VG_STATIC void steam_update(void)
 {
    if( steam_ready )
       steamworks_event_loop( hSteamClientPipe );
 }
 
-static void steam_end(void *nothing)
+VG_STATIC void steam_end(void *nothing)
 {
    if( steam_ready )
    {
index b812ef20a7ed24f92340af86742ced7ea10c9dc5..8b1ea59eb7d2748fcd0ae3b4d5d4bbae00fe80be 100644 (file)
@@ -5,7 +5,7 @@
 #define VG_CONFIG
 #include "vg/vg.h"
 
-static struct button_binding vg_button_binds[] = 
+VG_STATIC struct button_binding vg_button_binds[] = 
 {
        { .name = "primary", .bind = GLFW_MOUSE_BUTTON_LEFT },
        { .name = "secondary", .bind = GLFW_MOUSE_BUTTON_RIGHT },
@@ -21,7 +21,7 @@ static struct button_binding vg_button_binds[] =
    { .name = "menu", .bind = GLFW_KEY_ESCAPE }
 };
 
-static struct button_binding vg_controller_binds[] = 
+VG_STATIC struct button_binding vg_controller_binds[] = 
 {
    { "jump",         GLFW_GAMEPAD_BUTTON_A },
    { "break",        GLFW_GAMEPAD_BUTTON_B },
@@ -30,7 +30,7 @@ static struct button_binding vg_controller_binds[] =
    { "menu",         GLFW_GAMEPAD_BUTTON_BACK }
 };
 
-static struct axis_binding vg_axis_binds[] = 
+VG_STATIC struct axis_binding vg_axis_binds[] = 
 {
        { .name = "lookh",         .axis = GLFW_GAMEPAD_AXIS_LEFT_X },
        { .name = "lookv",         .axis = GLFW_GAMEPAD_AXIS_LEFT_Y },
@@ -40,6 +40,6 @@ static struct axis_binding vg_axis_binds[] =
    { .name = "grab",       .axis = GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER },
 };
 
-static struct vg_achievement vg_achievements[] =
+VG_STATIC struct vg_achievement vg_achievements[] =
 {
 };
diff --git a/world.h b/world.h
index 08fe437fc8cdb9821ed7f7c1933c6dda7ffda79c..8b1b1dc079ff159e06e6197837f0637e4a6a1e46 100644 (file)
--- a/world.h
+++ b/world.h
@@ -4,7 +4,7 @@
 
 #include "common.h"
 
-static int ray_world( v3f pos, v3f dir, ray_hit *hit );
+VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
 
 #ifndef WORLD_H
 #define WORLD_H
@@ -19,8 +19,6 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit );
 #include "bvh.h"
 #include "model.h"
 
-#include "traffic.h" /*TODO: -> world_traffic.h */
-
 #include "shaders/terrain.h"
 #include "shaders/sky.h"
 #include "shaders/planeinf.h"
@@ -30,28 +28,122 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit );
 #include "shaders/fscolour.h"
 #include "shaders/alphatest.h"
 
+typedef struct teleport_gate teleport_gate;
+
 enum { k_max_ui_segments = 8 };
-enum { k_max_ui_splits_per_segment = 16 };
 
-enum { k_max_ui_elements = k_max_ui_segments*k_max_ui_splits_per_segment };
+enum { k_max_ui_elements = k_max_ui_segments };
 enum { k_max_element_verts = 10 };
 enum { k_max_element_indices = 20 };
 
 enum { k_route_ui_max_verts = k_max_ui_elements*k_max_element_verts };
 enum { k_route_ui_max_indices = k_max_ui_elements*k_max_element_indices };
 
-static struct gworld
+enum logic_type
+{
+   k_logic_type_relay         = 1,
+   k_logic_type_chance        = 2,
+   k_logic_type_achievement   = 3
+};
+
+VG_STATIC struct gworld
 {
-   /* gameplay */
+   /*
+    * Allocated as system memory
+    * --------------------------------------------------------------------------
+    */
+
+   /* rendering */
+   glmesh skydome;
+   mdl_submesh dome_upper, dome_lower;
+
+   glmesh mesh_gate_surface;
+
+   double sky_time, sky_rate, sky_target_rate;
+
+   /* water rendering */
+   struct
+   {
+      struct framebuffer fbreflect, fbdepth;
+
+      boxf depthbounds;
+      int depth_computed;
+
+      float height;
+      int enabled;
+      v4f plane;
+   }
+   water;
+
+   /* split flap display */
+   struct
+   {
+      mdl_submesh *sm_module, *sm_card;
+      glmesh mesh_base, mesh_display;
+
+      u32 w, h;
+      float *buffer;
+   }
+   sfd;
+
+   /* timing bars, fixed maximum amount */
+   struct route_ui_bar
+   {
+      GLuint vao, vbo, ebo;
+
+      u32  indices_head;
+      u32  vertex_head;
+
+      float last_notch;
+
+      struct route_ui_segment
+      {
+         float length;
+         u32 vertex_start, vertex_count,
+             index_start, index_count, notches;
+      }
+      segments[k_max_ui_segments];
+
+      u32 segment_start, segment_count, fade_start, fade_count;
+      double fade_timer_start;
+      float xpos;
+   }
+   ui_bars[16];
+
+   v3f render_gate_pos;
+   int active_route_board;
+
+   /*
+    * Dynamically allocated when world_load is called.
+    *
+    *                  the following arrays index somewhere into this linear 
+    *                  allocator
+    *
+    * (world_gen.h)
+    * --------------------------------------------------------------------------
+    */
+   void *dynamic_vgl;
+
+   /*
+    * Main world .mdl 
+    */
+   mdl_context *meta;
+
+   /*
+    * Named safe places to respawn
+    */
    struct respawn_point
    {
       v3f co;
       v4f q;
-      char name[32];
+      const char *name;
    }
-   spawns[32];
+   * spawns;
    u32 spawn_count;
 
+   /*
+    * Audio player entities
+    */
    struct world_audio_thing
    {
       v3f pos;
@@ -62,98 +154,51 @@ static struct gworld
       audio_clip temp_embedded_clip;
    }
    * audio_things;
-   
-   u32 audio_things_count,
-       audio_things_cap;
+   u32 audio_things_count;
 
-   struct achievement_zone
+   /*
+    * Relays, random, etc
+    */
+   struct logic_entity
    {
-      m4x3f transform, inv_transform;
-      char name[32];
-      int triggered;
+      v3f pos;
+      enum logic_type logic_type;
+      int enabled;
 
-      union
-      {
-         mdl_node *ptarget_delegated;
-         struct world_audio_thing *ptarget;
-      };
+      /* indexes the action array */
+      u32 action_start, action_count;
    }
-   * achievement_zones;
+   * logic_entities;
+   u32 logic_entity_count;
 
-   u32 achievement_zones_count,
-       achievement_zones_cap;
-
-   struct subworld_sfd
+   /*
+    * Action array
+    */
+   struct logic_action
    {
-      scene mesh;
-      mdl_submesh *sm_module, *sm_card;
-      glmesh temp;
+      u32 event,     /* on trigger, on enable, etc (TODO: Enum) */
+          target_id; /* thing to target, 0: self */
 
-      struct sfd_instance
-      {
-         float *buffer;
-
-         u32 w,h;
-      } 
-      tester;
    }
-   sfd;
-
-   /* Paths */
-   traffic_node traffic[128];
-   u32 traffic_count;
-
-#if 0
-   traffic_driver van_man[6];
-#endif
-
-   double sky_time, sky_rate, sky_target_rate;
-   
-   /* Physics */
-   
-   /* Rendering & geometry */
-   scene geo, foliage;
-   rigidbody rb_geo;
+   * logic_actions;
+   u32 logic_action_count;
 
-   /* TODO Maybe make this less hardcoded */
-   mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
-               sm_foliage_main, sm_foliage_alphatest,
-               sm_graffiti, sm_subworld, sm_terrain;
-
-   glmesh skybox, skydome;
-   mdl_submesh dome_upper, dome_lower;
-
-   glmesh cars;
-   mdl_submesh car_holden;
-
-   /* Load time */
-
-   struct instance_cache
+   /*
+    * Box trigger entities
+    */
+   struct trigger_zone
    {
-      mdl_header *mdl;
-      u32 pstr_file;
+      m4x3f transform, inv_transform;
+      u32   trigger_entity;
    }
-   * instance_cache;
-   u32 instance_cache_count,
-       instance_cache_cap;
+   * triggers;
+   u32 trigger_count;
 
-   v3f render_gate_pos;
-   int active_route_board;
-}
-world ;
-
-typedef struct teleport_gate teleport_gate;
-struct teleport_gate
-{ 
-   v3f co[2];
-   v4f q[2];
-   v2f dims;
 
-   m4x3f to_world, recv_to_world, transport;
-};
-
-struct subworld_routes
-{
+   /*
+    * Routes (world_routes.h)
+    * --------------------------------------------------------------------------
+    */
    struct route_node
    {
       v3f co, right, up, h;
@@ -163,9 +208,7 @@ struct subworld_routes
       u32 route_ids[4];    /* Gates can be linked into up to four routes */
    }
    *nodes;
-
-   u32 node_count,
-       node_cap;
+   u32 node_count;
 
    struct route
    {
@@ -180,41 +223,23 @@ struct subworld_routes
 
       double best_lap, latest_pass; /* Session */
 
-      struct 
-      {
-         GLuint vao, vbo, ebo;
-
-         u32  indices_head;
-         u32  vertex_head;
-
-         float last_notch;
-
-         struct route_ui_segment
-         {
-            float length;
-            u32 vertex_start, vertex_count,
-                index_start, index_count, notches;
-         }
-         segments[k_max_ui_segments];
-
-         u32 segment_start, segment_count, fade_start, fade_count;
-         double fade_timer_start;
-         float xpos;
-      }
-      ui;
-
       m4x3f scoreboard_transform;
    }
    *routes;
-
-   double time, rewind_from, rewind_to, last_use;
-
-   u32 route_count,
-       route_cap;
+   u32 route_count;
 
    struct route_gate
    {
-      teleport_gate gate;
+      struct teleport_gate
+      { 
+         v3f co[2];
+         v4f q[2];
+         v2f dims;
+
+         m4x3f to_world, recv_to_world, transport;
+      }
+      gate;
+
       u32 node_id;
 
       struct route_timing
@@ -225,34 +250,71 @@ struct subworld_routes
       timing;
    }
    *gates;
+   u32 gate_count;
 
    struct route_collector
    {
       struct route_timing timing;
    }
    *collectors;
+   u32 collector_count;
+
 
-   u32 gate_count,
-       gate_cap,
-       collector_count,
-       collector_cap;
+   /* logic 
+    * ----------------------------------------------------
+    */
 
    u32 active_gate,
        current_run_version;
+   double time, rewind_from, rewind_to, last_use;
+
+   /* world geometry */
+   scene *scene_geo, 
+         *scene_no_collide,
+         *scene_lines;
+
+   /* spacial mappings */
+   bh_tree *audio_bh,
+           *trigger_bh,
+           *geo_bh;
+
+   /* graphics */
+   glmesh mesh_geo, 
+          mesh_no_collide,
+          mesh_route_lines,
+          mesh_water;
+
+   rigidbody rb_geo;
+
+   /* TODO Maybe make this less hardcoded */
+   mdl_submesh sm_geo_std_oob,   sm_geo_std, sm_geo_vb,
+               sm_foliage_main,  sm_foliage_alphatest,
+               sm_graffiti, sm_subworld, sm_terrain;
 
-   scene scene_lines;
+   /*
+    * Allocated AFTER all previous buffers are done
+    * --------------------------------------------------------------------------
+    */
+
+   struct instance_cache
+   {
+      mdl_context *mdl;
+      u32 pstr_file;
+   }
+   instance_cache[32];
+   u32 instance_cache_count;
 }
-static world_routes;
+world;
 
 
 /*
  * API
  */
 
-static int ray_hit_is_ramp( ray_hit *hit );
-static int ray_hit_is_terrain( ray_hit *hit );
-static void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
-static int ray_world( v3f pos, v3f dir, ray_hit *hit );
+VG_STATIC int ray_hit_is_ramp( ray_hit *hit );
+VG_STATIC int ray_hit_is_terrain( ray_hit *hit );
+VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
+VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
 
 /*
  * Submodules
@@ -271,8 +333,16 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit );
  * -----------------------------------------------------------------------------
  */
 
-static void world_init(void)
+VG_STATIC void world_init(void)
 {
+   vg_convar_push( (struct vg_convar){
+      .name = "water_enable",
+      .data = &world.water.enabled,
+      .data_type = k_convar_dtype_i32,
+      .opt_i32 = { .min=0, .max=1, .clamp=1 },
+      .persistent = 0
+   });
+
    world.sky_rate = 1.0;
    world.sky_target_rate = 1.0;
 
@@ -284,12 +354,9 @@ static void world_init(void)
    shader_alphatest_register();
 
    vg_info( "Loading world resources\n" );
-
-   VG_REQUIRED_ASSET( mdl_header*, mcars, mdl_load, "models/rs_cars.mdl" );
-   VG_REQUIRED_ASSET( mdl_header*, msky,  mdl_load, "models/rs_skydome.mdl" );
-
-   mdl_node *nholden = mdl_node_from_name( mcars, "holden" );
-   world.car_holden = *mdl_node_submesh( mcars, nholden, 0 );
+   
+   vg_linear_clear( vg_mem.scratch );
+   mdl_context *msky = mdl_load_full( vg_mem.scratch, "models/rs_skydome.mdl" );
 
    mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
             *nupper = mdl_node_from_name( msky, "dome_upper" );
@@ -299,37 +366,25 @@ static void world_init(void)
 
    vg_acquire_thread_sync();
    {
-      mdl_unpack_glmesh( mcars, &world.cars );
       mdl_unpack_glmesh( msky, &world.skydome );
    }
    vg_release_thread_sync();
 
-   vg_free(mcars);
-   vg_free(msky);
-
    /* Other systems */
    vg_info( "Loading other world systems\n" );
 
-   vg_loader_highwater( world_render_init, world_render_free, NULL );
-   vg_loader_highwater( world_sfd_init, world_sfd_free, NULL );
-   vg_loader_highwater( world_water_init, world_water_free, NULL );
-   vg_loader_highwater( world_gates_init, world_gates_free, NULL );
-   vg_loader_highwater( world_routes_init, world_routes_free, NULL );
-}
-
-static void world_free( void *_ )
-{
-   mesh_free( &world.cars );
-   mesh_free( &world.skydome );
-   vg_free( world.achievement_zones );
+   vg_loader_highwater( world_render_init, NULL, NULL );
+   vg_loader_highwater( world_sfd_init, NULL, NULL );
+   vg_loader_highwater( world_water_init, NULL, NULL );
+   vg_loader_highwater( world_gates_init, NULL, NULL );
+   vg_loader_highwater( world_routes_init, NULL, NULL );
 
-   /* FIXME: This fucks with the audio player. Use-after-free */
-#if 0
-   vg_free( world.audio_things );
-#endif
+   /* Allocate dynamic world memory arena */
+   u32 max_size = 72*1024*1024;
+   world.dynamic_vgl = vg_create_linear_allocator( vg_mem.rtmemory, max_size );
 }
 
-static void world_update( v3f pos )
+VG_STATIC void world_update( v3f pos )
 {
    world.sky_time += world.sky_rate * vg.time_delta;
    world.sky_rate = vg_lerp( world.sky_rate, world.sky_target_rate, 
@@ -343,9 +398,9 @@ static void world_update( v3f pos )
    int closest = 0;
    float min_dist = INFINITY;
 
-   for( int i=0; i<world_routes.route_count; i++ )
+   for( int i=0; i<world.route_count; i++ )
    {
-      float d = v3_dist2( world_routes.routes[i].scoreboard_transform[3], pos );
+      float d = v3_dist2( world.routes[i].scoreboard_transform[3], pos );
 
       if( d < min_dist )
       {
@@ -358,9 +413,8 @@ static void world_update( v3f pos )
    {
       network_scores_updated = 0;
       world.active_route_board = closest;
-      struct subworld_sfd *sfd = &world.sfd;
 
-      struct route *route = &world_routes.routes[closest];
+      struct route *route = &world.routes[closest];
 
       u32 id = route->track_id;
 
@@ -370,12 +424,13 @@ static void world_update( v3f pos )
 
          for( int i=0; i<13; i++ )
          {
-            sfd_encode( &sfd->tester, i, &local_board->data[27*i] );
+            sfd_encode( i, &local_board->data[27*i] );
          }
       }
    }
 
-   static int in_zone = 0;
+#if 0
+   VG_STATIC int in_zone = 0;
 
    int in_zone_this_time = 0;
 
@@ -415,8 +470,9 @@ static void world_update( v3f pos )
    }
 
    in_zone = in_zone_this_time;
+#endif
    
-   sfd_update( &world.sfd.tester );
+   sfd_update();
 }
 
 /* 
@@ -425,18 +481,18 @@ static void world_update( v3f pos )
  * -----------------------------------------------------------------------------
  */
 
-static void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
+VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
 {
    for( int i=0; i<3; i++ )
-      v3_copy( world.geo.verts[ hit->tri[i] ].co, tri[i] );
+      v3_copy( world.scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
 }
 
-static int ray_world( v3f pos, v3f dir, ray_hit *hit )
+VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit )
 {
-   return scene_raycast( &world.geo, pos, dir, hit );
+   return scene_raycast( world.scene_geo, world.geo_bh, pos, dir, hit );
 }
 
-static int ray_hit_is_terrain( ray_hit *hit )
+VG_STATIC int ray_hit_is_terrain( ray_hit *hit )
 {
    u32 valid_start = 0,
        valid_end   = world.sm_terrain.vertex_count;
@@ -445,7 +501,7 @@ static int ray_hit_is_terrain( ray_hit *hit )
           (hit->tri[0]  < valid_end);
 }
 
-static int ray_hit_is_ramp( ray_hit *hit )
+VG_STATIC int ray_hit_is_ramp( ray_hit *hit )
 {
    u32 valid_start = world.sm_geo_std.vertex_start,
        valid_end   = world.sm_geo_vb.vertex_start;
index 39a1e78d39dffdf8b2ff6f6034afd24aa039f910..b57c799fd33b68f31eb9a513fb8fc5f009253a52 100644 (file)
@@ -5,35 +5,15 @@
 #ifndef WORLD_GATE_H
 #define WORLD_GATE_H
 
-#define GATE_RENDER_PERFORMANCE
-
 #include "common.h"
 #include "model.h"
 #include "render.h"
 
-#ifndef GATE_RENDER_PERFORMANCE
-  #include "shaders/gate.h"
-#else
-  #include "shaders/gatelq.h"
-#endif
-
+#include "shaders/gatelq.h"
 #include "world_water.h"
 
 
-static struct
-{
-   struct framebuffer fb;
-   glmesh mdl;
-}
-grender =
-{
-   .fb = {
-      .format = GL_RGB,
-      .div = 1
-   }
-};
-
-static void gate_transform_update( teleport_gate *gate )
+VG_STATIC void gate_transform_update( teleport_gate *gate )
 {
    m4x3f to_local;
 
@@ -47,37 +27,23 @@ static void gate_transform_update( teleport_gate *gate )
    m4x3_mul( gate->recv_to_world, to_local, gate->transport );
 }
 
-static void world_gates_init(void)
+VG_STATIC void world_gates_init(void)
 {
    vg_info( "world_gates_init\n" );
 
-#ifndef GATE_RENDER_PERFORMANCE
-   shader_gate_register();
-#else
    shader_gatelq_register();
-#endif
 
-   mdl_header *mgate = mdl_load( "models/rs_gate.mdl" );
+   vg_linear_clear( vg_mem.scratch );
+   mdl_context *mgate = mdl_load_full( vg_mem.scratch, "models/rs_gate.mdl" );
 
    vg_acquire_thread_sync();
    {
-      fb_init( &grender.fb );
-      mdl_unpack_glmesh( mgate, &grender.mdl );
+      mdl_unpack_glmesh( mgate, &world.mesh_gate_surface );
    }
    vg_release_thread_sync();
 }
 
-static void world_gates_free(void*_)
-{
-   fb_free( &grender.fb );
-}
-
-static void gate_fb_resize(void)
-{
-   fb_resize( &grender.fb );
-}
-
-static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
+VG_STATIC int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
 {
    v3f viewdir, gatedir;
    m3x3_mulv( camera, (v3f){0.0f,0.0f,-1.0f}, viewdir );
@@ -135,11 +101,7 @@ static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
 
    m4x4_mul( projection, view, projection );
 
-#ifndef GATE_RENDER_PERFORMANCE
-      fb_use( &grender.fb );
-      glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
-      glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
-#else
+   {
       shader_gatelq_use();
       shader_gatelq_uPv( vg.pv );
       shader_gatelq_uMdl( gate_xform );
@@ -154,53 +116,17 @@ static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
       glStencilFunc( GL_ALWAYS, 1, 0xFF ); 
       glStencilMask( 0xFF );
 
-      mesh_bind( &grender.mdl );
-      mesh_draw( &grender.mdl );
+      mesh_bind( &world.mesh_gate_surface );
+      mesh_draw( &world.mesh_gate_surface );
 
       glClear( GL_DEPTH_BUFFER_BIT );
       glStencilFunc( GL_EQUAL, 1, 0xFF );
       glStencilMask( 0x00 ); 
-#endif
+   }
 
    render_world( projection, cam_new );
 
-#ifndef GATE_RENDER_PERFORMANCE
-
-      /*
-       * NOTE: Need to find a way to draw a stencil buffer into the water 
-       *       rendering 
-       */
-
-      render_water_texture( cam_new );
-      fb_use( &grender.fb );
-
-      render_water_surface( projection, cam_new );
-      fb_use( NULL );
-
-      shader_gate_use();
-
-      shader_gate_uPv( vg_pv );
-      shader_gate_uMdl( gate_xform );
-
-      fb_bindtex( &grender.fb, 0 );
-
-      shader_gate_uCam( viewpos );
-      shader_gate_uTexMain( 0 );
-      shader_gate_uTexWater( 1 );
-      shader_gate_uTime( vg_time*0.25f );
-      shader_gate_uInvRes( (v2f){
-            1.0f / (float)vg_window_x,
-            1.0f / (float)vg_window_y });
-      
-      glEnable(GL_BLEND);
-      glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-      glBlendEquation(GL_FUNC_ADD);
-
-      mesh_bind( &grender.mdl );
-      mesh_draw( &grender.mdl );
-
-      glDisable(GL_BLEND);
-#else
+   {
       glDisable( GL_STENCIL_TEST );
 
       render_water_texture( cam_new );
@@ -212,12 +138,12 @@ static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera )
       glStencilMask( 0xFF );
       glStencilFunc( GL_ALWAYS, 1, 0xFF );
       glDisable( GL_STENCIL_TEST );
-#endif
+   }
 
    return 1;
 }
 
-static int gate_intersect( teleport_gate *gate, v3f pos, v3f last )
+VG_STATIC int gate_intersect( teleport_gate *gate, v3f pos, v3f last )
 {
    v4f surface;
    m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, surface );
index 31722e563bf40f8a662929b000cdb5747fefe559..ccd3eda875feb36294f81108447610e2ecf730b2 100644 (file)
@@ -5,24 +5,23 @@
 #ifndef WORLD_GEN_H
 #define WORLD_GEN_H
 
-/* 
- * FUTURE:
- *    If we have multiple levels, write an unloader
- */
-
 #include "world.h"
 
-static void world_add_all_if_material( m4x3f transform, scene *pscene, 
-                                       mdl_header *mdl, u32 id )
+/* load world TODO: Put back vg back in loading state while this happens */
+VG_STATIC void world_load( const char *mdl_file );
+
+
+
+VG_STATIC void world_add_all_if_material( m4x3f transform, scene *pscene, 
+                                          mdl_context *mdl, u32 id )
 {
-   for( int i=0; i<mdl->node_count; i++ )
+   for( int i=0; i<mdl->info.node_count; i++ )
    {
       mdl_node *pnode = mdl_node_from_id( mdl, i );
 
       for( int j=0; j<pnode->submesh_count; j++ )
       {
          mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j );
-
          if( sm->material_id == id )
          {
             m4x3f transform2;
@@ -33,13 +32,14 @@ static void world_add_all_if_material( m4x3f transform, scene *pscene,
          }
       }
 
+#if 0
       if( pnode->classtype == k_classtype_instance )
       {
          if( pnode->sub_uid )
          {
             u32 instance_id = pnode->sub_uid -1;
             struct instance_cache *cache = &world.instance_cache[instance_id];
-            mdl_header *mdl2 = cache->mdl;
+            mdl_context *mdl2 = cache->mdl;
 
             m4x3f transform2;
             mdl_node_transform( pnode, transform2 );
@@ -48,15 +48,20 @@ static void world_add_all_if_material( m4x3f transform, scene *pscene,
             world_add_all_if_material( transform2, pscene, mdl2, id );
          }
       }
+#endif
    }
 }
 
-static void world_apply_procedural_foliage(void)
+/* Sprinkle foliage models over the map on terrain material */
+VG_STATIC void world_apply_procedural_foliage(void)
 {
-   mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl");
+   vg_linear_clear( vg_mem.scratch );
+
+   mdl_context *mfoliage = 
+      mdl_load_full( vg_mem.scratch, "models/rs_foliage.mdl");
 
    v3f volume;
-   v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume );
+   v3_sub( world.scene_geo->bbx[1], world.scene_geo->bbx[0], volume );
    volume[1] = 1.0f;
 
    m4x3f transform;
@@ -68,7 +73,7 @@ static void world_apply_procedural_foliage(void)
       v3f pos;
       v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos );
       pos[1] = 1000.0f;
-      v3_add( pos, world.geo.bbx[0], pos );
+      v3_add( pos, world.scene_geo->bbx[0], pos );
       
       ray_hit hit;
       hit.dist = INFINITY;
@@ -90,124 +95,211 @@ static void world_apply_procedural_foliage(void)
             q_m3x3( qsurface, transform );
 
             v3_copy( hit.pos, transform[3] );
-            scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform);
+            scene_add_submesh( world.scene_no_collide, mfoliage, 
+                               sm_blob, transform);
          }
       }
    }
-
-   vg_free( mfoliage );
 }
 
-static void world_load(void)
+VG_STATIC void world_ents_allocate(void)
 {
-   mdl_header *mworld = mdl_load( "models/mp_dev.mdl" );
-   vg_info( "Loading world: models/mp_dev.mdl\n" );
+   vg_info( "Allocating entities\n" );
 
-   world.spawn_count = 0;
-   world.traffic_count = 0;
-   world.instance_cache = NULL;
-   
-   /*
-    * Process entities
-    */
-   for( int i=0; i<mworld->node_count; i++ )
+   /* count entites to allocate buffers for them.
+    * maybe in the future we just store these numbers in the model file...
+    *
+    * TODO: use this in world_routes too */
+
+   struct countable
    {
-      mdl_node *pnode = mdl_node_from_id( mworld, i );
-      
-      if( pnode->classtype == k_classtype_none )
-      {}
-      else if( pnode->classtype == k_classtype_spawn )
+      enum   classtype ct;
+      void **to_allocate;
+      u32    item_size;
+      int    count;
+   }
+   entity_counts[] =
+   {
+      { 
+         k_classtype_spawn, 
+         (void*)&world.spawns,       
+         sizeof(struct respawn_point) 
+      },
+      { 
+         k_classtype_audio, 
+         (void*)&world.audio_things, 
+         sizeof(struct world_audio_thing) 
+      },
       {
-         struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
-
-         v3_copy( pnode->co, rp->co );
-         v4_copy( pnode->q, rp->q );
-         strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) );
+         k_classtype_trigger,
+         (void*)&world.triggers,
+         sizeof(struct trigger_zone)
       }
-      else if( pnode->classtype == k_classtype_water )
+   };
+
+   for( int i=0; i<vg_list_size(entity_counts); i++ )
+      entity_counts[i].count = 0;
+
+   for( int i=0; i<world.meta->info.node_count; i++ )
+   {
+      mdl_node *pnode = mdl_node_from_id( world.meta, i );
+      
+      for( int j=0; j<vg_list_size(entity_counts); j ++ )
       {
-         if( wrender.enabled )
+         if( pnode->classtype == entity_counts[j].ct )
          {
-            vg_warn( "Multiple water surfaces in level! ('%s')\n", 
-                  mdl_pstr( mworld, pnode->pstr_name ));
-            continue;
+            entity_counts[j].count ++;
+            break;
          }
+      }
+   }
 
-         mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 );
-         
-         if( sm )
-         {
-            vg_acquire_thread_sync();
-            {
-               glmesh surf;
-               mdl_unpack_submesh( mworld, &surf, sm );
-               water_set_surface( &surf, pnode->co[1] );
-            }
-            vg_release_thread_sync();
-         }
+   for( int i=0; i<vg_list_size(entity_counts); i++ )
+   {
+      struct countable *counter = &entity_counts[i];
+      
+      u32 bufsize = counter->item_size*counter->count;
+      *counter->to_allocate = vg_linear_alloc( world.dynamic_vgl, bufsize );
+   }
+}
+
+VG_STATIC void world_pct_spawn( mdl_node *pnode )
+{
+   struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ];
+
+   v3_copy( pnode->co, rp->co );
+   v4_copy( pnode->q, rp->q );
+   rp->name = mdl_pstr( world.meta, pnode->pstr_name );
+}
+
+VG_STATIC void world_pct_water( mdl_node *pnode )
+{
+   if( world.water.enabled )
+   {
+      vg_warn( "Multiple water surfaces in level! ('%s')\n", 
+               mdl_pstr( world.meta, pnode->pstr_name ));
+      return;
+   }
+
+   mdl_submesh *sm = mdl_node_submesh( world.meta, pnode, 0 );
+   
+   if( sm )
+   {
+      vg_acquire_thread_sync();
+      {
+         mdl_unpack_submesh( world.meta, &world.mesh_water, sm );
+         world.water.enabled = 1;
+         water_set_surface( pnode->co[1] );
+      }
+      vg_release_thread_sync();
+   }
+   else
+   {
+      vg_warn( "Water entity has no submeshes!\n" );
+   }
+}
+
+VG_STATIC void world_pct_instance( mdl_node *pnode )
+{
+   struct classtype_instance *inst = mdl_get_entdata( world.meta, pnode );
+   pnode->sub_uid = 0;
+   
+   int cache_entry = 0;
+   for( int i=0; i<world.instance_cache_count; i++ )
+   {
+      struct instance_cache *cache = &world.instance_cache[i];
+      if( inst->pstr_file == cache->pstr_file )
+      {
+         cache_entry = 1;
+         pnode->sub_uid = i+1;
+         break;
       }
-      else if( pnode->classtype == k_classtype_car_path )
+   }
+
+   if( !cache_entry )
+   {
+      if( world.instance_cache_count == vg_list_size(world.instance_cache) )
+         vg_fatal_exit_loop( "Instance cache is full!" );
+
+      struct instance_cache *cache = 
+         &world.instance_cache[world.instance_cache_count ++ ];
+
+      cache->pstr_file = inst->pstr_file;
+
+#if 0
+      cache->mdl = mdl_load( filename );
+
+      if( cache->mdl )
       {
-         struct classtype_car_path *p = mdl_get_entdata( mworld, pnode );
-         traffic_node *tn = &world.traffic[ world.traffic_count ];
-         tn->mn_next = NULL;
-         tn->mn_next1 = NULL;
-         
-         if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target );
-         if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 );
-
-         m4x3f transform;
-         mdl_node_transform( pnode, transform );
-         m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h );
-         v3_copy( transform[3], tn->co );
-
-         pnode->sub_uid = world.traffic_count ++;
+         world.instance_cache_count ++;
+         pnode->sub_uid = world.instance_cache_count;
+         mdl_link_materials( mworld, cache->mdl );
+         vg_success( "Cached %s\n", filename );
       }
-      else if( pnode->classtype == k_classtype_instance )
+      else
       {
-         struct classtype_instance *inst = mdl_get_entdata( mworld, pnode );
-         pnode->sub_uid = 0;
-         
-         int cached = 0;
-         for( int i=0; i<world.instance_cache_count; i++ )
-         {
-            struct instance_cache *cache = &world.instance_cache[i];
-            if( inst->pstr_file == cache->pstr_file )
-            {
-               cached = 1;
-               pnode->sub_uid = i+1;
-               break;
-            }
-         }
+         vg_warn( "Failed to cache %s\n", filename );
+      }
+#endif
+   }
+}
+
+VG_STATIC void world_pct_audio( mdl_node *pnode )
+{
+   struct world_audio_thing *thing = &world.audio_things[
+                                      world.audio_things_count ];
+
+   memset( thing, 0, sizeof(struct world_audio_thing) );
+   struct classtype_audio *aud = mdl_get_entdata( world.meta, pnode );
+
+   v3_copy( pnode->co, thing->pos );
+   
+   if( aud->flags & AUDIO_FLAG_SPACIAL_3D )
+      thing->volume = aud->volume * pnode->s[0];
+   else
+      thing->volume = aud->volume;
+
+   thing->flags = aud->flags;
+   thing->temp_embedded_clip.path = mdl_pstr( world.meta, aud->pstr_file );
+   audio_clip_load( &thing->temp_embedded_clip );
+   thing->player.name = mdl_pstr( world.meta, pnode->pstr_name );
+   thing->player.enqued = 0;
 
-         if( !cached )
+   pnode->sub_uid = world.audio_things_count;
+   world.audio_things_count ++;
+}
+
+VG_STATIC void world_entities_process(void)
+{
+   struct entity_instruction
+   {
+      enum classtype ct;
+      void (*process)( mdl_node *pnode );
+   }
+   entity_instructions[] = 
+   {
+      { k_classtype_spawn,    world_pct_spawn },
+      { k_classtype_water,    world_pct_water },
+      { k_classtype_instance, world_pct_instance },
+      { k_classtype_audio,    world_pct_audio },
+   };
+
+   for( int i=0; i<world.meta->info.node_count; i++ )
+   {
+      mdl_node *pnode = mdl_node_from_id( world.meta, i );
+
+      for( int j=0; j<vg_list_size(entity_instructions); j++ )
+      {
+         struct entity_instruction *instr = &entity_instructions[j];
+
+         if( pnode->classtype == instr->ct )
          {
-            world.instance_cache = buffer_reserve( 
-                            world.instance_cache, world.instance_cache_count,
-                            &world.instance_cache_cap, 1, 
-                            sizeof(struct instance_cache) );
-
-            struct instance_cache *cache = 
-               &world.instance_cache[world.instance_cache_count];
-
-            const char *filename = mdl_pstr(mworld, inst->pstr_file);
-
-            cache->pstr_file = inst->pstr_file;
-            cache->mdl = mdl_load( filename );
-
-            if( cache->mdl )
-            {
-               world.instance_cache_count ++;
-               pnode->sub_uid = world.instance_cache_count;
-               mdl_link_materials( mworld, cache->mdl );
-               vg_success( "Cached %s\n", filename );
-            }
-            else
-            {
-               vg_warn( "Failed to cache %s\n", filename );
-            }
+            instr->process( pnode );
+            break;
          }
       }
+      
+#if 0
       else if( pnode->classtype == k_classtype_achievement_box )
       {
          world.achievement_zones = 
@@ -233,41 +325,10 @@ static void world_load(void)
          else
             zone->ptarget_delegated = NULL;
       }
-      else if( pnode->classtype == k_classtype_audio )
-      {
-         world.audio_things = 
-            buffer_reserve( world.audio_things,
-                            world.audio_things_count,
-                            &world.audio_things_cap, 1, 
-                            sizeof(struct world_audio_thing) );
-
-         struct world_audio_thing *thing = &world.audio_things[
-                                            world.audio_things_count ];
-         memset( thing, 0, sizeof(struct world_audio_thing) );
-         struct classtype_audio *aud = mdl_get_entdata(mworld,pnode);
-
-         v3_copy( pnode->co, thing->pos );
-         
-         if( aud->flags & AUDIO_FLAG_SPACIAL_3D )
-            thing->volume = aud->volume * pnode->s[0];
-         else
-            thing->volume = aud->volume;
-
-         thing->flags = aud->flags;
-         const char *fp = mdl_pstr( mworld, aud->pstr_file );
-         char *path2 = vg_alloc( strlen(fp)+1 );
-         strcpy( path2, fp );
-         thing->temp_embedded_clip.path = path2;
-         thing->temp_embedded_clip.source_mode = k_audio_source_compressed;
-         audio_clip_load( &thing->temp_embedded_clip );
-         thing->player.name = "[temp]";
-         thing->player.enqued = 0;
-
-         pnode->sub_uid = world.audio_things_count;
-         world.audio_things_count ++;
-      }
+#endif
    }
 
+#if 0
    /* fixup links */
    for( int i=0; i<world.achievement_zones_count; i ++ )
    {
@@ -280,54 +341,44 @@ static void world_load(void)
       else
          ach->ptarget = NULL;
    }
+#endif
+}
 
-   /* initialize audio if need be */
-   audio_lock();
-   for( int i=0; i<world.audio_things_count; i++ )
+VG_STATIC void world_load_instance_cache(void)
+{
+   vg_linear_clear( vg_mem.scratch );
+
+   for( int i=0; i<world.instance_cache_count; i++ )
    {
-      struct world_audio_thing *thingy = &world.audio_things[ i ];
+      struct instance_cache *inst = &world.instance_cache[i];
       
-      audio_player_init( &thingy->player );
-      audio_player_set_flags( &thingy->player, thingy->flags );
-      audio_player_set_vol( &thingy->player, thingy->volume );
-      audio_player_set_pan( &thingy->player, 0.0f );
-
-      if( thingy->flags & AUDIO_FLAG_SPACIAL_3D )
-         audio_player_set_position( &thingy->player, thingy->pos );
-
-      if( thingy->flags & AUDIO_FLAG_AUTO_START )
-         audio_player_playclip( &thingy->player, &thingy->temp_embedded_clip );
+      const char *filename = mdl_pstr( world.meta, inst->pstr_file );
+      inst->mdl = mdl_load_full( vg_mem.scratch, filename );
    }
-   audio_unlock();
-
-   world.instance_cache = buffer_fix( world.instance_cache, 
-                                      world.instance_cache_count,
-                                     &world.instance_cache_cap,
-                                     sizeof( struct instance_cache ) );
-
-#if 0
-   traffic_finalize( world.traffic, world.traffic_count );
-   for( int i=0; i<vg_list_size(world.van_man); i++ )
-      world.van_man[i].current =&world.traffic[vg_randint(world.traffic_count)];
-#endif
+}
 
+VG_STATIC void world_generate(void)
+{
    /* 
     * Compile meshes into the world scenes
     */
-   scene_init( &world.geo );
-
-   u32 mat_surf = 0,
-       mat_surf_oob = 0,
+   world.scene_geo = scene_init( world.dynamic_vgl, 500000, 1200000 );
+   
+   /*
+    * TODO: System to dynamically allocate these 
+    */
+   u32 mat_surf         = 0,
+       mat_surf_oob     = 0,
        mat_vertex_blend = 0,
-       mat_alphatest = 0,
-       mat_graffiti = 0,
-       mat_subworld = 0,
-       mat_terrain = 0;
+       mat_alphatest    = 0,
+       mat_graffiti     = 0,
+       mat_subworld     = 0,
+       mat_terrain      = 0;
 
-   for( int i=1; i<mworld->material_count; i++ )
+   for( int i=1; i<world.meta->info.material_count; i++ )
    {
-      mdl_material *mat = mdl_material_from_id( mworld, i );
-      const char *mat_name = mdl_pstr( mworld, mat->pstr_name );
+      mdl_material *mat = &world.meta->material_buffer[ i ];
+      const char *mat_name = mdl_pstr( world.meta, mat->pstr_name );
 
       if( !strcmp( "surf", mat_name ))
          mat_surf = i;
@@ -346,50 +397,122 @@ static void world_load(void)
    m4x3f midentity;
    m4x3_identity( midentity );
 
+   world_load_instance_cache();
+
+   /*
+    * Generate scene: collidable geometry
+    * ----------------------------------------------------------------
+    */
+
+   vg_info( "Generating collidable geometry\n" );
+   vg_info( "terrain...\n" );
+   /* terrain */
    if( mat_terrain )
-      world_add_all_if_material( midentity, &world.geo, mworld, mat_terrain );
-   scene_copy_slice( &world.geo, &world.sm_terrain );
+      world_add_all_if_material( midentity, world.scene_geo, 
+                                 world.meta, mat_terrain );
+   scene_copy_slice( world.scene_geo, &world.sm_terrain );
 
+   /* oob */
+   vg_info( "oob...\n" );
    if( mat_surf_oob )
-      world_add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob );
+      world_add_all_if_material( midentity, world.scene_geo, 
+                                 world.meta, mat_surf_oob );
    else
       vg_warn( "No OOB surface\n" );
-   scene_copy_slice( &world.geo, &world.sm_geo_std_oob );
+   scene_copy_slice( world.scene_geo, &world.sm_geo_std_oob );
+
 
+   /* surface */
+   vg_info( "surface...\n" );
    if( mat_surf )
-      world_add_all_if_material( midentity, &world.geo, mworld, mat_surf );
-   scene_copy_slice( &world.geo, &world.sm_geo_std );
+      world_add_all_if_material( midentity, world.scene_geo, 
+                                 world.meta, mat_surf );
+   scene_copy_slice( world.scene_geo, &world.sm_geo_std );
 
+   /* vertex_blend */
+   vg_info( "vertex blend...\n" );
    if( mat_vertex_blend )
-      world_add_all_if_material( midentity, &world.geo,mworld,mat_vertex_blend);
-   scene_copy_slice( &world.geo, &world.sm_geo_vb );
+      world_add_all_if_material( midentity, world.scene_geo,
+                                 world.meta, mat_vertex_blend);
+   scene_copy_slice( world.scene_geo, &world.sm_geo_vb );
+   
+   /* compress that bad boy */
+   world.scene_geo = scene_fix( world.dynamic_vgl, world.scene_geo );
 
    vg_acquire_thread_sync();
-   scene_upload( &world.geo );
+   {
+      scene_upload( world.scene_geo, &world.mesh_geo );
+   }
    vg_release_thread_sync();
 
-   scene_bh_create( &world.geo );
+   /* setup spacial mapping and rigidbody */
+   world.geo_bh = scene_bh_create( world.dynamic_vgl, world.scene_geo );
 
+   v3_zero( world.rb_geo.co );
+   q_identity( world.rb_geo.q );
 
-   /* Foliage /nocollide layer.
-    * TODO: Probably should have material traits for this
+   world.rb_geo.type = k_rb_shape_scene;
+   world.rb_geo.inf.scene.bh_scene = world.geo_bh;
+   world.rb_geo.is_world = 1;
+   rb_init( &world.rb_geo );
+
+   /*
+    * Generate scene: non-collidable geometry
+    * ----------------------------------------------------------------
     */
-   scene_init( &world.foliage );
+   vg_info( "Generating non-collidable geometry\n" );
+
+   world.scene_no_collide = scene_init( world.dynamic_vgl, 200000, 500000 );
 
+   vg_info( "Applying foliage\n" );
    world_apply_procedural_foliage();
-   scene_copy_slice( &world.foliage, &world.sm_foliage_main );
+   scene_copy_slice( world.scene_no_collide, &world.sm_foliage_main );
 
-   world_add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest);
-   scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest );
+   vg_info( "alphatest...\n" );
+   world_add_all_if_material( midentity, world.scene_no_collide,
+                              world.meta, mat_alphatest );
+   scene_copy_slice( world.scene_no_collide, &world.sm_foliage_alphatest );
 
-   world_add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti );
-   scene_copy_slice( &world.foliage, &world.sm_graffiti );
+   vg_info( "graffiti...\n" );
+   world_add_all_if_material( midentity, world.scene_no_collide, 
+                              world.meta, mat_graffiti );
+   scene_copy_slice( world.scene_no_collide, &world.sm_graffiti );
 
 
+   /* upload and free that */
    vg_acquire_thread_sync();
    {
-      scene_upload( &world.foliage );
+      scene_upload( world.scene_no_collide, &world.mesh_no_collide );
+   }
+   vg_release_thread_sync();
+
+   vg_linear_del( world.dynamic_vgl, world.scene_no_collide );
+   world.scene_no_collide = NULL;
+}
 
+VG_STATIC void world_post_process(void)
+{
+   /* initialize audio if need be */
+   audio_lock();
+   for( int i=0; i<world.audio_things_count; i++ )
+   {
+      struct world_audio_thing *thingy = &world.audio_things[ i ];
+      
+      audio_player_init( &thingy->player );
+      audio_player_set_flags( &thingy->player, thingy->flags );
+      audio_player_set_vol( &thingy->player, thingy->volume );
+      audio_player_set_pan( &thingy->player, 0.0f );
+
+      if( thingy->flags & AUDIO_FLAG_SPACIAL_3D )
+         audio_player_set_position( &thingy->player, thingy->pos );
+
+      if( thingy->flags & AUDIO_FLAG_AUTO_START )
+         audio_player_playclip( &thingy->player, &thingy->temp_embedded_clip );
+   }
+   audio_unlock();
+
+   vg_acquire_thread_sync();
+   {
       /* 
        * Rendering the depth map
        */
@@ -397,12 +520,12 @@ static void world_load(void)
       m4x3f camera;
 
       v3f extent;
-      v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent );
+      v3_sub( world.scene_geo->bbx[1], world.scene_geo->bbx[0], extent );
 
-      float fl = world.geo.bbx[0][0],
-            fr = world.geo.bbx[1][0],
-            fb = world.geo.bbx[0][2],
-            ft = world.geo.bbx[1][2],
+      float fl = world.scene_geo->bbx[0][0],
+            fr = world.scene_geo->bbx[1][0],
+            fb = world.scene_geo->bbx[0][2],
+            ft = world.scene_geo->bbx[1][2],
             rl = 1.0f / (fr-fl),
             tb = 1.0f / (ft-fb);
 
@@ -434,14 +557,18 @@ static void world_load(void)
        * TODO: World settings entity
        */
       struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting;
-      v4_copy( wrender.plane, winfo->g_water_plane );
 
-      v4f bounds;
-      bounds[0] = world.geo.bbx[0][0];
-      bounds[1] = world.geo.bbx[0][2];
-      bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]);
-      bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]);
-      v4_copy( bounds, winfo->g_depth_bounds );
+      if( world.water.enabled )
+         v4_copy( world.water.plane, winfo->g_water_plane );
+
+      v4f info_vec;
+      v3f *bounds = world.scene_geo->bbx;
+
+      info_vec[0] = bounds[0][0];
+      info_vec[1] = bounds[0][2];
+      info_vec[2] = 1.0f/ (bounds[1][0]-bounds[0][0]);
+      info_vec[3] = 1.0f/ (bounds[1][2]-bounds[0][2]);
+      v4_copy( info_vec, winfo->g_depth_bounds );
 
       winfo->g_water_fog = 0.04f;
       render_update_lighting_ub();
@@ -449,25 +576,84 @@ static void world_load(void)
 
    vg_release_thread_sync();
 
-   world_routes_loadfrom( mworld );
-
-   for( int i=0; i<world.instance_cache_count; i++ )
-      vg_free( world.instance_cache[i].mdl );
-
-   vg_free( world.instance_cache );
-   vg_free( mworld );
-   scene_free_offline_buffers( &world.foliage );
-
    /*
     * Setup scene collider 
     */
-   v3_zero( world.rb_geo.co );
-   q_identity( world.rb_geo.q );
+}
 
-   world.rb_geo.type = k_rb_shape_scene;
-   world.rb_geo.inf.scene.pscene = &world.geo;
-   world.rb_geo.is_world = 1;
-   rb_init( &world.rb_geo );
+
+VG_STATIC void world_unload(void)
+{
+   /* free meshes */
+   mesh_free( &world.mesh_geo );
+   mesh_free( &world.mesh_no_collide );
+   mesh_free( &world.mesh_route_lines );
+   mesh_free( &world.mesh_water );
+
+   /* delete the entire block of memory */
+   vg_linear_clear( world.dynamic_vgl );
+
+   /* clean dangling pointers */
+   world.meta = NULL;
+   
+   world.scene_geo = NULL;
+   world.scene_lines = NULL;
+   world.scene_no_collide = NULL;
+
+   world.geo_bh = NULL;
+   world.trigger_bh = NULL;
+   world.audio_bh = NULL;
+
+   world.spawns = NULL;
+   world.spawn_count = 0;
+
+   world.audio_things = NULL;
+   world.audio_things_count = 0;
+
+   world.logic_entities = NULL;
+   world.logic_entity_count = 0;
+
+   world.logic_actions = NULL;
+   world.logic_action_count = 0;
+
+   world.triggers = NULL;
+   world.trigger_count = 0;
+
+   world.nodes = NULL;
+   world.node_count = 0;
+
+   world.routes = NULL;
+   world.route_count = 0;
+
+   world.gates = NULL;
+   world.gate_count = 0;
+
+   world.collectors = NULL;
+   world.collector_count = 0;
+
+   world.instance_cache_count = 0;
+   world.water.enabled = 0;
+}
+
+VG_STATIC void world_load( const char *mdl_file )
+{
+   world_unload();
+
+   world.meta = mdl_load_full( world.dynamic_vgl, mdl_file );
+   vg_info( "Loading world: %s\n", mdl_file );
+
+   /* dynamic allocations */
+   world_ents_allocate();
+   world_routes_allocate();
+
+   /* meta processing */
+   world_routes_process();
+   world_entities_process();
+   
+   /* main bulk */
+   world_generate();
+   world_routes_generate();
+   world_post_process();
 }
 
 #endif /* WORLD_GEN_H */
index 9693e814dc9c0c07347fd03883f07905265bdc09..a73998a778888c9a573dedf582f89195783059b2 100644 (file)
@@ -19,7 +19,7 @@ vg_tex2d tex_alphatest = { .path = "textures/alphatest.qoi",
 vg_tex2d tex_graffiti = { .path = "textures/graffitibox.qoi",
                                  .flags = VG_TEXTURE_NEAREST };
 
-static void world_render_init(void)
+VG_STATIC void world_render_init(void)
 {
    vg_info( "Loading default world textures\n" );
 
@@ -33,32 +33,19 @@ static void world_render_init(void)
    vg_release_thread_sync();
 }
 
-static void world_render_free(void*_)
-{
-   vg_tex2d_free( (vg_tex2d *[]){ &tex_terrain_colours, 
-                                  &tex_terrain_noise,
-                                  &tex_alphatest,
-                                  &tex_graffiti }, 4 );
-}
-
-
-
-static void render_world_depth( m4x4f projection, m4x3f camera );
-
-
-
+VG_STATIC void render_world_depth( m4x4f projection, m4x3f camera );
 
 /*
  * Rendering
  */
 
-static void bind_terrain_textures(void)
+VG_STATIC void bind_terrain_textures(void)
 {
    vg_tex2d_bind( &tex_terrain_noise, 0 );
    vg_tex2d_bind( &tex_terrain_colours, 1 );
 }
 
-static void render_world_vb( m4x4f projection, v3f camera )
+VG_STATIC void render_world_vb( m4x4f projection, v3f camera )
 {
    m4x3f identity_matrix;
    m4x3_identity( identity_matrix );
@@ -73,21 +60,11 @@ static void render_world_vb( m4x4f projection, v3f camera )
    shader_vblend_uMdl( identity_matrix );
    shader_vblend_uCamera( camera );
 
-   scene_bind( &world.geo );
+   mesh_bind( &world.mesh_geo );
    mdl_draw_submesh( &world.sm_geo_vb );
-
-   mesh_bind( &world.cars );
-
-#if 0
-   for( int i=0; i<vg_list_size(world.van_man); i++ )
-   {
-      shader_vblend_uMdl( world.van_man[i].transform );
-      mdl_draw_submesh( &world.car_holden );
-   }
-#endif
 }
 
-static void render_world_alphatest( m4x4f projection, v3f camera )
+VG_STATIC void render_world_alphatest( m4x4f projection, v3f camera )
 {
    m4x3f identity_matrix;
    m4x3_identity( identity_matrix );
@@ -105,7 +82,7 @@ static void render_world_alphatest( m4x4f projection, v3f camera )
    shader_alphatest_uCamera( camera );
 
    glDisable(GL_CULL_FACE);
-   scene_bind( &world.foliage );
+   mesh_bind( &world.mesh_no_collide );
    mdl_draw_submesh( &world.sm_foliage_alphatest );
 
    vg_tex2d_bind( &tex_graffiti, 1 );
@@ -114,7 +91,7 @@ static void render_world_alphatest( m4x4f projection, v3f camera )
    glEnable(GL_CULL_FACE);
 }
 
-static void render_terrain( m4x4f projection, v3f camera )
+VG_STATIC void render_terrain( m4x4f projection, v3f camera )
 {
    m4x3f identity_matrix;
    m4x3_identity( identity_matrix );
@@ -129,20 +106,20 @@ static void render_terrain( m4x4f projection, v3f camera )
    shader_terrain_uMdl( identity_matrix );
    shader_terrain_uCamera( camera );
 
-   scene_bind( &world.geo );
+   mesh_bind( &world.mesh_geo );
    mdl_draw_submesh( &world.sm_terrain );
    mdl_draw_submesh( &world.sm_geo_std_oob );
    mdl_draw_submesh( &world.sm_geo_std );
    mdl_draw_submesh( &world.sm_subworld );
 
    /* TODO: Dont draw in reflection */
-   glDisable(GL_CULL_FACE);
-   scene_bind( &world.foliage );
+   glDisable( GL_CULL_FACE );
+   mesh_bind( &world.mesh_no_collide );
    mdl_draw_submesh( &world.sm_foliage_main );
-   glEnable(GL_CULL_FACE);
+   glEnable( GL_CULL_FACE );
 }
 
-static void render_lowerdome( m4x3f camera )
+VG_STATIC void render_lowerdome( m4x3f camera )
 {
    m4x4f projection, full;
    pipeline_projection( projection, 0.4f, 1000.0f );
@@ -165,7 +142,7 @@ static void render_lowerdome( m4x3f camera )
    mdl_draw_submesh( &world.dome_lower );
 }
 
-static void render_sky(m4x3f camera)
+VG_STATIC void render_sky(m4x3f camera)
 {
    m4x4f projection, full;
    pipeline_projection( projection, 0.4f, 1000.0f );
@@ -197,14 +174,14 @@ static void render_sky(m4x3f camera)
    glDepthMask( GL_TRUE );
 }
 
-static void render_world_gates( m4x4f projection, v3f playerco, m4x3f camera )
+VG_STATIC void render_world_gates( m4x4f projection, v3f playerco, m4x3f camera )
 {
    float closest = INFINITY;
    int   id = 0;
 
-   for( int i=0; i<world_routes.gate_count; i++ )
+   for( int i=0; i<world.gate_count; i++ )
    {
-      struct route_gate *rg = &world_routes.gates[i];
+      struct route_gate *rg = &world.gates[i];
       float dist = v3_dist2( rg->gate.co[0], camera[3] );
 
       if( dist < closest )
@@ -214,14 +191,14 @@ static void render_world_gates( m4x4f projection, v3f playerco, m4x3f camera )
       }
    }
 
-   render_gate( &world_routes.gates[id].gate, playerco, camera );
+   render_gate( &world.gates[id].gate, playerco, camera );
    v3_lerp( world.render_gate_pos, 
-            world_routes.gates[id].gate.co[0],
+            world.gates[id].gate.co[0],
             1.0f,
             world.render_gate_pos );
 }
 
-static void render_world( m4x4f projection, m4x3f camera )
+VG_STATIC void render_world( m4x4f projection, m4x3f camera )
 {
    render_sky( camera );
    render_world_routes( projection, camera[3] );
@@ -232,9 +209,9 @@ static void render_world( m4x4f projection, m4x3f camera )
    int closest = 0;
    float min_dist = INFINITY;
 
-   for( int i=0; i<world_routes.route_count; i++ )
+   for( int i=0; i<world.route_count; i++ )
    {
-      float dist = v3_dist2( world_routes.routes[i].scoreboard_transform[3],
+      float dist = v3_dist2( world.routes[i].scoreboard_transform[3],
                               camera[3] );
 
       if( dist < min_dist )
@@ -244,11 +221,11 @@ static void render_world( m4x4f projection, m4x3f camera )
       }
    }
 
-   sfd_render( &world.sfd.tester, projection, camera[3], 
-         world_routes.routes[closest].scoreboard_transform );
+   sfd_render( projection, camera[3], 
+         world.routes[closest].scoreboard_transform );
 }
 
-static void render_world_depth( m4x4f projection, m4x3f camera )
+VG_STATIC void render_world_depth( m4x4f projection, m4x3f camera )
 {
    m4x3f identity_matrix;
    m4x3_identity( identity_matrix );
@@ -258,8 +235,8 @@ static void render_world_depth( m4x4f projection, m4x3f camera )
    shader_gpos_uPv( projection );
    shader_gpos_uMdl( identity_matrix );
    
-   scene_bind( &world.geo );
-   scene_draw( &world.geo );
+   mesh_bind( &world.mesh_geo );
+   mesh_draw( &world.mesh_geo );
 
 #if 0
    glDisable(GL_CULL_FACE);
index e53f0920537bea10fe3eebcfd66c9855fcac5e21..312429579a0fcd021d9b3cfe966d85424f9e4919 100644 (file)
 
 enum route_special_type
 {
+   k_route_special_type_none = 0,
    k_route_special_type_gate = 1,
    k_route_special_type_collector = 2
 };
 
-static void debug_sbpath( struct route_node *rna, struct route_node *rnb,
+VG_STATIC void debug_sbpath( struct route_node *rna, struct route_node *rnb,
                           u32 colour, float xoffset )
 {
    v3f p0, h0, p1, h1, l, p;
@@ -48,7 +49,7 @@ 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
  */
-static u32 world_routes_get_path( u32 starter, u32 stack[64] )
+VG_STATIC u32 world_routes_get_path( u32 starter, u32 stack[64] )
 {
    u32 stack_i[64];
 
@@ -66,7 +67,7 @@ static u32 world_routes_get_path( u32 starter, u32 stack[64] )
          continue;
       }
 
-      struct route_node *rn = &world_routes.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] ++;
 
@@ -107,37 +108,35 @@ static u32 world_routes_get_path( u32 starter, u32 stack[64] )
 /*
  * Free a segment from the UI bar to be reused later
  */
-static void world_routes_ui_popfirst( u32 route )
+VG_STATIC void world_routes_ui_popfirst( struct route_ui_bar *pui )
 {
-   struct route *pr = &world_routes.routes[route];
-
-   if( pr->ui.segment_count )
+   if( pui->segment_count )
    {
-      pr->ui.segment_start ++;
+      pui->segment_start ++;
 
-      if( pr->ui.segment_start == 32 )
-         pr->ui.segment_start = 0;
+      if( pui->segment_start == 32 )
+         pui->segment_start = 0;
 
-      pr->ui.segment_count --;
+      pui->segment_count --;
    }
 }
 
 /*
  * Reset ui bar completely
  */
-static void world_routes_ui_clear( u32 route )
+VG_STATIC void world_routes_ui_clear( struct route_ui_bar *pui )
 {
-   struct route *pr = &world_routes.routes[route];
-   pr->ui.segment_start = (pr->ui.segment_start + pr->ui.segment_count) %
-                              k_max_ui_segments;
-   pr->ui.segment_count = 0;
+   pui->segment_start = (pui->segment_start + pui->segment_count) %
+                                                            k_max_ui_segments;
+   pui->segment_count = 0;
 }
 
 /*
  * 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 )
+VG_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);
@@ -147,41 +146,42 @@ static void world_routes_ui_split_indices( u32 s0, u32 count, u32 *c0, u32 *c1 )
  * 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 )
+VG_STATIC void world_routes_ui_set_indices( struct route_ui_bar *pui
+                                         u16 *indices, u32 count )
 {
    u32 c0, c1;
-   world_routes_ui_split_indices( pr->ui.indices_head, count, &c0, &c1 );
+   world_routes_ui_split_indices( pui->indices_head, count, &c0, &c1 );
 
-   glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pr->ui.ebo );
+   glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pui->ebo );
 
    if( c0 )
    {
-      glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, pr->ui.indices_head*sizeof(u16),
+      glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, pui->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;
+      pui->indices_head = c1;
    }
    else
-      pr->ui.indices_head += c0;
+      pui->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 )
+VG_STATIC u32 world_routes_ui_set_verts( struct route_ui_bar *pui,
+                                      v2f *verts, u32 count )
 {
-   if( pr->ui.vertex_head + count >= k_route_ui_max_verts )
-      pr->ui.vertex_head = 0;
+   if( pui->vertex_head + count >= k_route_ui_max_verts )
+      pui->vertex_head = 0;
 
-   u32 vert_start = pr->ui.vertex_head;
-   pr->ui.vertex_head += count;
+   u32 vert_start = pui->vertex_head;
+   pui->vertex_head += count;
 
-   glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
+   glBindBuffer( GL_ARRAY_BUFFER, pui->vbo );
    glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
                         sizeof(v2f)*count, verts );
 
@@ -192,12 +192,12 @@ static u32 world_routes_ui_set_verts( struct route *pr, v2f *verts, u32 count )
  * 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, 
+VG_STATIC u32 world_routes_ui_update_verts( struct route_ui_bar *pui,
                                          v2f *verts, u32 count )
 {
-   u32 vert_start = pr->ui.vertex_head-count;
+   u32 vert_start = pui->vertex_head-count;
 
-   glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
+   glBindBuffer( GL_ARRAY_BUFFER, pui->vbo );
    glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
                         sizeof(v2f)*count, verts );
 
@@ -207,28 +207,29 @@ static u32 world_routes_ui_update_verts( struct route *pr,
 /* 
  * Current/active segment of this UI bar 
  */
-static struct route_ui_segment *world_routes_ui_curseg( struct route *pr )
+VG_STATIC struct route_ui_segment *world_routes_ui_curseg( 
+      struct route_ui_bar *pui )
 {
-   u32 index = (pr->ui.segment_start+pr->ui.segment_count-1)%k_max_ui_segments;
-   return &pr->ui.segments[ index ];
+   u32 index = (pui->segment_start+pui->segment_count-1)%k_max_ui_segments;
+   return &pui->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 )
+VG_STATIC void world_routes_ui_newseg( u32 route )
 {
-   struct route *pr = &world_routes.routes[route];
+   struct route_ui_bar *pui = &world.ui_bars[route];
 
-   pr->ui.last_notch = 0.0;
+   pui->last_notch = 0.0;
    
-   glBindVertexArray( pr->ui.vao );
-   if( pr->ui.segment_count )
+   glBindVertexArray( pui->vao );
+   if( pui->segment_count )
    {
       float const k_gap_width = 1.0f;
 
-      struct route_ui_segment *cseg = world_routes_ui_curseg(pr);
+      struct route_ui_segment *cseg = world_routes_ui_curseg( pui );
       
       v2f verts[2];
       verts[0][0] =  cseg->length-k_gap_width;
@@ -236,11 +237,11 @@ static void world_routes_ui_newseg( u32 route )
       verts[1][0] =  cseg->length-k_gap_width;
       verts[1][1] = -0.5f;
 
-      world_routes_ui_update_verts( pr, verts, 2 );
+      world_routes_ui_update_verts( pui, verts, 2 );
    }
 
-   pr->ui.segment_count ++;
-   struct route_ui_segment *segment = world_routes_ui_curseg(pr);
+   pui->segment_count ++;
+   struct route_ui_segment *segment = world_routes_ui_curseg( pui );
    
    v2f verts[4];
    verts[0][0] =  0.0f;
@@ -252,7 +253,7 @@ static void world_routes_ui_newseg( u32 route )
    verts[3][0] =  0.0f;
    verts[3][1] = -0.5f;
 
-   u32 vert_start = world_routes_ui_set_verts( pr, verts, 4 );
+   u32 vert_start = world_routes_ui_set_verts( pui, verts, 4 );
 
    u16 indices[6];
    indices[0] = vert_start + 0;
@@ -264,19 +265,19 @@ static void world_routes_ui_newseg( u32 route )
 
    segment->vertex_start = vert_start;
    segment->vertex_count = 4;
-   segment->index_start  = pr->ui.indices_head;
+   segment->index_start  = pui->indices_head;
    segment->index_count  = 6;
    segment->notches      = 0;
 
-   world_routes_ui_set_indices( pr, indices, 6 );
+   world_routes_ui_set_indices( pui, indices, 6 );
 }
 
 /*
  * Extend the end of the bar 
  */
-static void world_routes_ui_updatetime( u32 route, float time )
+VG_STATIC void world_routes_ui_updatetime( u32 route, float time )
 {
-   struct route *pr = &world_routes.routes[route];
+   struct route_ui_bar *pui = &world.ui_bars[route];
 
    v2f verts[2];
    verts[0][0] =  time;
@@ -284,96 +285,16 @@ static void world_routes_ui_updatetime( u32 route, float time )
    verts[1][0] =  time;
    verts[1][1] = -0.5f;
 
-   u32 vert_start = pr->ui.vertex_head-2;
+   u32 vert_start = pui->vertex_head-2;
 
-   glBindVertexArray( pr->ui.vao );
-   world_routes_ui_update_verts( pr, verts, 2 );
+   glBindVertexArray( pui->vao );
+   world_routes_ui_update_verts( pui, verts, 2 );
 
-   struct route_ui_segment *cseg = world_routes_ui_curseg(pr);
+   struct route_ui_segment *cseg = world_routes_ui_curseg( pui );
    cseg->length = time;
 }
 
-/*
- * 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 )
-{
-   return; /* FIXME: Temporarily disabled */
-
-   struct route *pr = &world_routes.routes[route];
-
-   if( (time - pr->ui.last_notch) > 1.0 )
-   {
-      struct route_ui_segment *segment = world_routes_ui_curseg(pr);
-      if( segment->notches == k_max_ui_splits_per_segment )
-         return;
-
-      segment->notches ++;
-
-      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;
-
-      segment->vertex_count += 6;
-      segment->index_count  += 18;
-   }
-}
-
-static void world_routes_ui_draw_segment( struct route_ui_segment *segment )
+VG_STATIC void world_routes_ui_draw_segment( struct route_ui_segment *segment )
 {
    u32 c0, c1;
    world_routes_ui_split_indices( segment->index_start, 
@@ -388,28 +309,29 @@ static void world_routes_ui_draw_segment( struct route_ui_segment *segment )
 /*
  * Draws full bar at Y offset(offset).
  */
-static void world_routes_ui_draw( u32 route, v4f colour, float offset )
+VG_STATIC void world_routes_ui_draw( u32 route, v4f colour, float offset )
 {
    float const k_bar_height = 0.05f,
                k_bar_scale_x = 0.005f;
 
-   struct route *pr = &world_routes.routes[route];
+   struct route *pr = &world.routes[route];
+   struct route_ui_bar *pui = &world.ui_bars[route];
 
-   float cx = pr->ui.xpos;
+   float cx = pui->xpos;
 
    shader_routeui_use();
-   glBindVertexArray( pr->ui.vao );
+   glBindVertexArray( pui->vao );
 
-   float fade_amt = world_routes.time - pr->ui.fade_timer_start;
+   float fade_amt = world.time - pui->fade_timer_start;
    fade_amt = vg_clampf( fade_amt / 1.0f, 0.0f, 1.0f );
    
    float fade_block_size = 0.0f,
          main_block_size = 0.0f;
 
-   for( u32 i=0; i<pr->ui.fade_count; i++ )
+   for( u32 i=0; i<pui->fade_count; i++ )
    {
-      u32 j = (pr->ui.fade_start + i) % k_max_ui_segments;
-      struct route_ui_segment *segment = &pr->ui.segments[j];
+      u32 j = (pui->fade_start + i) % k_max_ui_segments;
+      struct route_ui_segment *segment = &pui->segments[j];
 
       fade_block_size += segment->length;
    }
@@ -421,7 +343,7 @@ 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_routes.time - world_routes.last_use) * (1.0/45.0),
+   float timer_delta = (world.time - world.last_use) * (1.0/45.0),
          timer_scale = 1.0f - vg_minf( timer_delta, 1.0f );
 
    /* 
@@ -432,10 +354,10 @@ static void world_routes_ui_draw( u32 route, v4f colour, float offset )
          base = -1.0f + (offset+0.5f)*k_bar_height * timer_scale;
 
    shader_routeui_uColour( fade_colour );
-   for( u32 i=0; i<pr->ui.fade_count; i++ )
+   for( u32 i=0; i<pui->fade_count; i++ )
    {
-      u32 j = (pr->ui.fade_start + i) % k_max_ui_segments;
-      struct route_ui_segment *segment = &pr->ui.segments[j];
+      u32 j = (pui->fade_start + i) % k_max_ui_segments;
+      struct route_ui_segment *segment = &pui->segments[j];
 
       shader_routeui_uOffset( (v4f){ cx*k_bar_scale_x, base,
                                      k_bar_scale_x, height } );
@@ -448,10 +370,10 @@ static void world_routes_ui_draw( u32 route, v4f colour, float offset )
     * Draw main bar 
     */
    shader_routeui_uColour( colour );
-   for( u32 i=0; i<pr->ui.segment_count; i++ )
+   for( u32 i=0; i<pui->segment_count; i++ )
    {
-      u32 j = (pr->ui.segment_start + i) % k_max_ui_segments;
-      struct route_ui_segment *segment = &pr->ui.segments[j];
+      u32 j = (pui->segment_start + i) % k_max_ui_segments;
+      struct route_ui_segment *segment = &pui->segments[j];
 
       shader_routeui_uOffset( (v4f){ cx*k_bar_scale_x, base,
                                      k_bar_scale_x, height } );
@@ -462,14 +384,14 @@ static void world_routes_ui_draw( u32 route, v4f colour, float offset )
       main_block_size += segment->length;
    }
 
-   pr->ui.xpos = vg_lerpf( pr->ui.xpos, -main_block_size * 0.5f, 0.03f );
+   pui->xpos = vg_lerpf( pui->xpos, -main_block_size * 0.5f, 0.03f );
 }
 
-static void world_routes_local_set_record( u32 route, double lap_time )
+VG_STATIC void world_routes_local_set_record( u32 route, double lap_time )
 {
    vg_success( "  NEW LAP TIME: %f\n", lap_time );
 
-   struct route *pr = &world_routes.routes[route];
+   struct route *pr = &world.routes[route];
 
    if( pr->track_id != 0xffffffff )
    {
@@ -507,12 +429,13 @@ 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)
  */
-static void world_routes_verify_run( u32 route )
+VG_STATIC void world_routes_verify_run( u32 route )
 {
-   struct route *pr = &world_routes.routes[route];
+   struct route *pr = &world.routes[route];
+   struct route_ui_bar *pui = &world.ui_bars[route];
 
    u32 stack[64];
-   u32 si = world_routes_get_path( world_routes.routes[route].start, stack );
+   u32 si = world_routes_get_path( world.routes[route].start, stack );
 
    /* 
     * we only care about gates that ref gates, so shuffle down the array
@@ -521,15 +444,15 @@ 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_routes.nodes[stack[i]];
+      struct route_node *inode = &world.nodes[stack[i]];
 
       if( inode->special_type == k_route_special_type_collector )
       {
-         timings[sj ++] = &world_routes.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_routes.gates[inode->special_id].timing;
+         timings[sj ++] = &world.gates[inode->special_id].timing;
       }
    }
    
@@ -543,10 +466,10 @@ static void world_routes_verify_run( u32 route )
    }
 
    vg_info( "== begin verification (%u) ==\n", route );
-   vg_info( "  current version: %u\n", world_routes.current_run_version );
+   vg_info( "  current version: %u\n", world.current_run_version );
 
    int verified = 0;
-   if( timings[begin]->version == world_routes.current_run_version )
+   if( timings[begin]->version == world.current_run_version )
       verified = 1;
 
    int valid_segment_count = 0;
@@ -576,24 +499,24 @@ static void world_routes_verify_run( u32 route )
       
       if( verified )
          vg_success( " [ %u %f ] %f\n", timings[j1]->time, 
-                                         timings[j1]->version, diff );
+                                        timings[j1]->version, diff );
       else
          vg_warn( " [ %u %f ]\n", timings[j1]->time, timings[j1]->version );
    }
 
-   pr->ui.fade_start = pr->ui.segment_start;
-   pr->ui.fade_count = 0;
-   pr->ui.fade_timer_start = world_routes.time;
+   pui->fade_start = pui->segment_start;
+   pui->fade_count = 0;
+   pui->fade_timer_start = world.time;
 
-   int orig_seg_count = pr->ui.segment_count;
+   int orig_seg_count = pui->segment_count;
 
    world_routes_ui_newseg( route );
 
    if( verified )
    {
       world_routes_local_set_record( route, lap_time );
-      world_routes_ui_popfirst(route);
-      pr->ui.fade_count ++;
+      world_routes_ui_popfirst( pui );
+      pui->fade_count ++;
    }
    else
       vg_info( "  ctime: %f\n", lap_time );
@@ -602,32 +525,33 @@ static void world_routes_verify_run( u32 route )
    int to_remove = orig_seg_count-valid_segment_count;
    for( int i=0; i<to_remove; i++ )
    {
-      world_routes_ui_popfirst(route);
-      pr->ui.fade_count ++;
+      world_routes_ui_popfirst( pui );
+      pui->fade_count ++;
    }
 
-   world_routes.routes[route].latest_pass = world_routes.time;
+   world.routes[route].latest_pass = world.time;
 }
 
 /*
  * When going through a gate this is called for bookkeeping purposes
  */
-static void world_routes_activate_gate( u32 id )
+VG_STATIC void world_routes_activate_gate( u32 id )
 {
-   struct route_gate *rg = &world_routes.gates[id];
-   struct route_node *pnode = &world_routes.nodes[rg->node_id],
-                     *pdest = &world_routes.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_routes.last_use = world_routes.time;
+   struct route_collector *rc = &world.collectors[ pdest->special_id ];
 
-   struct route_collector *rc = &world_routes.collectors[ pdest->special_id ];
+   world.active_gate = id;
+   rg->timing.version = world.current_run_version;
+   rg->timing.time = world.time;
 
-   world_routes.active_gate = id;
-   rg->timing.version = world_routes.current_run_version;
-   rg->timing.time = world_routes.time;
-   for( u32 i=0; i<world_routes.route_count; i++ )
+   for( u32 i=0; i<world.route_count; i++ )
    {
-      struct route *route = &world_routes.routes[i];
+      struct route *route = &world.routes[i];
       
       int was_active = route->active;
 
@@ -644,30 +568,31 @@ static void world_routes_activate_gate( u32 id )
 
       if( was_active && !route->active )
       {
-         route->ui.fade_start = route->ui.segment_start;
-         route->ui.fade_count = route->ui.segment_count;
-         route->ui.fade_timer_start = world_routes.time;
-         world_routes_ui_clear(i);
-
-         vg_success( "CLEARING -> %u %u \n", route->ui.fade_start,
-                                             route->ui.fade_count );
+         struct route_ui_bar *pui = &world.ui_bars[i];
+         pui->fade_start = pui->segment_start;
+         pui->fade_count = pui->segment_count;
+         pui->fade_timer_start = world.time;
+
+         world_routes_ui_clear( pui );
+         vg_success( "CLEARING -> %u %u \n", pui->fade_start,
+                                             pui->fade_count );
       }
    }
    
-   world_routes.current_run_version ++;
+   world.current_run_version ++;
 
-   rc->timing.version = world_routes.current_run_version;
-   rc->timing.time = world_routes.time;
-   world_routes.current_run_version ++;
+   rc->timing.version = world.current_run_version;
+   rc->timing.time = world.time;
+   world.current_run_version ++;
 }
 
 /*
  * Notify the UI system that we've reset the player
  */
-static void world_routes_notify_reset(void)
+VG_STATIC void world_routes_notify_reset(void)
 {
-   world_routes.rewind_from = world_routes.time;
-   world_routes.rewind_to = world_routes.last_use;
+   world.rewind_from = world.time;
+   world.rewind_to = world.last_use;
 
 #if 0
    for( int i=0; i<r->route_count; i++ )
@@ -681,25 +606,23 @@ static void world_routes_notify_reset(void)
 }
 
 /* Rewind between the saved points in time */
-static void world_routes_rollback_time( double t )
+VG_STATIC void world_routes_rollback_time( double t )
 {
-   world_routes.time = 
-      vg_lerp( world_routes.rewind_to, world_routes.rewind_from, t );
+   world.time = vg_lerp( world.rewind_to, world.rewind_from, t );
 }
 
 /* draw lines along the paths */
-static void world_routes_debug(void)
+VG_STATIC void world_routes_debug(void)
 {
-
-   for( int i=0; i<world_routes.node_count; i++ )
+   for( int i=0; i<world.node_count; i++ )
    {
-      struct route_node *rn = &world_routes.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_routes.route_count; i++ )
+   for( int i=0; i<world.route_count; i++ )
    {
-      struct route *route = &world_routes.routes[i];
+      struct route *route = &world.routes[i];
 
       u32 stack[64];
       u32 si = world_routes_get_path( route->start, stack );
@@ -713,39 +636,31 @@ static void world_routes_debug(void)
       {
          int sk = (sj+1)%si;
 
-         struct route_node *pj = &world_routes.nodes[stack[sj]],
-                           *pk = &world_routes.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_routes.node_count; i++ )
+   for( int i=0; i<world.node_count; i++ )
    {
-      struct route_node *ri = &world_routes.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_routes.nodes[ri->next[j]];
+            rj = &world.nodes[ri->next[j]];
             vg_line( ri->co, rj->co, 0x20ffffff );
          }
       }
    }
 }
 
-static void world_id_fixup( u32 *uid, mdl_header *mdl )
+VG_STATIC void world_routes_create_mesh( u32 route_id )
 {
-   if( *uid )
-      *uid = mdl_node_from_id( mdl, *uid )->sub_uid;
-   else
-      *uid = 0xffffffff;
-}
-
-static void world_routes_create_mesh( u32 route_id )
-{
-   struct route *route = &world_routes.routes[ route_id ];
+   struct route *route = &world.routes[ route_id ];
 
    u32 stack[64];
    u32 si = world_routes_get_path( route->start, stack );
@@ -756,8 +671,8 @@ static void world_routes_create_mesh( u32 route_id )
    {
       int sk=(sj+1)%si;
 
-      struct route_node *rnj = &world_routes.nodes[ stack[sj] ],
-                        *rnk = &world_routes.nodes[ stack[sk] ],
+      struct route_node *rnj = &world.nodes[ stack[sj] ],
+                        *rnk = &world.nodes[ stack[sk] ],
                         *rnl;
       
       if( rnj->special_type && rnk->special_type )
@@ -771,7 +686,7 @@ static void world_routes_create_mesh( u32 route_id )
 
       if( rnk->special_type )
       {
-         rnl = &world_routes.nodes[ rnk->next[0] ];
+         rnl = &world.nodes[ rnk->next[0] ];
          base_x1 = (float)rnl->ref_count*-0.5f + (float)rnl->current_refs;
       }
 
@@ -830,19 +745,19 @@ static void world_routes_create_mesh( u32 route_id )
             v2_zero( va.uv );
             v2_zero( vb.uv );
 
-            scene_push_vert( &world_routes.scene_lines, &va );
-            scene_push_vert( &world_routes.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_routes.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_routes.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_routes.scene_lines.vertex_count;
+            last_valid = world.scene_lines->vertex_count;
          }
          else
             last_valid = 0;
@@ -860,255 +775,286 @@ static void world_routes_create_mesh( u32 route_id )
       rnj->current_refs ++;
    }
 
-   scene_copy_slice( &world_routes.scene_lines, &route->sm );
+   scene_copy_slice( world.scene_lines, &route->sm );
 }
 
 /* 
  * Create the strips of colour that run through the world along course paths
  */
-static int world_routes_create_all_meshes(void)
+VG_STATIC void world_routes_generate(void)
 {
    vg_info( "Generating route meshes\n" );
+   world.scene_lines = scene_init( world.dynamic_vgl, 200000, 300000 );
 
-   scene_init( &world_routes.scene_lines );
-
-   for( u32 i=0; i<world_routes.route_count; i++ )
+   for( u32 i=0; i<world.route_count; i++ )
       world_routes_create_mesh( i );
 
    vg_acquire_thread_sync();
    {
-      scene_upload( &world_routes.scene_lines );
+      scene_upload( world.scene_lines, &world.mesh_route_lines );
+   }
+   vg_release_thread_sync();
+   vg_linear_del( world.dynamic_vgl, 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 )
+{
+   if( pnode->classtype == k_classtype_gate )
+   {
+      struct classtype_gate *inf = mdl_get_entdata( world.meta, pnode );
 
-      /* UI buffers */
-      for( int i=0; i<world_routes.route_count; i++ )
+      if( inf->target )
       {
-         /* OpenGL strips */
-         struct route *route = &world_routes.routes[i];
+         mdl_node *pother = mdl_node_from_id( world.meta, inf->target );
+         
+         if( pother->classtype == k_classtype_gate )
+         {
+            return k_route_special_type_gate;
+         }
+      }
 
-         glGenVertexArrays( 1, &route->ui.vao );
-         glGenBuffers( 1, &route->ui.vbo );
-         glGenBuffers( 1, &route->ui.ebo );
-         glBindVertexArray( route->ui.vao );
+      return k_route_special_type_collector;
+   }
 
-         size_t stride = sizeof(v2f);
+   return k_route_special_type_none;
+}
 
-         glBindBuffer( GL_ARRAY_BUFFER, route->ui.vbo );
-         glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride, 
-                       NULL, GL_DYNAMIC_DRAW );
+/* count entities and allocate correct amount of memory in advance */
+VG_STATIC void world_routes_allocate(void)
+{
+   vg_info( "Allocating routes\n" );
 
-         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 );
+   /* count */
+   u32 node_count       = 0,
+       route_count      = 0,
+       gate_count       = 0,
+       collector_count  = 0;
+   
+   for( int i=0; i<world.meta->info.node_count; i++ )
+   {
+      mdl_node *pnode = mdl_node_from_id( world.meta, i );
 
-         glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)0 );
-         glEnableVertexAttribArray( 0 );
-         VG_CHECK_GL_ERR();
+      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 );
+
+         if( type == k_route_special_type_gate )
+            gate_count ++;
+         else if( type == k_route_special_type_collector )
+            collector_count ++;
+
+         node_count ++;
+      }
+      else if( pnode->classtype == k_classtype_route )
+      {
+         route_count ++;
       }
    }
-   vg_release_thread_sync();
 
-   scene_free_offline_buffers( &world_routes.scene_lines );
-   return 1;
-}
+   /* allocate */
+   u32 node_size        = node_count      * sizeof(struct route_node),
+       route_size       = route_count     * sizeof(struct route),
+       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 );
+}
 
-static void world_routes_loadfrom( mdl_header *mdl )
+/* create node from mdl node */
+VG_STATIC struct route_node *world_routes_create_node( mdl_node *pnode )
 {
-   vg_info( "Initializing routes\n" );
+   struct route_node *rn = &world.nodes[ world.node_count ++ ];
 
-   world_routes.nodes = NULL;
-   world_routes.node_count = 0; 
-   world_routes.node_cap = 0; 
-   world_routes.routes = NULL;
-   world_routes.route_count = 0;
-   world_routes.route_cap = 0;
-   world_routes.gates = NULL;
-   world_routes.gate_count = 0;
-   world_routes.gate_cap = 0;
-
-   /* TODO Break this up */
-   for( int i=0; i<mdl->node_count; i++ )
-   {
-      mdl_node *pnode = mdl_node_from_id(mdl,i);
-      m4x3f transform;
+   m4x3f transform;
+   mdl_node_transform( pnode, transform );
 
-      if( pnode->classtype == k_classtype_route_node ||
-          pnode->classtype == k_classtype_gate )
-      {
-         mdl_node_transform( pnode, transform );
-         pnode->sub_uid = world_routes.node_count;
-         
-         world_routes.nodes = buffer_reserve( world_routes.nodes, 
-                                              world_routes.node_count, 
-                                              &world_routes.node_cap, 1,
-                                                sizeof( struct route_node ) );
-
-         struct route_node *rn = &world_routes.nodes[world_routes.node_count];
-
-         v3_copy( transform[0], rn->right );
-         v3_normalize( rn->right );
-         v3_copy( transform[1], rn->up );
-         v3_normalize( rn->up );
-         v3_muls( transform[2], -1.0f, rn->h );
-         v3_copy( transform[3], rn->co );
-         rn->ref_count = 0;
-         rn->current_refs = 0;
-         rn->special_type = 0;
-         rn->special_id = 0;
+   v3_copy( transform[3], rn->co );
+   v3_copy( transform[0], rn->right );
+   v3_copy( transform[1], rn->up );
+   v3_muls( transform[2], -1.0f, rn->h );
+   v3_normalize( rn->right );
+   v3_normalize( rn->up );
 
-         if( pnode->classtype == k_classtype_gate )
-         {
-            struct classtype_gate *inf = mdl_get_entdata( mdl, pnode );
+   rn->next[0] = 0xffffffff;
+   rn->next[1] = 0xffffffff;
 
-            /* H is later scaled based on link distance */
-            v3_normalize( rn->h );
-            rn->next[0] = inf->target;
-            rn->next[1] = 0;
+   rn->special_type = 0;
+   rn->special_id = 0;
+   rn->current_refs = 0;
+   rn->ref_count = 0;
 
-            /* TODO */
-            if( inf->target )
-            {
-               mdl_node *pother = mdl_node_from_id( mdl, inf->target );
-               
-               if( pother->classtype == k_classtype_gate )
-               {
-                  world_routes.gates = buffer_reserve( world_routes.gates, 
-                                                       world_routes.gate_count, 
-                                             &world_routes.gate_cap,
-                                             1, sizeof( struct route_gate ) );
-
-                  struct route_gate *rg = 
-                     &world_routes.gates[world_routes.gate_count];
-
-                  rg->node_id = world_routes.node_count;
-                  rg->timing.time = 0.0;
-                  rg->timing.version = 0;
-
-                  v3_copy( pnode->co,  rg->gate.co[0] );
-                  v3_copy( pother->co, rg->gate.co[1] );
-                  v4_copy( pnode->q,   rg->gate.q[0] );
-                  v4_copy( pother->q,  rg->gate.q[1] );
-                  v2_copy( inf->dims,  rg->gate.dims );
-
-                  gate_transform_update( &rg->gate );
-                  rn->special_type = k_route_special_type_gate;
-                  rn->special_id = world_routes.gate_count;
-
-                  world_routes.gate_count ++;
-               }
-            }
+   return rn;
+}
 
-            if( rn->special_type == 0 )
-            {
-               world_routes.collectors = buffer_reserve( 
-                     world_routes.collectors, 
-                     world_routes.collector_count, 
-                     &world_routes.collector_cap,
-                                          1, sizeof( struct route_collector ));
+/* retrieve the correct node id from mdl subuid */
+VG_STATIC u32 world_routes_get_subuid( u32 target )
+{
+   if( target == 0 )
+      return 0xffffffff;
+   else
+      return mdl_node_from_id( world.meta, target )->sub_uid;
+}
+
+#if 0
+VG_STATIC void world_id_fixup( u32 *uid, mdl_context *mdl )
+{
+   if( *uid )
+      *uid = mdl_node_from_id( mdl, *uid )->sub_uid;
+   else
+      *uid = 0xffffffff;
+}
+#endif
 
-               struct route_collector *rc = 
-                  &world_routes.collectors[world_routes.collector_count];
-               rc->timing.time = 0.0;
-               rc->timing.version = 0;
+/* process gate attachement onto node */
+VG_STATIC void world_routes_process_gate( struct route_node *rn, 
+                                          mdl_node *pnode )
+{
+   struct classtype_gate *inf = mdl_get_entdata( world.meta, pnode );
 
-               rn->special_type = k_route_special_type_collector;
-               rn->special_id = world_routes.collector_count;
+   /* H is later scaled based on link distance */
+   v3_normalize( rn->h );
 
-               world_routes.collector_count ++;
-            }
-         }
-         else
-         {
-            struct classtype_route_node *inf = mdl_get_entdata( mdl, pnode );
-            rn->next[0] = inf->target;
-            rn->next[1] = inf->target1;
-         }
+   rn->next[0] = world_routes_get_subuid( inf->target );
+   rn->next[1] = 0xffffffff;
+   rn->special_type = world_route_node_type( pnode );
 
-         world_routes.node_count ++;
-      }
-      else if( pnode->classtype == k_classtype_route )
-      {
-         struct classtype_route *inf = mdl_get_entdata( mdl, pnode );
-         world_routes.routes = buffer_reserve( world_routes.routes, 
-                                               world_routes.route_count, 
-                                               &world_routes.route_cap,
-                                     1, sizeof( struct route ) );
+   /* process gate type */
+   if( rn->special_type == k_route_special_type_gate )
+   {
+      mdl_node *pother = mdl_node_from_id( world.meta, inf->target );
+      
+      struct route_gate *rg = &world.gates[ world.gate_count ];
 
-         struct route *route = &world_routes.routes[world_routes.route_count];
-         memset( route, 0, sizeof(struct route) );
+      rg->node_id = world.node_count-1;
+      rg->timing.time = 0.0;
+      rg->timing.version = 0;
 
-         v3_copy( inf->colour, route->colour );
-         route->colour[3] = 1.0f;
+      v3_copy( pnode->co,  rg->gate.co[0] );
+      v3_copy( pother->co, rg->gate.co[1] );
+      v4_copy( pnode->q,   rg->gate.q[0] );
+      v4_copy( pother->q,  rg->gate.q[1] );
+      v2_copy( inf->dims,  rg->gate.dims );
 
+      gate_transform_update( &rg->gate );
+      rn->special_id = world.gate_count;
 
-         route->track_id = 0xffffffff;
-         for( u32 j=0; j<vg_list_size(track_infos); j++ )
-         {
-            if( !strcmp( mdl_pstr(mdl,pnode->pstr_name), track_infos[j].name ))
-            {
-               route->track_id = j;
-               break;
-            }
-         }
+      world.gate_count ++;
+   }
 
-         route->start = inf->id_start;
-         route->active = 0;
-         route->factive = 0.0f;
-         mdl_node_transform( pnode, route->scoreboard_transform );
-
-         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;
-         route->ui.fade_start = 0;
-         route->ui.fade_count = 0;
-         route->ui.fade_timer_start = 0.0;
-
-         world_routes.route_count ++;
-      }
+   /* process collector type */
+   else if( rn->special_type == k_route_special_type_collector )
+   {
+      struct route_collector *rc = 
+         &world.collectors[ world.collector_count ];
+
+      rc->timing.time = 0.0;
+      rc->timing.version = 0;
+
+      rn->special_id = world.collector_count;
+      world.collector_count ++;
    }
+   else
+      vg_fatal_exit_loop( "Invalid state" );
+}
 
-   /* 
-    * Apply correct system-local ids
-    */
-   for( int i=0; i<world_routes.node_count; i++ )
+/* create route from node description */
+VG_STATIC void world_routes_create_route( mdl_node *pnode )
+{
+   mdl_context *mdl = world.meta;
+
+   struct classtype_route *inf = mdl_get_entdata( mdl, pnode );
+   struct route *route = &world.routes[ world.route_count ];
+   memset( route, 0, sizeof(struct route) );
+
+   v3_copy( inf->colour, route->colour );
+   route->colour[3] = 1.0f;
+   route->track_id = 0xffffffff;
+
+   for( u32 j=0; j<vg_list_size(track_infos); j++ )
    {
-      struct route_node *rn = &world_routes.nodes[i];
-      
-      for( int j=0; j<2; j++ )
-         world_id_fixup( &rn->next[j], mdl );
+      if( !strcmp( mdl_pstr(mdl,pnode->pstr_name), track_infos[j].name ))
+      {
+         route->track_id = j;
+         break;
+      }
    }
 
-   for( int i=0; i<world_routes.route_count; i++ )
+   route->start = world_routes_get_subuid( 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 ];
+   pui->indices_head = k_route_ui_max_indices - 9;
+   pui->vertex_head = k_route_ui_max_verts - 200;
+   pui->segment_start = 0;
+   pui->segment_count = 0;
+   pui->last_notch = 0.0;
+   pui->fade_start = 0;
+   pui->fade_count = 0;
+   pui->fade_timer_start = 0.0;
+
+   world.route_count ++;
+}
+
+/* load all routes from model header */
+VG_STATIC void world_routes_process(void)
+{
+   vg_info( "Initializing routes\n" );
+   mdl_context *mdl = world.meta;
+
+   for( int i=0; i<mdl->info.node_count; i++ )
    {
-      struct route *route = &world_routes.routes[i];
-      world_id_fixup( &route->start, mdl );
+      mdl_node *pnode = mdl_node_from_id(mdl,i);
+
+      if( pnode->classtype == k_classtype_route_node ||
+          pnode->classtype == k_classtype_gate )
+      {
+         struct route_node *rn = world_routes_create_node( pnode );
+
+         if( pnode->classtype == k_classtype_gate )
+         {
+            world_routes_process_gate( 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 );
+         }
+      }
+      else if( pnode->classtype == k_classtype_route )
+      {
+         world_routes_create_route( pnode );
+      }
    }
 
    /*
     * Gather references
     */
-   for( int i=0; i<world_routes.route_count; i++ )
+   for( int i=0; i<world.route_count; i++ )
    {
-      struct route *route = &world_routes.routes[i];
+      struct route *route = &world.routes[i];
 
       u32 stack[64];
       u32 si = world_routes_get_path( route->start, stack );
 
       for( int sj=0; sj<si; sj++ )
       {
-         struct route_node *rn = &world_routes.nodes[ stack[sj] ];
+         struct route_node *rn = &world.nodes[ stack[sj] ];
          rn->route_ids[ rn->ref_count ++ ] = i;
 
          if( rn->ref_count > 4 )
             vg_warn( "Too many references on route node %i\n", i );
       }
    }
-
-   world_routes_create_all_meshes();
 }
 
 /* 
@@ -1117,42 +1063,67 @@ static void world_routes_loadfrom( mdl_header *mdl )
  * -----------------------------------------------------------------------------
  */
 
-static void world_routes_init(void)
+VG_STATIC void world_routes_init(void)
 {
-   world_routes.current_run_version = 2;
-   world_routes.time = RESET_MAX_TIME*2.0;
-   world_routes.last_use = 0.0;
+   world.current_run_version = 2;
+   world.time = RESET_MAX_TIME*2.0;
+   world.last_use = 0.0;
 
    shader_route_register();
    shader_routeui_register();
-}
 
-static void world_routes_free(void*_)
-{
-   vg_free( world_routes.nodes );
-   vg_free( world_routes.routes );
-   vg_free( world_routes.gates );
+   vg_acquire_thread_sync();
+   {
+      /* UI buffers */
+      for( int i=0; i<vg_list_size(world.ui_bars); i++ )
+      {
+         /* OpenGL strips */
+         struct route_ui_bar *pui = &world.ui_bars[i];
+
+         glGenVertexArrays( 1, &pui->vao );
+         glGenBuffers( 1, &pui->vbo );
+         glGenBuffers( 1, &pui->ebo );
+         glBindVertexArray( pui->vao );
+
+         size_t stride = sizeof(v2f);
+
+         glBindBuffer( GL_ARRAY_BUFFER, pui->vbo );
+         glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride, 
+                       NULL, GL_DYNAMIC_DRAW );
+
+         glBindVertexArray( pui->vao );
+         glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pui->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_ERR();
+      }
+   }
+   vg_release_thread_sync();
 }
 
-static void world_routes_update(void)
+VG_STATIC void world_routes_update(void)
 {
-   world_routes.time += vg.time_delta;
+   world.time += vg.time_delta;
 
-   for( int i=0; i<world_routes.route_count; i++ )
+   for( int i=0; i<world.route_count; i++ )
    {
-      struct route *route = &world_routes.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_routes.time - route->latest_pass );
+         world_routes_ui_updatetime(i, world.time - route->latest_pass );
       }
    }
 }
 
-static void bind_terrain_textures(void);
-static void render_world_routes( m4x4f projection, v3f camera )
+VG_STATIC void bind_terrain_textures(void);
+VG_STATIC void render_world_routes( m4x4f projection, v3f camera )
 {
    m4x3f identity_matrix;
    m4x3_identity( identity_matrix );
@@ -1166,11 +1137,11 @@ static void render_world_routes( m4x4f projection, v3f camera )
    shader_route_uMdl( identity_matrix );
    shader_route_uCamera( camera );
 
-   scene_bind( &world_routes.scene_lines );
+   mesh_bind( &world.mesh_route_lines );
 
-   for( int i=0; i<world_routes.route_count; i++ )
+   for( int i=0; i<world.route_count; i++ )
    {
-      struct route *route = &world_routes.routes[i];
+      struct route *route = &world.routes[i];
 
       v4f colour;
       v3_lerp( (v3f){0.7f,0.7f,0.7f}, route->colour, route->factive, colour );
@@ -1181,16 +1152,16 @@ static void render_world_routes( m4x4f projection, v3f camera )
    }
 }
 
-static void render_world_routes_ui(void)
+VG_STATIC void render_world_routes_ui(void)
 {
    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_routes.route_count; i++ )
+   for( int i=0; i<world.route_count; i++ )
    {
-      struct route *route = &world_routes.routes[i];
+      struct route *route = &world.routes[i];
       world_routes_ui_draw( i, route->colour, active_offset );
       active_offset += route->factive;
    }
index 0f8e3746d567798e10d847fa4adfb4f3d8e7f645..a83fe0a92359c4b8cb9cb885fb30b9dc360474d2 100644 (file)
@@ -53,43 +53,37 @@ float sfd_encode_glyph( char c )
    return (float)value;
 }
 
-static void sfd_encode( struct sfd_instance *display, u32 row, const char *str )
+VG_STATIC void sfd_encode( u32 row, const char *str )
 {
    int end=0;
-   u32 row_h = display->h-1-row;
+   u32 row_h = world.sfd.h -1 -row;
 
-   for( int i=0; i<display->w; i++ )
+   for( int i=0; i<world.sfd.w; i++ )
    {
       if( end )
       {
-         display->buffer[display->w*row_h + i] = 0.0f;
+         world.sfd.buffer[world.sfd.w*row_h + i] = 0.0f;
       }
       else
       {
          if( !str[i] )
             end = 1;
 
-         display->buffer[display->w*row_h + i] = sfd_encode_glyph( str[i] );
+         world.sfd.buffer[world.sfd.w*row_h + i] = sfd_encode_glyph( str[i] );
       }
    }
 }
 
-static void sfd_new( struct sfd_instance *display, u32 w, u32 h )
+VG_STATIC void sfd_init( u32 w, u32 h )
 {
-   display->w = w;
-   display->h = h;
-   display->buffer = vg_alloc( w*h*sizeof(float)*2 );
-
-   for( int i=0; i<w*h*2; i++ )
-      display->buffer[i] = 0.0f;
 }
 
-static void sfd_update( struct sfd_instance *display )
+VG_STATIC void sfd_update(void)
 {
-   for( int i=0; i<display->w*display->h; i++ )
+   for( int i=0; i<world.sfd.w*world.sfd.h; i++ )
    {
-      float *target = &display->buffer[i],
-            *cur = target+display->w*display->h;
+      float *target = &world.sfd.buffer[i*2+0],
+            *cur =    &world.sfd.buffer[i*2+1];
       
       float const rate = vg.time_delta * 15.2313131414f;
       float d1 = *target-*cur;
@@ -105,11 +99,9 @@ static void sfd_update( struct sfd_instance *display )
    }
 }
 
-static void sfd_render( struct sfd_instance *display, 
-                        m4x4f projection, v3f camera, m4x3f transform )
+VG_STATIC void sfd_render( m4x4f projection, v3f camera, m4x3f transform )
 {
-   struct subworld_sfd *sfd = &world.sfd;
-   scene_bind( &sfd->mesh );
+   mesh_bind( &world.sfd.mesh_display );
 
    shader_scoretext_use();
    shader_scoretext_uTexGarbage(0);
@@ -122,13 +114,13 @@ static void sfd_render( struct sfd_instance *display,
    shader_scoretext_uMdl( transform );
    shader_scoretext_uCamera( camera );
 
-   for( int y=0;y<display->h; y++ )
+   for( int y=0;y<world.sfd.h; y++ )
    {
-      for( int x=0; x<display->w; x++ )
+      for( int x=0; x<world.sfd.w; x++ )
       {
-         float value = display->buffer[display->h*display->w+y*display->w+x];
+         float value = world.sfd.buffer[(y*world.sfd.w+x)*2+1];
          shader_scoretext_uInfo( (v3f){ x,y, value } );
-         scene_draw( &sfd->mesh );
+         mesh_draw( &world.sfd.mesh_display );
       }
    }
 
@@ -142,54 +134,53 @@ static void sfd_render( struct sfd_instance *display,
    shader_vblend_uMdl( transform );
    shader_vblend_uCamera( camera );
    
-   mesh_bind( &sfd->temp );
-   mesh_draw( &sfd->temp );
+   mesh_bind( &world.sfd.mesh_base );
+   mesh_draw( &world.sfd.mesh_base );
 }
 
-static int world_sfd_test( int argc, const char *argv[] )
+VG_STATIC int world_sfd_test( int argc, const char *argv[] )
 {
-   struct subworld_sfd *sfd = &world.sfd;
-
    if( argc == 2 )
    {
-      int row = vg_min(vg_max(atoi(argv[0]),0),sfd->tester.h);
-      sfd_encode( &sfd->tester, row, argv[1] );
+      int row = vg_min( vg_max(atoi(argv[0]),0), world.sfd.h);
+      sfd_encode( row, argv[1] );
    }
 
    return 0;
 }
 
-static void world_sfd_init(void)
+VG_STATIC void world_sfd_init(void)
 {
    vg_info( "world_sfd_init\n" );
    shader_scoretext_register();
 
-   struct subworld_sfd *sfd = &world.sfd;
-
        vg_function_push( (struct vg_cmd){
                .name = "sfd",
                .function = world_sfd_test
        });
 
-   mdl_header *mboard = mdl_load( "models/rs_scoretext.mdl" );
-   scene_init( &sfd->mesh );
+   vg_linear_clear( vg_mem.scratch );
+   mdl_context *mboard = 
+      mdl_load_full( vg_mem.scratch, "models/rs_scoretext.mdl" );
+
+   scene *sc = scene_init( vg_mem.scratch, 3000, 8000 );
 
    mdl_node *pn_backer = mdl_node_from_name( mboard, "backer" );
-   mdl_submesh *backer = mdl_submesh_from_id( mboard, pn_backer->submesh_start);
+   mdl_submesh *backer = &mboard->submesh_buffer[ pn_backer->submesh_start ];
    mdl_node *pn_card = mdl_node_from_name( mboard, "score_card" );
-   mdl_submesh *card = mdl_submesh_from_id( mboard, pn_card->submesh_start );
+   mdl_submesh *card = &mboard->submesh_buffer[ pn_card->submesh_start ];
 
    m4x3f identity;
    m4x3_identity( identity );
 
    for( int i=4;i<6;i++ )
    {
-      u32 vert_start = sfd->mesh.vertex_count;
-      scene_add_submesh( &sfd->mesh, mboard, card, identity );
+      u32 vert_start = sc->vertex_count;
+      scene_add_submesh( sc, mboard, card, identity );
 
       for( int j=0; j<card->vertex_count; j++ )
       {
-         mdl_vert *vert = &sfd->mesh.verts[ vert_start+j ];
+         mdl_vert *vert = &sc->arrvertices[ vert_start+j ];
 
          float const k_glyph_uvw = 1.0f/64.0f;
          vert->uv[0] -= k_glyph_uvw * (float)(i-4);
@@ -200,23 +191,22 @@ static void world_sfd_init(void)
 
    vg_acquire_thread_sync();
    {
-      vg_tex2d_init( (vg_tex2d *[]){ &tex_scoretext }, 1 );
+      scene_upload( sc, &world.sfd.mesh_display );
+      mdl_unpack_submesh( mboard, &world.sfd.mesh_base, backer );
 
-      scene_upload( &sfd->mesh );
-      mdl_unpack_submesh( mboard, &sfd->temp, backer );
+      vg_tex2d_init( (vg_tex2d *[]){ &tex_scoretext }, 1 );
    }
    vg_release_thread_sync();
 
-   scene_free_offline_buffers( &sfd->mesh );
-   sfd_new( &sfd->tester, 27, 13 );
-   vg_free( mboard );
-}
+   int w = 27,
+       h = 13;
 
+   world.sfd.w = w;
+   world.sfd.h = h;
+   world.sfd.buffer = vg_linear_alloc( vg_mem.rtmemory, 2*w*h*sizeof(float) );
 
-static void world_sfd_free(void *_)
-{
-   mesh_free( &world.sfd.mesh.mesh );
-   vg_tex2d_free( (vg_tex2d *[]){ &tex_scoretext }, 1 );
+   for( int i=0; i<w*h*2; i++ )
+      world.sfd.buffer[i] = 0.0f;
 }
 
 #endif /* SFD_H */
index b799e4e56ed9615c536a3ed1ab84e0e17d3cdf79..656f1b2350afa588117d1a80f8a47a3dddab1093 100644 (file)
 
 vg_tex2d tex_water_surf = { .path = "textures/water_surf.qoi" };
 
-static struct
-{
-   struct framebuffer fbreflect, fbdepth;
-   glmesh mdl;
-
-   boxf depthbounds;
-   int depth_computed;
-
-   float height;
-   int enabled;
-   v4f plane;
-}
-wrender =
-{
-   .fbreflect = { .format = GL_RGB,  .div = 3 },
-   .fbdepth   = { .format = GL_RGBA, .div = 4 }
-};
-
-static void world_water_init(void)
+VG_STATIC void world_water_init(void)
 {
    vg_info( "world_water_init\n" );
    shader_water_register();
-   
+
    vg_acquire_thread_sync();
    {
-      fb_init( &wrender.fbreflect );
-      fb_init( &wrender.fbdepth );
+      world.water.fbreflect.format  = GL_RGB;
+      world.water.fbreflect.div     = 3;
+      world.water.fbdepth.format    = GL_RGBA;
+      world.water.fbdepth.div       = 4;
+   
+      fb_init( &world.water.fbreflect );
+      fb_init( &world.water.fbdepth );
 
       vg_tex2d_init( (vg_tex2d *[]){&tex_water_surf}, 1 );
-      vg_success( "done\n" );
    }
    vg_release_thread_sync();
-}
 
-static void world_water_free(void *_)
-{
-   vg_tex2d_free( (vg_tex2d *[]){&tex_water_surf}, 1 );
-   fb_free( &wrender.fbreflect );
-   fb_free( &wrender.fbdepth );
+   vg_success( "done\n" );
 }
 
-static void water_fb_resize(void)
+VG_STATIC void water_fb_resize(void)
 {
-   if( !wrender.enabled )
+   if( !world.water.enabled )
       return;
    
-   fb_resize( &wrender.fbreflect );
-   fb_resize( &wrender.fbdepth );
+   fb_resize( &world.water.fbreflect );
+   fb_resize( &world.water.fbdepth );
 }
 
-static void water_set_surface( glmesh *surf, float height )
+VG_STATIC void water_set_surface( float height )
 {
-   wrender.mdl = *surf;
-   wrender.height = height;
-   wrender.enabled = 1;
-
-   v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, wrender.plane );
+   world.water.height = height;
+   v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, world.water.plane );
 }
 
-static void render_water_texture( m4x3f camera )
+VG_STATIC void render_water_texture( m4x3f camera )
 {
-   if( !wrender.enabled )
+   if( !world.water.enabled )
       return;
 
    /* Draw reflection buffa */
-   fb_use( &wrender.fbreflect );
+   fb_use( &world.water.fbreflect );
    glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
 
    m4x3f new_cam, inverse;
    v3_copy( camera[3], new_cam[3] );
-   new_cam[3][1] -= 2.0f * (camera[3][1] - wrender.height);
+   new_cam[3][1] -= 2.0f * (camera[3][1] - world.water.height);
 
    m3x3f flip;
    m3x3_identity( flip );
@@ -101,7 +79,7 @@ static void render_water_texture( m4x3f camera )
    m4x3_invert_affine( new_cam, inverse );
    m4x3_expand( inverse, view );
 
-   v4f clippa = { 0.0f, 1.0f, 0.0f, wrender.height-0.1f };
+   v4f clippa = { 0.0f, 1.0f, 0.0f, world.water.height-0.1f };
    m4x3_mulp( inverse, clippa, clippa );
    clippa[3] *= -1.0f;
 
@@ -119,14 +97,14 @@ static void render_water_texture( m4x3f camera )
 
 
    /* Draw beneath texture */
-   fb_use( &wrender.fbdepth );
+   fb_use( &world.water.fbdepth );
    glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
 
    m4x3_invert_affine( camera, inverse );
    m4x3_expand( inverse, view );
 
-   float bias = -(camera[3][1]-wrender.height)*0.1f;
-   v4f clippb = { 0.0f, -1.0f, 0.0f, -(wrender.height) + bias };
+   float bias = -(camera[3][1]-world.water.height)*0.1f;
+   v4f clippb = { 0.0f, -1.0f, 0.0f, -(world.water.height) + bias };
    m4x3_mulp( inverse, clippb, clippb );
    clippb[3] *= -1.0f;
 
@@ -142,15 +120,15 @@ static void render_water_texture( m4x3f camera )
    glViewport( 0, 0, vg.window_x, vg.window_y );
 }
 
-static void render_water_surface( m4x4f pv, m4x3f camera )
+VG_STATIC void render_water_surface( m4x4f pv, m4x3f camera )
 {
-   if( !wrender.enabled )
+   if( !world.water.enabled )
       return;
 
    /* Draw surface */
    shader_water_use();
    
-   fb_bindtex( &wrender.fbreflect, 0 );
+   fb_bindtex( &world.water.fbreflect, 0 );
    shader_water_uTexMain( 0 );
 
    vg_tex2d_bind( &tex_water_surf, 1 );
@@ -161,17 +139,17 @@ static void render_water_surface( m4x4f pv, m4x3f camera )
 
    shader_link_standard_ub( _shader_water.id, 2 );
 
-   fb_bindtex( &wrender.fbdepth, 3 );
+   fb_bindtex( &world.water.fbdepth, 3 );
    shader_water_uTexBack( 3 );
-   shader_water_uTime( world_routes.time );
+   shader_water_uTime( world.time );
    shader_water_uCamera( camera[3] );
-   shader_water_uSurfaceY( wrender.height );
+   shader_water_uSurfaceY( world.water.height );
 
    shader_water_uPv( pv );
 
    m4x3f full;
    m4x3_identity( full );
-   full[3][1] = wrender.height;
+   full[3][1] = world.water.height;
 
    shader_water_uMdl( full );
 
@@ -179,8 +157,8 @@ static void render_water_surface( m4x4f pv, m4x3f camera )
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glBlendEquation(GL_FUNC_ADD);
 
-   mesh_bind( &wrender.mdl );
-   mesh_draw( &wrender.mdl );
+   mesh_bind( &world.mesh_water );
+   mesh_draw( &world.mesh_water );
 
    glDisable(GL_BLEND);
 }