modular stuffs
authorhgn <hgodden00@gmail.com>
Sat, 22 Apr 2023 03:39:44 +0000 (04:39 +0100)
committerhgn <hgodden00@gmail.com>
Sat, 22 Apr 2023 03:39:44 +0000 (04:39 +0100)
21 files changed:
blender_export.py
build.c
entity.h
maps_src/mp_spawn.mdl
model.h
models_src/board_fish.mdl [new file with mode: 0644]
models_src/ch_jordan.mdl
models_src/ch_new.mdl
models_src/ch_outlaw.mdl
player.c
player.h
player_api.h
player_model.h
player_ragdoll.c [new file with mode: 0644]
player_ragdoll.h
player_render.c [new file with mode: 0644]
player_render.h [new file with mode: 0644]
player_skate.c
shaders/model_board_view.h [new file with mode: 0644]
skaterift.c
world_routes.h

index c8639711a06a352c4a852945ea929c22e693aecd..a7698e9bf2fa6f33334d1d2d31de574286b6c873 100644 (file)
@@ -17,17 +17,31 @@ bl_info = {
    "category":"Import/Export",
 }
 
-sr_entity_alias = {
-   'ent_gate': 1,
-   'ent_spawn': 2,
-   'ent_route_node': 3,
-   'ent_route': 4,
-   'ent_water': 5,
-   'ent_volume': 6,
-   'ent_audio': 7,
-   'ent_marker': 8,
-   'ent_glyph': 9
-}
+sr_entity_list = [
+   ('none',             'None',           '', 0  ),
+   ('ent_gate',         'Gate',           '', 1  ),
+   ('ent_spawn',        'Spawn Point',    '', 2  ),
+   ('ent_route_node',   'Routing Path',   '', 3  ),
+   ('ent_route',        'Skate Course',   '', 4  ),
+   ('ent_water',        'Water Surface',  '', 5  ),
+   ('ent_volume',       'Volume/Trigger', '', 6  ),
+   ('ent_audio',        'Audio',          '', 7  ),
+   ('ent_marker',       'Marker',         '', 8  ),
+   ('ent_font',         'Font',           '', 9  ),
+   ('ent_font_variant', 'Font:Variant',   '', 10 ),
+   ('ent_traffic',      'Traffic Model',  '', 11 ),
+]
+
+def get_entity_enum_id( alias ):
+#{
+   for et in sr_entity_list:#{
+      if et[0] == alias:#{
+         return et[3]
+      #}
+   #}
+
+   return 0
+#}
 
 class mdl_vert(Structure):              # 48 bytes. Quite large. Could compress
 #{                                      # the normals and uvs to i16s. Not an
@@ -107,7 +121,7 @@ class mdl_mesh(Structure):
                ("submesh_start",c_uint32),
                ("submesh_count",c_uint32),
                ("pstr_name",c_uint32),
-               ("flags",c_uint32),
+               ("entity_id",c_uint32),
                ("armature_id",c_uint32)]
 #}
 
@@ -121,7 +135,7 @@ class mdl_file(Structure):
 class mdl_texture(Structure):
 #{
    _fields_ = [("file",mdl_file),
-               ("type",c_uint32)]
+               ("glname",c_uint32)]
 #}
 
 class mdl_array(Structure):
@@ -538,7 +552,7 @@ def sr_compile_texture( img ):
    texture_index = (len(sr_compile.texture_data)//sizeof(mdl_texture)) +1
 
    tex = mdl_texture()
-   tex.type = 0
+   tex.glname = 0
 
    if sr_compile.pack_textures:#{
       filedata = qoi_encode( img )
@@ -565,12 +579,17 @@ def sr_compile_material( mat ):
    
    flags = 0x00
    if mat.SR_data.collision:#{
-      flags |= 0x2
-      if mat.SR_data.skate_surface: flags |= 0x1
-      if mat.SR_data.grind_surface: flags |= (0x8|0x1)
+      flags |= 0x2 # collision flag
+      if (mat.SR_data.shader != 'invisible') and \
+         (mat.SR_data.shader != 'boundary'):#{
+         if mat.SR_data.skate_surface: flags |= 0x1
+         if mat.SR_data.grow_grass: flags |= 0x4
+         if mat.SR_data.grind_surface: flags |= 0x8
+      #}
+      if mat.SR_data.shader == 'invisible': flags |= 0x10
+      if mat.SR_data.shader == 'boundary': flags |= (0x10|0x20)
    #}
 
-   if mat.SR_data.grow_grass: flags |= 0x4
    m.flags = flags
 
    m.surface_prop = int(mat.SR_data.surface_prop)
@@ -608,6 +627,14 @@ def sr_compile_material( mat ):
       m.colour1[2] = pow( mat.SR_data.ocean_colour[2], 1.0/2.2 )
       m.colour1[3] = 1.0
    #}
+
+   if mat.SR_data.shader == 'invisible':#{
+      m.shader = 5
+   #}
+
+   if mat.SR_data.shader == 'boundary':#{
+      m.shader = 6
+   #}
    
    inf = material_info( mat )
 
@@ -642,7 +669,16 @@ def sr_compile_mesh( obj ):
    node=mdl_mesh()
    compile_obj_transform(obj, node.transform)
    node.pstr_name = sr_compile_string(obj.name)
-   node.flags = 0
+   ent_type = obj_ent_type( obj )
+
+   node.entity_id = 0
+
+   if ent_type != 'none':#{
+      ent_id_lwr = sr_compile.entity_ids[obj.name]
+      ent_id_upr = get_entity_enum_id( obj_ent_type(obj) )
+      node.entity_id = (ent_id_upr << 16) | ent_id_lwr
+   #}
+   print( node.entity_id )
 
    can_use_cache = True
    armature = None
@@ -656,7 +692,6 @@ def sr_compile_mesh( obj ):
       #}
 
       if mod.type == 'ARMATURE': #{
-         node.flags = 1
          armature = mod.object
          rig_weight_groups = \
                ['0 [ROOT]']+[_.name for _ in sr_armature_bones(mod.object)]
@@ -1400,7 +1435,7 @@ def sr_compile( collection ):
 
             if obj_data.target:#{
                target = obj_data.target
-               volume.target.type = sr_entity_alias[obj_ent_type(target)]
+               volume.target.type = get_entity_enum_id( obj_ent_type(target) )
                volume.target.index = sr_compile.entity_ids[ target.name ]
             #}
 
@@ -1866,9 +1901,15 @@ class SR_MATERIAL_PANEL(bpy.types.Panel):
       _.layout.prop( active_mat.SR_data, "collision" )
 
       if active_mat.SR_data.collision:#{
-         _.layout.prop( active_mat.SR_data, "skate_surface" )
-         _.layout.prop( active_mat.SR_data, "grind_surface" )
-         _.layout.prop( active_mat.SR_data, "grow_grass" )
+         box = _.layout.box()
+         row = box.row()
+
+         if (active_mat.SR_data.shader != 'invisible') and \
+            (active_mat.SR_data.shader != 'boundary'):#{
+            row.prop( active_mat.SR_data, "skate_surface" )
+            row.prop( active_mat.SR_data, "grind_surface" )
+            row.prop( active_mat.SR_data, "grow_grass" )
+         #}
       #}
 
       if active_mat.SR_data.shader == "terrain_blend":#{
@@ -2449,6 +2490,13 @@ class SR_OBJECT_ENT_FONT(bpy.types.PropertyGroup):
    #}
 #}
 
+class SR_OBJECT_ENT_TRAFFIC(bpy.types.PropertyGroup):
+#{
+   track: bpy.props.PointerProperty(\
+               type=bpy.types.Object, name='track', \
+               poll=lambda self,obj: sr_filter_ent_type(obj,['ent_route_node']))
+#}
+
 class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
 #{
    ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE)
@@ -2459,19 +2507,10 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
    ent_marker: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_MARKER)
    ent_glyph: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GLYPH)
    ent_font: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_FONT)
+   ent_traffic: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_TRAFFIC)
    ent_type: bpy.props.EnumProperty(
       name="Type",
-      items=[('none', 'None', '', 0),
-             ('ent_gate','Gate','', 1),
-             ('ent_spawn','Spawn','', 2),
-             ('ent_route_node', 'Route Node', '', 3 ),
-             ('ent_route', 'Route', '', 4),
-             ('ent_water', 'Water Surface', '', 5),
-             ('ent_volume', 'Volume', '', 6 ),
-             ('ent_audio', 'Audio Files', '', 7),
-             ('ent_marker', 'Marker', '', 8),
-             ('ent_font', 'Font', '', 9),
-             ('ent_font_variant','Font variant','',10)],
+      items=sr_entity_list,
       update=sr_on_type_change
    )
 #}
@@ -2540,7 +2579,9 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup):
       ('standard_cutout', "standard_cutout", ''),
       ('terrain_blend', "terrain_blend", ''),
       ('vertex_blend', "vertex_blend", ''),
-      ('water',"water",'')
+      ('water',"water",''),
+      ('invisible','Invisible',''),
+      ('boundary','Boundary','')
       ])
 
    surface_prop: bpy.props.EnumProperty(
@@ -2556,17 +2597,17 @@ class SR_MATERIAL_PROPERTIES(bpy.types.PropertyGroup):
    collision: bpy.props.BoolProperty( \
          name="Collisions Enabled",\
          default=True,\
-         description = "Can the player collide with this material"\
+         description = "Can the player collide with this material?"\
    )
    skate_surface: bpy.props.BoolProperty( \
-         name="Skate Surface", \
+         name="Skate Target", \
          default=True,\
          description = "Should the game try to target this surface?" \
    )
    grind_surface: bpy.props.BoolProperty( \
-         name="Grind Surface", \
-         default=False,\
-         description = "Grind face?" \
+         name="Grindable", \
+         default=True,\
+         description = "Can you grind on this surface?" \
    )
    grow_grass: bpy.props.BoolProperty( \
          name="Grow Grass", \
@@ -3450,7 +3491,7 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\
             SR_OBJECT_ENT_FONT_VARIANT,
             SR_OBJECT_ENT_GLYPH_ENTRY,\
             SR_UL_FONT_VARIANT_LIST,SR_UL_FONT_GLYPH_LIST,\
-            SR_OBJECT_ENT_FONT,\
+            SR_OBJECT_ENT_FONT,SR_OBJECT_ENT_TRAFFIC,\
             \
             SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, 
             SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \
diff --git a/build.c b/build.c
index 73ba1b7a2c2952be5c6302b9227f87c207afd2f3..fd0a1026ea3b165947334236b76e115c3a6793a0 100644 (file)
--- a/build.c
+++ b/build.c
@@ -132,6 +132,7 @@ void build_shaders(void)
    _S( "model_sky",            "model.vs",         "model_sky.fs" );
    _S( "model_menu",           "model.vs",         "model_menu.fs" );
    _S( "model_character_view", "model_skinned.vs", "model_character_view.fs" );
+   _S( "model_board_view",     "model.vs",         "model_character_view.fs" );
    _S( "model_gate",           "model_gate.vs",    "model_gate_lq.fs" );
    _S( "model_font",           "model_font.vs",    "model_font.fs" );
 
index 9bfd04aab3cb7da7328cc0e86c5f4591f3574a02..25fd63ff55a85134ea295c5ed4c2b95b92a32b52 100644 (file)
--- a/entity.h
+++ b/entity.h
@@ -23,16 +23,30 @@ typedef struct ent_font_variant ent_font_variant;
 typedef struct ent_glyph ent_glyph;
 
 enum entity_alias{
-   k_ent_gate = 1,
-   k_ent_spawn = 2,
-   k_ent_route_node = 3,
-   k_ent_route = 4,
-   k_ent_water = 5,
-   k_ent_volume = 6,
-   k_ent_audio = 7,
-   k_ent_marker = 8
+   k_ent_none        = 0,
+   k_ent_gate        = 1,
+   k_ent_spawn       = 2,
+   k_ent_route_node  = 3,
+   k_ent_route       = 4,
+   k_ent_water       = 5,
+   k_ent_volume      = 6,
+   k_ent_audio       = 7,
+   k_ent_marker      = 8,
+   k_ent_font        = 9,
+   k_ent_font_variant= 10,
+   k_ent_traffic     = 11
 };
 
+static u32 mdl_entity_id_type( u32 entity_id )
+{
+   return (entity_id & 0xffff0000) >> 16;
+}
+
+static u32 mdl_entity_id_id( u32 entity_id )
+{
+   return entity_id & 0x0000ffff;
+}
+
 struct ent_index{
    u32 type,
        index;
index 2d9a7d2ba76f3652905afdd5a433b1fb677f9e46..8df5081721f76e4eea8cb7bdeed79cdf25dc5dc5 100644 (file)
Binary files a/maps_src/mp_spawn.mdl and b/maps_src/mp_spawn.mdl differ
diff --git a/model.h b/model.h
index 05790c655d204ed18668b8e1b101c4f03cba2989..fffd26d111228c8661989f7291208afec53d5b48 100644 (file)
--- a/model.h
+++ b/model.h
@@ -7,14 +7,15 @@
 
 #include "common.h"
 
-
 enum mdl_shader
 {
    k_shader_standard                = 0,
    k_shader_standard_cutout         = 1,
    k_shader_terrain_blend           = 2,
    k_shader_standard_vertex_blend   = 3,
-   k_shader_water                   = 4
+   k_shader_water                   = 4,
+   k_shader_invisible               = 5,
+   k_shader_boundary                = 6
 };
 
 enum mdl_surface_prop
@@ -28,10 +29,12 @@ enum mdl_surface_prop
 
 enum material_flag
 {
-   k_material_flag_skate_surface    = 0x1,
+   k_material_flag_skate_target     = 0x1,
    k_material_flag_collision        = 0x2,
    k_material_flag_grow_grass       = 0x4,
-   k_material_flag_grind_surface    = 0x8
+   k_material_flag_grindable        = 0x8,
+   k_material_flag_invisible        = 0x10,
+   k_material_flag_boundary         = 0x20
 };
 
 #pragma pack(push,1)
@@ -150,7 +153,7 @@ struct mdl_mesh
    u32 submesh_start,
        submesh_count,
        pstr_name,
-       flags,
+       entity_id,    /* upper 16 bits: type, lower 16 bits: index */
        armature_id;
 };
 
@@ -164,7 +167,7 @@ struct mdl_file
 struct mdl_texture
 {
    mdl_file file;
-   u32 type;
+   u32 glname;
 };
 
 struct mdl_array
@@ -239,9 +242,15 @@ VG_STATIC u32 mdl_query_array_size( mdl_array *arr )
       return 0;
 }
 
+VG_STATIC const char *mdl_pstr( mdl_context *mdl, u32 pstr );
 VG_STATIC 
 void mdl_fread_pack_file( mdl_context *mdl, mdl_file *info, void *dst )
 {
+   if( !info->pack_size ){
+      vg_warn( "path: %s\n", mdl_pstr( mdl, info->pstr_path ) );
+      vg_fatal_exit_loop( "Packed file is only a header; it is not packed" );
+   }
+
    fseek( mdl->file, mdl->pack_base_offset+info->pack_offset, SEEK_SET );
    u64 l = fread( dst, info->pack_size, 1, mdl->file );
 
@@ -340,13 +349,6 @@ VG_STATIC int mdl_load_animation_block( mdl_context *mdl, void *lin_alloc )
    return mdl_load_array( mdl, &mdl->keyframes, "mdl_keyframe", lin_alloc );
 }
 
-#if 0
-VG_STATIC int mdl_load_pack_block( mdl_context *mdl, void *lin_alloc )
-{
-   return mdl_load_array( mdl, &mdl->pack, "pack", lin_alloc );
-}
-#endif
-
 /*
  * if calling mdl_open, and the file does not exist, the game will fatal quit
  */
diff --git a/models_src/board_fish.mdl b/models_src/board_fish.mdl
new file mode 100644 (file)
index 0000000..b72141d
Binary files /dev/null and b/models_src/board_fish.mdl differ
index c1ac5b3fb8aee08de8d1475ccb21583331d07f20..00fbf4cdc377ac471dc62d1eff2b886e5cd3ac59 100644 (file)
Binary files a/models_src/ch_jordan.mdl and b/models_src/ch_jordan.mdl differ
index 2351dfd4796a7afd95be28033556e55efa98518d..042c4e3f75157f1318b8cfc96ca584ca6da4dc5c 100644 (file)
Binary files a/models_src/ch_new.mdl and b/models_src/ch_new.mdl differ
index 80e52abe94c1d77cdf798b002cf0db6412d78d10..a761b0a7c3dfeef929d7761381b5716f21649bcf 100644 (file)
Binary files a/models_src/ch_outlaw.mdl and b/models_src/ch_outlaw.mdl differ
index 19c44929cd61f01ea336592f8ab36d2d6e266438..da097071804d7a6e18d5faaef5a1c56c59451bb7 100644 (file)
--- a/player.c
+++ b/player.c
@@ -149,15 +149,15 @@ void player__use_avatar( player_instance *player, struct player_avatar *av )
 }
 
 PLAYER_API
-void player__use_mesh( player_instance *player, glmesh *mesh )
+void player__use_model( player_instance *player, struct player_model *mdl )
 {
-   player->playermesh = mesh;
+   player->playermodel = mdl;
 }
 
 PLAYER_API
-void player__use_texture( player_instance *player, vg_tex2d *tex )
+void player__use_board( player_instance *player, struct player_board *mdl )
 {
-   player->playertex = tex;
+   player->playerboard = mdl;
 }
 
 PLAYER_API
@@ -282,40 +282,6 @@ void player__post_update( player_instance *player )
    }
 }
 
-VG_STATIC void player_apply_transport_to_cam( m4x3f transport )
-{
-   /* FIXME: Applies to main_camera directly! */
-
-   /* Pre-emptively edit the camera matrices so that the motion vectors 
-    * are correct */
-   m4x3f transport_i;
-   m4x4f transport_4;
-   m4x3_invert_affine( transport, transport_i );
-   m4x3_expand( transport_i, transport_4 );
-   m4x4_mul( main_camera.mtx.pv, transport_4, main_camera.mtx.pv );
-   m4x4_mul( main_camera.mtx.v,  transport_4, main_camera.mtx.v );
-
-   /* we want the regular transform here no the inversion */
-   m4x3_expand( transport, transport_4 );
-   m4x4_mul( gate_camera.mtx.pv, transport_4, gate_camera.mtx.pv );
-   m4x4_mul( gate_camera.mtx.v,  transport_4, gate_camera.mtx.v );
-}
-
-__attribute__ ((deprecated))
-VG_STATIC void gate_rotate_angles( ent_gate *gate, v3f angles, v3f d )
-{
-   v3_copy( angles, d );
-   return;
-
-   v3f fwd_dir = { cosf(angles[0]),
-                   0.0f,
-                   sinf(angles[0])};
-   m3x3_mulv( gate->transport, fwd_dir, fwd_dir );
-
-   v3_copy( angles, d );
-   d[0] = atan2f( fwd_dir[2], fwd_dir[0] );
-}
-
 /*
  * Applies gate transport to a player_interface
  */
@@ -362,176 +328,38 @@ void player__pass_gate( player_instance *player, ent_gate *gate )
    audio_unlock();
 }
 
-VG_STATIC void player__pre_render( player_instance *player )
+VG_STATIC void player_apply_transport_to_cam( m4x3f transport )
 {
-   if( _player_animate[ player->subsystem ] ){
-      player_animation res;
-      _player_animate[ player->subsystem ]( player, &res );
-
-      m4x3f transform;
-      q_m3x3( res.root_q, transform );
-      v3_copy( res.root_co, transform[3] );
-
-      struct skeleton *sk = &player->playeravatar->sk;
-
-      if( player->holdout_time > 0.0f ){
-         skeleton_lerp_pose( sk, res.pose, player->holdout_pose, 
-                                           player->holdout_time, res.pose );
-         player->holdout_time -= vg.time_frame_delta * 2.0f;
-      }
-
-      skeleton_apply_pose( sk, res.pose, k_anim_apply_defer_ik );
-      skeleton_apply_ik_pass( sk );
-      skeleton_apply_pose( sk, res.pose, k_anim_apply_deffered_only );
-      skeleton_apply_inverses( sk );
-      skeleton_apply_transform( sk, transform );
-
-      skeleton_debug( sk );
-   }
-
-   if( _player_post_animate[ player->subsystem ] )
-      _player_post_animate[ player->subsystem ]( player );
-
-   struct player_avatar *av = player->playeravatar;
-   v3f vp0 = {0.0f,0.1f, 0.55f},
-       vp1 = {0.0f,0.1f,-0.55f};
-
-   struct ub_world_lighting *ubo = &get_active_world()->ub_lighting;
-   m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, ubo->g_board_0 );
-   m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp1, ubo->g_board_1 );
-
-   if( player->rewinding ){
-      if( player->rewind_time <= 0.0f ){
-         double taken = vg.time - player->rewind_start;
-         vg_success( "Rewind took (rt, pt, tl): %f, %f, %f\n", 
-                           taken, player->rewind_predicted_time,
-                           player->rewind_total_length );
-
-         player->rewinding = 0;
-         player->rewind_length = 1;
-         player->rewind_total_length = 0.0f;
-         player->rewind_accum = 0.0f;
-         world_global.sky_target_rate = 1.0;
-         world_global.time = world_global.last_use;
-      }
-      else{
-         world_global.sky_target_rate = -100.0;
-
-         float budget         = vg.time_delta,
-               overall_length = player->rewind_length;
-
-         for( int i=0; (i<10)&&(player->rewind_time>0.0f)&&(budget>0.0f); i++ ){
-            /* Interpolate frames */
-            int i0 = floorf( player->rewind_time ),
-                i1 = VG_MIN( i0+1, player->rewind_length-1 );
-            
-            struct rewind_frame *fr =  &player->rewind_buffer[i0],
-                                *fr1 = &player->rewind_buffer[i1];
-
-            float dist = vg_maxf( v3_dist( fr->pos, fr1->pos ), 0.001f ),
-                  subl = vg_fractf( player->rewind_time ) + 0.001f,
-
-                  sramp = 3.0f-(1.0f/(0.4f+0.4f*player->rewind_time)),
-                  speed = sramp*28.0f + 0.5f*player->rewind_time,
-                  mod  = speed * (budget / dist),
-
-                  advl = vg_minf( mod, subl ),
-                  advt = (advl / mod) * budget;
-            
-            player->dist_accum += speed * advt;
-            player->rewind_time -= advl;
-            budget -= advt;
-         }
-
-         player->rewind_time = vg_maxf( 0.0f, player->rewind_time );
-
-         float current_time = vg.time - player->rewind_start,
-               remaining    = player->rewind_predicted_time - current_time;
-
-         if( player->rewind_sound_wait ){
-            if( player->rewind_predicted_time >= 6.5f ){
-               if( remaining <= 6.5f ){
-                  audio_lock();
-                  audio_oneshot( &audio_rewind[3], 1.0f, 0.0f );
-                  audio_unlock();
-                  player->rewind_sound_wait = 0;
-               }
-            }
-            else if( player->rewind_predicted_time >= 2.5f ){
-               if( remaining <= 2.5f ){
-                  audio_lock();
-                  audio_oneshot( &audio_rewind[2], 1.0f, 0.0f );
-                  audio_unlock();
-                  player->rewind_sound_wait = 0;
-               }
-            }
-            else if( player->rewind_predicted_time >= 1.5f ){
-               if( remaining <= 1.5f ){
-                  audio_lock();
-                  audio_oneshot( &audio_rewind[1], 1.0f, 0.0f );
-                  audio_unlock();
-                  player->rewind_sound_wait = 0;
-               }
-            }
-         }
-         
-         int i0 = floorf( player->rewind_time ),
-             i1 = VG_MIN( i0+1, player->rewind_length-1 );
-         
-         struct rewind_frame *fr =  &player->rewind_buffer[i0],
-                             *fr1 = &player->rewind_buffer[i1];
-         
-         float sub = vg_fractf(player->rewind_time);
-
-         v3_lerp( fr->pos, fr1->pos, sub, player->cam_override_pos );
-         player->cam_override_angles[0] = 
-            vg_alerpf( fr->ang[0], fr1->ang[0], sub );
-         player->cam_override_angles[1] = 
-            vg_lerpf ( fr->ang[1], fr1->ang[1], sub );
+   /* FIXME: Applies to main_camera directly! */
 
-         float blend = player->rewind_time * 0.25f;
-         player->cam_override_strength = vg_clampf( blend, 0.0f, 1.0f );
-      }
-   }
-   else player->cam_override_strength = 0.0f;
+   /* Pre-emptively edit the camera matrices so that the motion vectors 
+    * are correct */
+   m4x3f transport_i;
+   m4x4f transport_4;
+   m4x3_invert_affine( transport, transport_i );
+   m4x3_expand( transport_i, transport_4 );
+   m4x4_mul( main_camera.mtx.pv, transport_4, main_camera.mtx.pv );
+   m4x4_mul( main_camera.mtx.v,  transport_4, main_camera.mtx.v );
 
-   player__cam_iterate( player );
+   /* we want the regular transform here no the inversion */
+   m4x3_expand( transport, transport_4 );
+   m4x4_mul( gate_camera.mtx.pv, transport_4, gate_camera.mtx.pv );
+   m4x4_mul( gate_camera.mtx.v,  transport_4, gate_camera.mtx.v );
 }
 
-PLAYER_API void player__render( camera *cam, player_instance *player )
+__attribute__ ((deprecated))
+VG_STATIC void gate_rotate_angles( ent_gate *gate, v3f angles, v3f d )
 {
-   shader_model_character_view_use();
-   vg_tex2d_bind( player->playertex, 0 );
-   shader_model_character_view_uTexMain( 0 );
-   shader_model_character_view_uCamera( cam->transform[3] );
-   shader_model_character_view_uPv( cam->mtx.pv );
-   shader_model_character_view_uTexSceneDepth( 1 );
-   render_fb_bind_texture( gpipeline.fb_main, 2, 1 );
-   v3f inverse;
-   render_fb_inverse_ratio( gpipeline.fb_main, inverse );
-   inverse[2] = main_camera.farz-main_camera.nearz;
-
-   shader_model_character_view_uInverseRatioDepth( inverse );
-   render_fb_inverse_ratio( NULL, inverse );
-   inverse[2] = cam->farz-cam->nearz;
-   shader_model_character_view_uInverseRatioMain( inverse );
-
-   world_instance *world = get_active_world();
-   world_link_lighting_ub( world, _shader_model_character_view.id );
-   world_bind_position_texture( world, _shader_model_character_view.id,
-                              _uniform_model_character_view_g_world_depth, 2 );
-   world_bind_light_array( world, _shader_model_character_view.id,
-                              _uniform_model_character_view_uLightsArray, 3 );
-   world_bind_light_index( world, _shader_model_character_view.id,
-                              _uniform_model_character_view_uLightsIndex, 4 );
-
-   glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms,
-                         player->playeravatar->sk.bone_count,
-                         0,
-                         (float *)player->playeravatar->sk.final_mtx );
-   
-   mesh_bind( player->playermesh );
-   mesh_draw( player->playermesh );
+   v3_copy( angles, d );
+   return;
+
+   v3f fwd_dir = { cosf(angles[0]),
+                   0.0f,
+                   sinf(angles[0])};
+   m3x3_mulv( gate->transport, fwd_dir, fwd_dir );
+
+   v3_copy( angles, d );
+   d[0] = atan2f( fwd_dir[2], fwd_dir[0] );
 }
 
 PLAYER_API void player__im_gui( player_instance *player )
index aa82925502bf6e59a07b7cd6b593c78165de20d8..dac0db44fd121079074b0ee2b19227c99ef4e7ba 100644 (file)
--- a/player.h
+++ b/player.h
@@ -1,8 +1,9 @@
 #ifndef PLAYER_H
 #define PLAYER_H
 
-#include "player_api.h"
-
+#include "player_ragdoll.h"
+#include "player_render.h"
+#include "player_model.h"
 #include "player_common.h"
 #include "player_walk.h"
 #include "player_skate.h"
@@ -85,10 +86,11 @@ struct player_instance
     * --------------------------------------------------
     */
 
+
    struct player_avatar  *playeravatar;
-   glmesh                *playermesh;
+   struct player_model   *playermodel;
+   struct player_board   *playerboard;
    struct player_ragdoll  ragdoll;
-   vg_tex2d              *playertex;
 
    player_pose            holdout_pose;
    float                  holdout_time;
@@ -228,6 +230,22 @@ void( *_player_restore[] )( player_instance *player ) =
    NULL
 };
 
+PLAYER_API void player__debugtext( int size, const char *fmt, ... );
+PLAYER_API void player__create( player_instance *inst );
+PLAYER_API void player__use_avatar( player_instance *player, 
+                                    struct player_avatar *av );
+PLAYER_API void player__use_mesh( player_instance *player, glmesh *mesh );
+PLAYER_API void player__use_texture( player_instance *player, vg_tex2d *tex );
+PLAYER_API void player__bind( player_instance *player );
+PLAYER_API void player__pre_update( player_instance *player );
+PLAYER_API void player__update( player_instance *player );
+PLAYER_API void player__post_update( player_instance *player );
+
+PLAYER_API void player__pass_gate( player_instance *player, ent_gate *gate );
+PLAYER_API void player__im_gui( player_instance *player );
+PLAYER_API void player__spawn( player_instance *player, ent_spawn *rp );
+PLAYER_API void player__kill( player_instance *player );
+
 /* implementation */
 
 #include "player.c"
@@ -236,5 +254,7 @@ void( *_player_restore[] )( player_instance *player ) =
 #include "player_skate.c"
 #include "player_dead.c"
 #include "player_drive.c"
+#include "player_render.c"
+#include "player_ragdoll.c"
 
 #endif /* PLAYER_H */
index dbf1b53950124cb2528e629bf61faeddbd9ac304..ad9e4ca496a0043ed229ebd2b1678fc33fa76c4e 100644 (file)
@@ -1,15 +1,9 @@
 #ifndef PLAYER_API_H
 #define PLAYER_API_H
 
-#define VG_GAME
-#include "vg/vg.h"
-
-#include "player_ragdoll.h"
-#include "player_model.h"
-
-/*
- * Defines a set of routines used to interact with the player
- */
+#include "model.h"
+#include "camera.h"
+#include "entity.h"
 
 #define PLAYER_API VG_STATIC
 typedef struct player_instance player_instance;
@@ -18,56 +12,9 @@ typedef struct player_animation player_animation;
 
 struct player_animation
 {
-#if 0
-   camera camera_firstperson,
-          camera_thirdperson;
-#endif
-
    player_pose pose;
    v3f         root_co;
    v4f         root_q;
 };
 
-/*
- * Init
- */
-PLAYER_API void player_create       ( player_instance *player );
-
-/* 
- * Appearence
- */
-PLAYER_API void player_use_avatar   ( player_instance *player,
-                                      struct player_avatar *av );
-PLAYER_API void player_use_mesh     ( player_instance *player, glmesh *mesh );
-PLAYER_API void player_use_texture  ( player_instance *player, vg_tex2d *tex );
-
-
-/*
- * Gameloop events
- * ----------------------------------------------------------------------------
- */
-PLAYER_API void player__bind        ( player_instance *player );
-PLAYER_API void player__pre_update  ( player_instance *player );
-PLAYER_API void player__update      ( player_instance *player );
-PLAYER_API void player__post_update ( player_instance *player );
-PLAYER_API void player__pre_render  ( player_instance *player );
-PLAYER_API void player__render      ( camera *cam, player_instance *player );
-PLAYER_API void player__im_gui      ( player_instance *player );
-
-/*
- * Mechanic events
- * ----------------------------------------------------------------------------
- */
-PLAYER_API void player__spawn       ( player_instance *player,
-                                      ent_spawn *rp );
-PLAYER_API void player__kill        ( player_instance *player );
-PLAYER_API void player__pass_gate   ( player_instance *player,
-                                      ent_gate *gate );
-
-/*
- * Utiltiy
- * ----------------------------------------------------------------------------
- */
-PLAYER_API void player__debugtext( int size, const char *fmt, ... );
-
 #endif /* PLAYER_API_H */
index 2567a83aac42668c46843d73e0cb4519b27536c1..1d462f6377485280db4eea7c7323439d60128ea7 100644 (file)
 
 #include "shaders/model_character_view.h"
 
-struct player_avatar
-{
-   mdl_context meta;
-   struct skeleton sk;
-
-   u32 id_hip,
-       id_ik_hand_l,
-       id_ik_hand_r,
-       id_ik_elbow_l,
-       id_ik_elbow_r,
-       id_head,
-       id_ik_foot_l,
-       id_ik_foot_r,
-       id_ik_knee_l,
-       id_ik_knee_r,
-       id_wheel_l,
-       id_wheel_r,
-       id_board;
-};
-
-#if 0
-glmesh player_meshes[3];
-#endif
-
-VG_STATIC void player_avatar_load( struct player_avatar *av, const char *path )
-{
-   /* load in reference player model, with animations and such */
-   /* FIXME: This is allocated as un-freeable systems memory */
-
-   mdl_open( &av->meta, path, vg_mem.rtmemory );
-   mdl_load_metadata_block( &av->meta, vg_mem.rtmemory );
-   mdl_load_animation_block( &av->meta, vg_mem.rtmemory );
-   mdl_close( &av->meta );
-
-   struct skeleton *sk = &av->sk;
-   skeleton_setup( sk, vg_mem.rtmemory, &av->meta );
-
-   av->id_hip        = skeleton_bone_id( sk, "hips" );
-   av->id_ik_hand_l  = skeleton_bone_id( sk, "hand.IK.L" );
-   av->id_ik_hand_r  = skeleton_bone_id( sk, "hand.IK.R" );
-   av->id_ik_elbow_l = skeleton_bone_id( sk, "elbow.L" );
-   av->id_ik_elbow_r = skeleton_bone_id( sk, "elbow.R" );
-   av->id_head       = skeleton_bone_id( sk, "head" );
-   av->id_ik_foot_l  = skeleton_bone_id( sk, "foot.IK.L" );
-   av->id_ik_foot_r  = skeleton_bone_id( sk, "foot.IK.R" );
-   av->id_board      = skeleton_bone_id( sk, "board" );
-   av->id_wheel_l    = skeleton_bone_id( sk, "wheel.L" );
-   av->id_wheel_r    = skeleton_bone_id( sk, "wheel.R" );
-   av->id_ik_knee_l  = skeleton_bone_id( sk, "knee.L" );
-   av->id_ik_knee_r  = skeleton_bone_id( sk, "knee.R" );
-}
-
-#if 0
-VG_STATIC void player_load_reference( struct player_model *pmodel )
-{
-   shader_viewchar_register();
-   vg_acquire_thread_sync();
-   {
-      vg_tex2d_init( (vg_tex2d *[]){ &tex_characters }, 1 );
-   }
-   vg_release_thread_sync();
-
-   /* 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();
-   {
-      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();
-
-   skeleton_setup( &player.mdl.sk, vg_mem.rtmemory, &player.mdl.meta );
-   player_init_ragdoll();
-
-   /* 
-    * 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  }
-   };
-   
-   for( int i=0; i<vg_list_size(anims); i++ )
-   {
-      *anims[i].anim = skeleton_get_anim( &player.mdl.sk, anims[i].name );
-      
-      if( !(*anims[i].anim) )
-      {
-         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 },
-      { "foot.IK.L", &player.mdl.id_ik_foot_l },
-      { "foot.IK.R", &player.mdl.id_ik_foot_r },
-      { "board",     &player.mdl.id_board }
-   };
-
-   for( int i=0; i<vg_list_size(bones); i++ )
-   {
-      *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\n", bones[i].name );
-         vg_fatal_exit_loop( "Invalid character file" );
-      }
-   }
-}
-#endif
-
 #endif
diff --git a/player_ragdoll.c b/player_ragdoll.c
new file mode 100644 (file)
index 0000000..a7e3e75
--- /dev/null
@@ -0,0 +1,454 @@
+#ifndef PLAYER_RAGDOLL_C
+#define PLAYER_RAGDOLL_C
+
+#include "player.h"
+#include "audio.h"
+
+VG_STATIC void player_ragdoll_init(void)
+{
+   VG_VAR_F32( k_ragdoll_limit_scale );
+   VG_VAR_I32( k_ragdoll_div );
+   VG_VAR_I32( k_ragdoll_debug_collider );
+   VG_VAR_I32( k_ragdoll_debug_constraints );
+}
+
+VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
+                                                  struct ragdoll_part *rp )
+{
+   m4x3_identity( rp->collider_mtx );
+
+   if( bone->collider == k_bone_collider_box ){
+      v3f delta;
+      v3_sub( bone->hitbox[1], bone->hitbox[0], delta );
+      v3_muls( delta, 0.5f, delta );
+      v3_add( bone->hitbox[0], delta, rp->collider_mtx[3] );
+
+      v3_copy( delta, rp->obj.rb.bbx[1] );
+      v3_muls( delta, -1.0f, rp->obj.rb.bbx[0] );
+
+      q_identity( rp->obj.rb.q );
+      rp->obj.type = k_rb_shape_box;
+      rp->colour = 0xffcccccc;
+   }
+   else if( bone->collider == k_bone_collider_capsule ){
+      v3f v0, v1, tx, ty;
+      v3_sub( bone->hitbox[1], bone->hitbox[0], v0 );
+
+      int major_axis = 0;
+      float largest = -1.0f;
+
+      for( int i=0; i<3; i ++ ){
+         if( fabsf( v0[i] ) > largest ){
+            largest = fabsf( v0[i] );
+            major_axis = i;
+         }
+      }
+      
+      v3_zero( v1 );
+      v1[ major_axis ] = 1.0f;
+      rb_tangent_basis( v1, tx, ty );
+      
+      float r = (fabsf(v3_dot(tx,v0)) + fabsf(v3_dot(ty,v0))) * 0.25f,
+            l = fabsf(v0[ major_axis ]);
+      
+      /* orientation */
+      v3_muls( tx, -1.0f, rp->collider_mtx[0] );
+      v3_muls( v1, -1.0f, rp->collider_mtx[1] );
+      v3_muls( ty, -1.0f, rp->collider_mtx[2] );
+      v3_add( bone->hitbox[0], bone->hitbox[1], rp->collider_mtx[3] );
+      v3_muls( rp->collider_mtx[3], 0.5f, rp->collider_mtx[3] );
+
+      rp->obj.type = k_rb_shape_capsule;
+      rp->obj.inf.capsule.height = l;
+      rp->obj.inf.capsule.radius = r;
+
+      rp->colour = 0xff000000 | (0xff << (major_axis*8));
+   }
+   else{
+      vg_warn( "type: %u\n", bone->collider );
+      vg_fatal_exit_loop( "Invalid bone collider type" );
+   }
+
+   m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx );
+
+   /* Position collider into rest */
+   m3x3_q( rp->collider_mtx, rp->obj.rb.q );
+   v3_add( rp->collider_mtx[3], bone->co, rp->obj.rb.co );
+   v3_zero( rp->obj.rb.v );
+   v3_zero( rp->obj.rb.w );
+   rb_init_object( &rp->obj );
+}
+
+/*
+ * Get parent index in the ragdoll
+ */
+VG_STATIC u32 ragdoll_bone_parent( struct player_ragdoll *rd,
+                                   struct player_avatar *av, u32 bone_id )
+{
+   for( u32 j=0; j<rd->part_count; j++ )
+      if( rd->parts[ j ].bone_id == bone_id )
+         return j;
+
+   vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" );
+   return 0;
+}
+
+/*
+ * Setup ragdoll colliders 
+ */
+VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd,
+                                                 struct player_avatar *av )
+{
+   rd->part_count = 0;
+
+   if( !av->sk.collider_count )
+      return;
+
+   rd->position_constraints_count = 0;
+   rd->cone_constraints_count = 0;
+
+   for( u32 i=1; i<av->sk.bone_count; i ++ ){
+      struct skeleton_bone *bone = &av->sk.bones[i];
+
+      /*
+       * Bones with colliders
+       */
+      if( !(bone->collider) )
+         continue;
+
+      if( rd->part_count > vg_list_size(rd->parts) )
+         vg_fatal_exit_loop( "Playermodel has too many colliders" );
+
+      struct ragdoll_part *rp = &rd->parts[ rd->part_count ++ ];
+      rp->bone_id = i;
+      rp->parent = 0xffffffff;
+
+      player_init_ragdoll_bone_collider( bone, rp );
+      
+      /*
+       * Bones with collider and parent
+       */
+      if( !bone->parent )
+         continue;
+
+      rp->parent = ragdoll_bone_parent( rd, av, bone->parent );
+      
+      
+      if( bone->orig_bone->flags & k_bone_flag_cone_constraint ){
+         struct rb_constr_pos *c = 
+            &rd->position_constraints[ rd->position_constraints_count ++ ];
+
+         struct skeleton_bone *bj = &av->sk.bones[rp->bone_id];
+         struct ragdoll_part  *pp = &rd->parts[rp->parent];
+         struct skeleton_bone *bp = &av->sk.bones[pp->bone_id];
+
+         /* Convention: rba -- parent, rbb -- child */
+         c->rba = &pp->obj.rb;
+         c->rbb = &rp->obj.rb;
+
+         v3f delta;
+         v3_sub( bj->co, bp->co, delta );
+         m4x3_mulv( rp->inv_collider_mtx, (v3f){0.0f,0.0f,0.0f}, c->lcb );
+         m4x3_mulv( pp->inv_collider_mtx, delta, c->lca );
+
+
+         mdl_bone *inf = bone->orig_bone;
+
+         struct rb_constr_swingtwist *a = 
+            &rd->cone_constraints[ rd->cone_constraints_count ++ ];
+
+         a->rba = &pp->obj.rb;
+         a->rbb = &rp->obj.rb;
+         a->conet = cosf( inf->conet )-0.0001f;
+         
+         /* Store constraint in local space vectors */
+         m3x3_mulv( c->rba->to_local, inf->conevx, a->conevx );
+         m3x3_mulv( c->rba->to_local, inf->conevy, a->conevy );
+         m3x3_mulv( c->rbb->to_local, inf->coneva, a->coneva );
+         v3_copy( c->lca, a->view_offset );
+         
+         v3_cross( inf->coneva, inf->conevy, a->conevxb );
+         m3x3_mulv( c->rbb->to_local, a->conevxb, a->conevxb );
+
+         v3_normalize( a->conevxb );
+         v3_normalize( a->conevx );
+         v3_normalize( a->conevy );
+         v3_normalize( a->coneva );
+
+         a->conevx[3] = v3_length( inf->conevx );
+         a->conevy[3] = v3_length( inf->conevy );
+
+         rp->use_limits = 1;
+      }
+   }
+}
+
+/*
+ * Make avatar copy the ragdoll
+ */
+VG_STATIC void copy_ragdoll_pose_to_avatar( struct player_ragdoll *rd,
+                                            struct player_avatar *av )
+{
+   for( int i=0; i<rd->part_count; i++ ){
+      struct ragdoll_part *part = &rd->parts[i];
+
+      m4x3f mtx;
+
+      v4f q_int;
+      v3f co_int;
+
+      float substep = vg.time_fixed_extrapolate;
+      v3_lerp( part->prev_co, part->obj.rb.co, substep, co_int );
+      q_nlerp( part->prev_q, part->obj.rb.q, substep, q_int );
+
+      q_m3x3( q_int, mtx );
+      v3_copy( co_int, mtx[3] );
+
+      m4x3_mul( mtx, part->inv_collider_mtx, av->sk.final_mtx[part->bone_id] );
+   }
+
+   for( u32 i=1; i<av->sk.bone_count; i++ ){
+      struct skeleton_bone *sb = &av->sk.bones[i];
+
+      if( sb->parent && !sb->collider ){
+         v3f delta;
+         v3_sub( av->sk.bones[i].co, av->sk.bones[sb->parent].co, delta );
+
+         m4x3f posemtx;
+         m3x3_identity( posemtx );
+         v3_copy( delta, posemtx[3] );
+
+         /* final matrix */
+         m4x3_mul( av->sk.final_mtx[sb->parent], posemtx, av->sk.final_mtx[i] );
+      }
+   }
+
+   skeleton_apply_inverses( &av->sk );
+}
+
+/*
+ * Make the ragdoll copy the player model
+ */
+VG_STATIC void copy_avatar_pose_to_ragdoll( struct player_avatar *av,
+                                            struct player_ragdoll *rd,
+                                            v3f velocity )
+{
+   for( int i=0; i<rd->part_count; i++ ){
+      struct ragdoll_part *part = &rd->parts[i];
+
+      v3f pos, offset;
+      u32 bone = part->bone_id;
+
+      m4x3_mulv( av->sk.final_mtx[bone], av->sk.bones[bone].co, pos );
+      m3x3_mulv( av->sk.final_mtx[bone], part->collider_mtx[3], offset );
+      v3_add( pos, offset, part->obj.rb.co );
+
+      m3x3f r;
+      m3x3_mul( av->sk.final_mtx[bone], part->collider_mtx, r );
+      m3x3_q( r, part->obj.rb.q );
+
+      v3_copy( velocity, part->obj.rb.v );
+      v3_zero( part->obj.rb.w );
+
+      v3_copy( part->obj.rb.co, part->prev_co );
+      v4_copy( part->obj.rb.q, part->prev_q );
+      
+      rb_update_transform( &part->obj.rb );
+   }
+}
+
+/*
+ * Draw rigidbody colliders for ragdoll
+ */
+VG_STATIC void player_debug_ragdoll(void)
+{
+}
+
+/*
+ * Ragdoll physics step
+ */
+VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd )
+{
+   world_instance *world = get_active_world();
+
+   int run_sim = 0;
+   ragdoll_frame ++;
+
+   if( ragdoll_frame >= k_ragdoll_div ){
+      ragdoll_frame = 0;
+      run_sim = 1;
+   }
+
+   rb_solver_reset();
+   
+   float contact_velocities[256];
+
+   for( int i=0; i<rd->part_count; i ++ ){
+      v4_copy( rd->parts[i].obj.rb.q, rd->parts[i].prev_q );
+      v3_copy( rd->parts[i].obj.rb.co, rd->parts[i].prev_co );
+
+      if( rb_global_has_space() ){
+         rb_ct *buf = rb_global_buffer();
+
+         int l;
+         
+         if( rd->parts[i].obj.type == k_rb_shape_capsule ){
+            l = rb_capsule__scene( rd->parts[i].obj.rb.to_world,
+                                   &rd->parts[i].obj.inf.capsule,
+                                   NULL, &world->rb_geo.inf.scene, buf );
+         }
+         else if( rd->parts[i].obj.type == k_rb_shape_box ){
+            l = rb_box__scene( rd->parts[i].obj.rb.to_world,
+                               rd->parts[i].obj.rb.bbx,
+                               NULL, &world->rb_geo.inf.scene, buf );
+         }
+         else continue;
+
+         for( int j=0; j<l; j++ ){
+            buf[j].rba = &rd->parts[i].obj.rb;
+            buf[j].rbb = &world->rb_geo.rb;
+         }
+
+         rb_contact_count += l;
+      }
+   }
+
+   /* 
+    * self-collision
+    */
+   for( int i=0; i<rd->part_count-1; i ++ ){
+      for( int j=i+1; j<rd->part_count; j ++ ){
+         if( rd->parts[j].parent != i ){
+            if( !rb_global_has_space() )
+               break;
+
+            if( rd->parts[j].obj.type != k_rb_shape_capsule )
+               continue;
+
+            if( rd->parts[i].obj.type != k_rb_shape_capsule )
+               continue;
+
+            rb_ct *buf = rb_global_buffer();
+
+            int l = rb_capsule__capsule( rd->parts[i].obj.rb.to_world,
+                                         &rd->parts[i].obj.inf.capsule,
+                                         rd->parts[j].obj.rb.to_world,
+                                         &rd->parts[j].obj.inf.capsule,
+                                         buf );
+
+            for( int k=0; k<l; k++ ){
+               buf[k].rba = &rd->parts[i].obj.rb;
+               buf[k].rbb = &rd->parts[j].obj.rb;
+            }
+
+            rb_contact_count += l;
+         }
+      }
+   }
+
+   for( int j=0; j<rd->part_count; j++ ){
+      struct ragdoll_part *pj = &rd->parts[j];
+
+      if( run_sim ){
+         v4f plane = {0.0f,1.0f,0.0f,0.0f};
+         rb_effect_simple_bouyency( &pj->obj.rb, plane, 
+                                     k_ragdoll_floatyiness,
+                                     k_ragdoll_floatydrag );
+      }
+   }
+
+   /*
+    * PRESOLVE
+    */
+   for( u32 i=0; i<rb_contact_count; i++ ){
+      rb_ct *ct = &rb_contact_buffer[i];
+
+      v3f rv, ra, rb;
+      v3_sub( ct->co, ct->rba->co, ra );
+      v3_sub( ct->co, ct->rbb->co, rb );
+      rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
+      float     vn = v3_dot( rv, ct->n );
+
+      contact_velocities[i] = vn;
+   }
+
+   rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
+   rb_presolve_swingtwist_constraints( rd->cone_constraints,
+                                       rd->cone_constraints_count );
+
+   /* 
+    * DEBUG
+    */
+   if( k_ragdoll_debug_collider ){
+      for( u32 i=0; i<rd->part_count; i ++ )
+         rb_object_debug( &rd->parts[i].obj, rd->parts[i].colour );
+   }
+
+   if( k_ragdoll_debug_constraints ){
+      rb_debug_position_constraints( rd->position_constraints, 
+                                     rd->position_constraints_count );
+
+      rb_debug_swingtwist_constraints( rd->cone_constraints,
+                                       rd->cone_constraints_count );
+   }
+
+   /*
+    * SOLVE CONSTRAINTS 
+    */
+   if( run_sim ){
+      for( int i=0; i<16; i++ ){
+         rb_solve_contacts( rb_contact_buffer, rb_contact_count );
+         rb_solve_swingtwist_constraints( rd->cone_constraints, 
+                                          rd->cone_constraints_count );
+         rb_solve_position_constraints( rd->position_constraints, 
+                                        rd->position_constraints_count );
+      }
+
+      for( int i=0; i<rd->part_count; i++ )
+         rb_iter( &rd->parts[i].obj.rb );
+
+      for( int i=0; i<rd->part_count; i++ )
+         rb_update_transform( &rd->parts[i].obj.rb );
+
+      rb_correct_swingtwist_constraints( rd->cone_constraints, 
+                                         rd->cone_constraints_count, 0.25f );
+
+      rb_correct_position_constraints( rd->position_constraints,
+                                       rd->position_constraints_count, 0.5f );
+   }
+
+   rb_ct *stress = NULL;
+   float max_stress = 1.0f;
+
+   for( u32 i=0; i<rb_contact_count; i++ ){
+      rb_ct *ct = &rb_contact_buffer[i];
+
+      v3f rv, ra, rb;
+      v3_sub( ct->co, ct->rba->co, ra );
+      v3_sub( ct->co, ct->rbb->co, rb );
+      rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
+      float vn = v3_dot( rv, ct->n );
+
+      float s = fabsf(vn - contact_velocities[i]);
+      if( s > max_stress ){
+         stress = ct;
+         max_stress = s;
+      }
+   }
+
+   static u32 temp_filter = 0;
+
+   if( temp_filter ){
+      temp_filter --;
+      return;
+   }
+
+   if( stress ){
+      temp_filter = 20;
+      audio_lock();
+      audio_oneshot_3d( &audio_hits[rand()%5], stress->co, 20.0f, 1.0f );
+      audio_unlock();
+   }
+}
+
+#endif /* PLAYER_RAGDOLL_C */
index 40ee45158ded5b131eff9649bba16d4691c922cc..789db4c48e731acfd2054ebc6dd058db0bc74ccd 100644 (file)
@@ -1,13 +1,10 @@
 #ifndef PLAYER_RAGDOLL_H
 #define PLAYER_RAGDOLL_H
 
-#define VG_GAME
-#include "vg/vg.h"
+#include "player_api.h"
 #include "skeleton.h"
 #include "rigidbody.h"
-#include "player_model.h"
-#include "world.h"
-#include "audio.h"
+#include "player_render.h"
 
 struct player_ragdoll{
    struct ragdoll_part{
@@ -48,451 +45,19 @@ VG_STATIC int   k_ragdoll_div = 1,
                 k_ragdoll_debug_collider = 1,
                 k_ragdoll_debug_constraints = 0;
 
-VG_STATIC void player_ragdoll_init(void)
-{
-   VG_VAR_F32( k_ragdoll_limit_scale );
-   VG_VAR_I32( k_ragdoll_div );
-   VG_VAR_I32( k_ragdoll_debug_collider );
-   VG_VAR_I32( k_ragdoll_debug_constraints );
-}
-
+VG_STATIC void player_ragdoll_init(void);
 VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
-                                                  struct ragdoll_part *rp )
-{
-   m4x3_identity( rp->collider_mtx );
-
-   if( bone->collider == k_bone_collider_box ){
-      v3f delta;
-      v3_sub( bone->hitbox[1], bone->hitbox[0], delta );
-      v3_muls( delta, 0.5f, delta );
-      v3_add( bone->hitbox[0], delta, rp->collider_mtx[3] );
-
-      v3_copy( delta, rp->obj.rb.bbx[1] );
-      v3_muls( delta, -1.0f, rp->obj.rb.bbx[0] );
-
-      q_identity( rp->obj.rb.q );
-      rp->obj.type = k_rb_shape_box;
-      rp->colour = 0xffcccccc;
-   }
-   else if( bone->collider == k_bone_collider_capsule ){
-      v3f v0, v1, tx, ty;
-      v3_sub( bone->hitbox[1], bone->hitbox[0], v0 );
-
-      int major_axis = 0;
-      float largest = -1.0f;
-
-      for( int i=0; i<3; i ++ ){
-         if( fabsf( v0[i] ) > largest ){
-            largest = fabsf( v0[i] );
-            major_axis = i;
-         }
-      }
-      
-      v3_zero( v1 );
-      v1[ major_axis ] = 1.0f;
-      rb_tangent_basis( v1, tx, ty );
-      
-      float r = (fabsf(v3_dot(tx,v0)) + fabsf(v3_dot(ty,v0))) * 0.25f,
-            l = fabsf(v0[ major_axis ]);
-      
-      /* orientation */
-      v3_muls( tx, -1.0f, rp->collider_mtx[0] );
-      v3_muls( v1, -1.0f, rp->collider_mtx[1] );
-      v3_muls( ty, -1.0f, rp->collider_mtx[2] );
-      v3_add( bone->hitbox[0], bone->hitbox[1], rp->collider_mtx[3] );
-      v3_muls( rp->collider_mtx[3], 0.5f, rp->collider_mtx[3] );
-
-      rp->obj.type = k_rb_shape_capsule;
-      rp->obj.inf.capsule.height = l;
-      rp->obj.inf.capsule.radius = r;
-
-      rp->colour = 0xff000000 | (0xff << (major_axis*8));
-   }
-   else{
-      vg_warn( "type: %u\n", bone->collider );
-      vg_fatal_exit_loop( "Invalid bone collider type" );
-   }
-
-   m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx );
-
-   /* Position collider into rest */
-   m3x3_q( rp->collider_mtx, rp->obj.rb.q );
-   v3_add( rp->collider_mtx[3], bone->co, rp->obj.rb.co );
-   v3_zero( rp->obj.rb.v );
-   v3_zero( rp->obj.rb.w );
-   rb_init_object( &rp->obj );
-}
-
-/*
- * Get parent index in the ragdoll
- */
+                                                  struct ragdoll_part *rp );
 VG_STATIC u32 ragdoll_bone_parent( struct player_ragdoll *rd,
-                                   struct player_avatar *av, u32 bone_id )
-{
-   for( u32 j=0; j<rd->part_count; j++ )
-      if( rd->parts[ j ].bone_id == bone_id )
-         return j;
-
-   vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" );
-   return 0;
-}
-
-/*
- * Setup ragdoll colliders 
- */
+                                   struct player_avatar *av, u32 bone_id );
 VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd,
-                                                 struct player_avatar *av )
-{
-   rd->part_count = 0;
-
-   if( !av->sk.collider_count )
-      return;
-
-   rd->position_constraints_count = 0;
-   rd->cone_constraints_count = 0;
-
-   for( u32 i=1; i<av->sk.bone_count; i ++ ){
-      struct skeleton_bone *bone = &av->sk.bones[i];
-
-      /*
-       * Bones with colliders
-       */
-      if( !(bone->collider) )
-         continue;
-
-      if( rd->part_count > vg_list_size(rd->parts) )
-         vg_fatal_exit_loop( "Playermodel has too many colliders" );
-
-      struct ragdoll_part *rp = &rd->parts[ rd->part_count ++ ];
-      rp->bone_id = i;
-      rp->parent = 0xffffffff;
-
-      player_init_ragdoll_bone_collider( bone, rp );
-      
-      /*
-       * Bones with collider and parent
-       */
-      if( !bone->parent )
-         continue;
-
-      rp->parent = ragdoll_bone_parent( rd, av, bone->parent );
-      
-      
-      if( bone->orig_bone->flags & k_bone_flag_cone_constraint ){
-         struct rb_constr_pos *c = 
-            &rd->position_constraints[ rd->position_constraints_count ++ ];
-
-         struct skeleton_bone *bj = &av->sk.bones[rp->bone_id];
-         struct ragdoll_part  *pp = &rd->parts[rp->parent];
-         struct skeleton_bone *bp = &av->sk.bones[pp->bone_id];
-
-         /* Convention: rba -- parent, rbb -- child */
-         c->rba = &pp->obj.rb;
-         c->rbb = &rp->obj.rb;
-
-         v3f delta;
-         v3_sub( bj->co, bp->co, delta );
-         m4x3_mulv( rp->inv_collider_mtx, (v3f){0.0f,0.0f,0.0f}, c->lcb );
-         m4x3_mulv( pp->inv_collider_mtx, delta, c->lca );
-
-
-         mdl_bone *inf = bone->orig_bone;
-
-         struct rb_constr_swingtwist *a = 
-            &rd->cone_constraints[ rd->cone_constraints_count ++ ];
-
-         a->rba = &pp->obj.rb;
-         a->rbb = &rp->obj.rb;
-         a->conet = cosf( inf->conet )-0.0001f;
-         
-         /* Store constraint in local space vectors */
-         m3x3_mulv( c->rba->to_local, inf->conevx, a->conevx );
-         m3x3_mulv( c->rba->to_local, inf->conevy, a->conevy );
-         m3x3_mulv( c->rbb->to_local, inf->coneva, a->coneva );
-         v3_copy( c->lca, a->view_offset );
-         
-         v3_cross( inf->coneva, inf->conevy, a->conevxb );
-         m3x3_mulv( c->rbb->to_local, a->conevxb, a->conevxb );
-
-         v3_normalize( a->conevxb );
-         v3_normalize( a->conevx );
-         v3_normalize( a->conevy );
-         v3_normalize( a->coneva );
-
-         a->conevx[3] = v3_length( inf->conevx );
-         a->conevy[3] = v3_length( inf->conevy );
-
-         rp->use_limits = 1;
-      }
-   }
-}
-
-/*
- * Make avatar copy the ragdoll
- */
+                                                 struct player_avatar *av );
 VG_STATIC void copy_ragdoll_pose_to_avatar( struct player_ragdoll *rd,
-                                            struct player_avatar *av )
-{
-   for( int i=0; i<rd->part_count; i++ ){
-      struct ragdoll_part *part = &rd->parts[i];
-
-      m4x3f mtx;
-
-      v4f q_int;
-      v3f co_int;
-
-      float substep = vg.time_fixed_extrapolate;
-      v3_lerp( part->prev_co, part->obj.rb.co, substep, co_int );
-      q_nlerp( part->prev_q, part->obj.rb.q, substep, q_int );
-
-      q_m3x3( q_int, mtx );
-      v3_copy( co_int, mtx[3] );
-
-      m4x3_mul( mtx, part->inv_collider_mtx, av->sk.final_mtx[part->bone_id] );
-   }
-
-   for( u32 i=1; i<av->sk.bone_count; i++ ){
-      struct skeleton_bone *sb = &av->sk.bones[i];
-
-      if( sb->parent && !sb->collider ){
-         v3f delta;
-         v3_sub( av->sk.bones[i].co, av->sk.bones[sb->parent].co, delta );
-
-         m4x3f posemtx;
-         m3x3_identity( posemtx );
-         v3_copy( delta, posemtx[3] );
-
-         /* final matrix */
-         m4x3_mul( av->sk.final_mtx[sb->parent], posemtx, av->sk.final_mtx[i] );
-      }
-   }
-
-   skeleton_apply_inverses( &av->sk );
-}
-
-/*
- * Make the ragdoll copy the player model
- */
+                                            struct player_avatar *av );
 VG_STATIC void copy_avatar_pose_to_ragdoll( struct player_avatar *av,
                                             struct player_ragdoll *rd,
-                                            v3f velocity )
-{
-   for( int i=0; i<rd->part_count; i++ ){
-      struct ragdoll_part *part = &rd->parts[i];
-
-      v3f pos, offset;
-      u32 bone = part->bone_id;
-
-      m4x3_mulv( av->sk.final_mtx[bone], av->sk.bones[bone].co, pos );
-      m3x3_mulv( av->sk.final_mtx[bone], part->collider_mtx[3], offset );
-      v3_add( pos, offset, part->obj.rb.co );
-
-      m3x3f r;
-      m3x3_mul( av->sk.final_mtx[bone], part->collider_mtx, r );
-      m3x3_q( r, part->obj.rb.q );
-
-      v3_copy( velocity, part->obj.rb.v );
-      v3_zero( part->obj.rb.w );
-
-      v3_copy( part->obj.rb.co, part->prev_co );
-      v4_copy( part->obj.rb.q, part->prev_q );
-      
-      rb_update_transform( &part->obj.rb );
-   }
-}
-
-/*
- * Draw rigidbody colliders for ragdoll
- */
-VG_STATIC void player_debug_ragdoll(void)
-{
-}
-
-/*
- * Ragdoll physics step
- */
-VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd )
-{
-   world_instance *world = get_active_world();
-
-   int run_sim = 0;
-   ragdoll_frame ++;
-
-   if( ragdoll_frame >= k_ragdoll_div ){
-      ragdoll_frame = 0;
-      run_sim = 1;
-   }
-
-   rb_solver_reset();
-   
-   float contact_velocities[256];
-
-   for( int i=0; i<rd->part_count; i ++ ){
-      v4_copy( rd->parts[i].obj.rb.q, rd->parts[i].prev_q );
-      v3_copy( rd->parts[i].obj.rb.co, rd->parts[i].prev_co );
-
-      if( rb_global_has_space() ){
-         rb_ct *buf = rb_global_buffer();
-
-         int l;
-         
-         if( rd->parts[i].obj.type == k_rb_shape_capsule ){
-            l = rb_capsule__scene( rd->parts[i].obj.rb.to_world,
-                                   &rd->parts[i].obj.inf.capsule,
-                                   NULL, &world->rb_geo.inf.scene, buf );
-         }
-         else if( rd->parts[i].obj.type == k_rb_shape_box ){
-            l = rb_box__scene( rd->parts[i].obj.rb.to_world,
-                               rd->parts[i].obj.rb.bbx,
-                               NULL, &world->rb_geo.inf.scene, buf );
-         }
-         else continue;
-
-         for( int j=0; j<l; j++ ){
-            buf[j].rba = &rd->parts[i].obj.rb;
-            buf[j].rbb = &world->rb_geo.rb;
-         }
-
-         rb_contact_count += l;
-      }
-   }
-
-   /* 
-    * self-collision
-    */
-   for( int i=0; i<rd->part_count-1; i ++ ){
-      for( int j=i+1; j<rd->part_count; j ++ ){
-         if( rd->parts[j].parent != i ){
-            if( !rb_global_has_space() )
-               break;
-
-            if( rd->parts[j].obj.type != k_rb_shape_capsule )
-               continue;
-
-            if( rd->parts[i].obj.type != k_rb_shape_capsule )
-               continue;
-
-            rb_ct *buf = rb_global_buffer();
-
-            int l = rb_capsule__capsule( rd->parts[i].obj.rb.to_world,
-                                         &rd->parts[i].obj.inf.capsule,
-                                         rd->parts[j].obj.rb.to_world,
-                                         &rd->parts[j].obj.inf.capsule,
-                                         buf );
-
-            for( int k=0; k<l; k++ ){
-               buf[k].rba = &rd->parts[i].obj.rb;
-               buf[k].rbb = &rd->parts[j].obj.rb;
-            }
-
-            rb_contact_count += l;
-         }
-      }
-   }
-
-   for( int j=0; j<rd->part_count; j++ ){
-      struct ragdoll_part *pj = &rd->parts[j];
-
-      if( run_sim ){
-         v4f plane = {0.0f,1.0f,0.0f,0.0f};
-         rb_effect_simple_bouyency( &pj->obj.rb, plane, 
-                                     k_ragdoll_floatyiness,
-                                     k_ragdoll_floatydrag );
-      }
-   }
-
-   /*
-    * PRESOLVE
-    */
-   for( u32 i=0; i<rb_contact_count; i++ ){
-      rb_ct *ct = &rb_contact_buffer[i];
-
-      v3f rv, ra, rb;
-      v3_sub( ct->co, ct->rba->co, ra );
-      v3_sub( ct->co, ct->rbb->co, rb );
-      rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
-      float     vn = v3_dot( rv, ct->n );
-
-      contact_velocities[i] = vn;
-   }
-
-   rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
-   rb_presolve_swingtwist_constraints( rd->cone_constraints,
-                                       rd->cone_constraints_count );
-
-   /* 
-    * DEBUG
-    */
-   if( k_ragdoll_debug_collider ){
-      for( u32 i=0; i<rd->part_count; i ++ )
-         rb_object_debug( &rd->parts[i].obj, rd->parts[i].colour );
-   }
-
-   if( k_ragdoll_debug_constraints ){
-      rb_debug_position_constraints( rd->position_constraints, 
-                                     rd->position_constraints_count );
-
-      rb_debug_swingtwist_constraints( rd->cone_constraints,
-                                       rd->cone_constraints_count );
-   }
-
-   /*
-    * SOLVE CONSTRAINTS 
-    */
-   if( run_sim ){
-      for( int i=0; i<16; i++ ){
-         rb_solve_contacts( rb_contact_buffer, rb_contact_count );
-         rb_solve_swingtwist_constraints( rd->cone_constraints, 
-                                          rd->cone_constraints_count );
-         rb_solve_position_constraints( rd->position_constraints, 
-                                        rd->position_constraints_count );
-      }
-
-      for( int i=0; i<rd->part_count; i++ )
-         rb_iter( &rd->parts[i].obj.rb );
-
-      for( int i=0; i<rd->part_count; i++ )
-         rb_update_transform( &rd->parts[i].obj.rb );
-
-      rb_correct_swingtwist_constraints( rd->cone_constraints, 
-                                         rd->cone_constraints_count, 0.25f );
-
-      rb_correct_position_constraints( rd->position_constraints,
-                                       rd->position_constraints_count, 0.5f );
-   }
-
-   rb_ct *stress = NULL;
-   float max_stress = 1.0f;
-
-   for( u32 i=0; i<rb_contact_count; i++ ){
-      rb_ct *ct = &rb_contact_buffer[i];
-
-      v3f rv, ra, rb;
-      v3_sub( ct->co, ct->rba->co, ra );
-      v3_sub( ct->co, ct->rbb->co, rb );
-      rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
-      float vn = v3_dot( rv, ct->n );
-
-      float s = fabsf(vn - contact_velocities[i]);
-      if( s > max_stress ){
-         stress = ct;
-         max_stress = s;
-      }
-   }
-
-   static u32 temp_filter = 0;
-
-   if( temp_filter ){
-      temp_filter --;
-      return;
-   }
-
-   if( stress ){
-      temp_filter = 20;
-      audio_lock();
-      audio_oneshot_3d( &audio_hits[rand()%5], stress->co, 20.0f, 1.0f );
-      audio_unlock();
-   }
-}
+                                            v3f velocity );
+VG_STATIC void player_debug_ragdoll(void);
+VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd );
 
 #endif /* PLAYER_RAGDOLL_H */
diff --git a/player_render.c b/player_render.c
new file mode 100644 (file)
index 0000000..ab89422
--- /dev/null
@@ -0,0 +1,393 @@
+#ifndef PLAYER_RENDER_C
+#define PLAYER_RENDER_C
+
+#include "player.h"
+#include "player_render.h"
+#include "camera.h"
+#include "player_model.h"
+
+#include "shaders/model_character_view.h"
+#include "shaders/model_board_view.h"
+
+VG_STATIC void player_avatar_load( struct player_avatar *av, const char *path )
+{
+   mdl_open( &av->meta, path, vg_mem.rtmemory );
+   mdl_load_metadata_block( &av->meta, vg_mem.rtmemory );
+   mdl_load_animation_block( &av->meta, vg_mem.rtmemory );
+   mdl_close( &av->meta );
+
+   struct skeleton *sk = &av->sk;
+   skeleton_setup( sk, vg_mem.rtmemory, &av->meta );
+
+   av->id_hip        = skeleton_bone_id( sk, "hips" );
+   av->id_ik_hand_l  = skeleton_bone_id( sk, "hand.IK.L" );
+   av->id_ik_hand_r  = skeleton_bone_id( sk, "hand.IK.R" );
+   av->id_ik_elbow_l = skeleton_bone_id( sk, "elbow.L" );
+   av->id_ik_elbow_r = skeleton_bone_id( sk, "elbow.R" );
+   av->id_head       = skeleton_bone_id( sk, "head" );
+   av->id_ik_foot_l  = skeleton_bone_id( sk, "foot.IK.L" );
+   av->id_ik_foot_r  = skeleton_bone_id( sk, "foot.IK.R" );
+   av->id_board      = skeleton_bone_id( sk, "board" );
+   av->id_wheel_l    = skeleton_bone_id( sk, "wheel.L" );
+   av->id_wheel_r    = skeleton_bone_id( sk, "wheel.R" );
+   av->id_ik_knee_l  = skeleton_bone_id( sk, "knee.L" );
+   av->id_ik_knee_r  = skeleton_bone_id( sk, "knee.R" );
+}
+
+/* TODO: Standard model load */
+
+VG_STATIC void player_model_load( struct player_model *mdl, const char *path )
+{
+   vg_linear_clear( vg_mem.scratch );
+
+   mdl_context ctx;
+   mdl_open( &ctx, path, vg_mem.scratch );
+   mdl_load_metadata_block( &ctx, vg_mem.scratch );
+   mdl_load_mesh_block( &ctx, vg_mem.scratch );
+
+   if( !mdl_arrcount( &ctx.textures ) )
+      vg_fatal_exit_loop( "No texture in player model" );
+
+   mdl_texture *tex0 = mdl_arritm( &ctx.textures, 0 );
+   void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
+   mdl_fread_pack_file( &ctx, &tex0->file, data );
+
+   vg_acquire_thread_sync();
+   {
+      mdl_unpack_glmesh( &ctx, &mdl->mesh );
+
+      /* upload first texture */
+      mdl->texture = vg_tex2d_new();
+
+      vg_tex2d_set_error();
+      vg_tex2d_qoi( data, tex0->file.pack_size,
+                    mdl_pstr( &ctx, tex0->file.pstr_path ));
+      vg_tex2d_nearest();
+      vg_tex2d_clamp();
+   }
+   vg_release_thread_sync();
+
+   mdl_close( &ctx );
+}
+
+VG_STATIC void player_board_load( struct player_board *mdl, const char *path )
+{
+   vg_linear_clear( vg_mem.scratch );
+
+   mdl_context ctx;
+   mdl_open( &ctx, path, vg_mem.scratch );
+   mdl_load_metadata_block( &ctx, vg_mem.scratch );
+   mdl_load_mesh_block( &ctx, vg_mem.scratch );
+
+   mdl_array_ptr markers;
+   mdl_load_array( &ctx, &markers, "ent_marker", vg_mem.scratch );
+
+   if( !mdl_arrcount( &ctx.textures ) )
+      vg_fatal_exit_loop( "No texture in board model" );
+
+   mdl_texture *tex0 = mdl_arritm( &ctx.textures, 0 );
+   void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
+   mdl_fread_pack_file( &ctx, &tex0->file, data );
+
+   vg_acquire_thread_sync();
+   {
+      mdl_unpack_glmesh( &ctx, &mdl->mesh );
+
+      /* upload first texture */
+      mdl->texture = vg_tex2d_new();
+
+      vg_tex2d_set_error();
+      vg_tex2d_qoi( data, tex0->file.pack_size,
+                    mdl_pstr( &ctx, tex0->file.pstr_path ));
+      vg_tex2d_nearest();
+      vg_tex2d_clamp();
+   }
+   vg_release_thread_sync();
+
+   mdl_close( &ctx );
+
+   for( int i=0; i<4; i++ )
+      mdl->wheels[i].indice_count = 0;
+   for( int i=0; i<2; i++ )
+      mdl->trucks[i].indice_count = 0;
+   mdl->board.indice_count = 0;
+
+   for( u32 i=0; i<mdl_arrcount(&ctx.meshs); i++ ){
+      mdl_mesh *mesh = mdl_arritm( &ctx.meshs, i );
+
+      vg_info( "[%u]=%u:%u\n", mesh->entity_id,
+                          mdl_entity_id_type( mesh->entity_id ),
+                          mdl_entity_id_id( mesh->entity_id ) );
+
+      if( mdl_entity_id_type( mesh->entity_id ) != k_ent_marker )
+         continue;
+
+      u32 index = mdl_entity_id_id( mesh->entity_id );
+      ent_marker *marker = mdl_arritm( &markers, index );
+
+      mdl_submesh *sm0 = mdl_arritm( &ctx.submeshs, mesh->submesh_start );
+      
+      const char *alias = mdl_pstr( &ctx, marker->pstr_alias );
+      u32 lr = marker->transform.co[0] > 0.0f? 1: 0,
+          fb = marker->transform.co[2] > 0.0f? 0: 1;
+
+      if( !strcmp( alias, "wheel" ) ){
+         u32 id = fb<<1 | lr;
+         mdl->wheels[ id ] = *sm0;
+         v3_copy( marker->transform.co, mdl->wheel_positions[ id ] );
+      }
+      else if( !strcmp( alias, "board" ) ){
+         mdl->board = *sm0;
+         v3_copy( marker->transform.co, mdl->board_position );
+      }
+      else if( !strcmp( alias, "truck" ) ){
+         mdl->trucks[ fb ] = *sm0;
+         v3_copy( marker->transform.co, mdl->truck_positions[ fb ] );
+      }
+   }
+}
+
+VG_STATIC void player__pre_render( player_instance *player )
+{
+   if( _player_animate[ player->subsystem ] ){
+      player_animation res;
+      _player_animate[ player->subsystem ]( player, &res );
+
+      m4x3f transform;
+      q_m3x3( res.root_q, transform );
+      v3_copy( res.root_co, transform[3] );
+
+      struct skeleton *sk = &player->playeravatar->sk;
+
+      if( player->holdout_time > 0.0f ){
+         skeleton_lerp_pose( sk, res.pose, player->holdout_pose, 
+                                           player->holdout_time, res.pose );
+         player->holdout_time -= vg.time_frame_delta * 2.0f;
+      }
+
+      skeleton_apply_pose( sk, res.pose, k_anim_apply_defer_ik );
+      skeleton_apply_ik_pass( sk );
+      skeleton_apply_pose( sk, res.pose, k_anim_apply_deffered_only );
+      skeleton_apply_inverses( sk );
+      skeleton_apply_transform( sk, transform );
+
+      skeleton_debug( sk );
+   }
+
+   if( _player_post_animate[ player->subsystem ] )
+      _player_post_animate[ player->subsystem ]( player );
+
+   struct player_avatar *av = player->playeravatar;
+
+   v3f vp0 = {0.0f,0.1f, player->playerboard->truck_positions[0][2]},
+       vp1 = {0.0f,0.1f, player->playerboard->truck_positions[1][2]};
+
+   struct ub_world_lighting *ubo = &get_active_world()->ub_lighting;
+   m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, ubo->g_board_0 );
+   m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp1, ubo->g_board_1 );
+
+   if( player->rewinding ){
+      if( player->rewind_time <= 0.0f ){
+         double taken = vg.time - player->rewind_start;
+         vg_success( "Rewind took (rt, pt, tl): %f, %f, %f\n", 
+                           taken, player->rewind_predicted_time,
+                           player->rewind_total_length );
+
+         player->rewinding = 0;
+         player->rewind_length = 1;
+         player->rewind_total_length = 0.0f;
+         player->rewind_accum = 0.0f;
+         world_global.sky_target_rate = 1.0;
+         world_global.time = world_global.last_use;
+      }
+      else{
+         world_global.sky_target_rate = -100.0;
+
+         float budget         = vg.time_delta,
+               overall_length = player->rewind_length;
+
+         for( int i=0; (i<10)&&(player->rewind_time>0.0f)&&(budget>0.0f); i++ ){
+            /* Interpolate frames */
+            int i0 = floorf( player->rewind_time ),
+                i1 = VG_MIN( i0+1, player->rewind_length-1 );
+            
+            struct rewind_frame *fr =  &player->rewind_buffer[i0],
+                                *fr1 = &player->rewind_buffer[i1];
+
+            float dist = vg_maxf( v3_dist( fr->pos, fr1->pos ), 0.001f ),
+                  subl = vg_fractf( player->rewind_time ) + 0.001f,
+
+                  sramp = 3.0f-(1.0f/(0.4f+0.4f*player->rewind_time)),
+                  speed = sramp*28.0f + 0.5f*player->rewind_time,
+                  mod  = speed * (budget / dist),
+
+                  advl = vg_minf( mod, subl ),
+                  advt = (advl / mod) * budget;
+            
+            player->dist_accum += speed * advt;
+            player->rewind_time -= advl;
+            budget -= advt;
+         }
+
+         player->rewind_time = vg_maxf( 0.0f, player->rewind_time );
+
+         float current_time = vg.time - player->rewind_start,
+               remaining    = player->rewind_predicted_time - current_time;
+
+         if( player->rewind_sound_wait ){
+            if( player->rewind_predicted_time >= 6.5f ){
+               if( remaining <= 6.5f ){
+                  audio_lock();
+                  audio_oneshot( &audio_rewind[3], 1.0f, 0.0f );
+                  audio_unlock();
+                  player->rewind_sound_wait = 0;
+               }
+            }
+            else if( player->rewind_predicted_time >= 2.5f ){
+               if( remaining <= 2.5f ){
+                  audio_lock();
+                  audio_oneshot( &audio_rewind[2], 1.0f, 0.0f );
+                  audio_unlock();
+                  player->rewind_sound_wait = 0;
+               }
+            }
+            else if( player->rewind_predicted_time >= 1.5f ){
+               if( remaining <= 1.5f ){
+                  audio_lock();
+                  audio_oneshot( &audio_rewind[1], 1.0f, 0.0f );
+                  audio_unlock();
+                  player->rewind_sound_wait = 0;
+               }
+            }
+         }
+         
+         int i0 = floorf( player->rewind_time ),
+             i1 = VG_MIN( i0+1, player->rewind_length-1 );
+         
+         struct rewind_frame *fr =  &player->rewind_buffer[i0],
+                             *fr1 = &player->rewind_buffer[i1];
+         
+         float sub = vg_fractf(player->rewind_time);
+
+         v3_lerp( fr->pos, fr1->pos, sub, player->cam_override_pos );
+         player->cam_override_angles[0] = 
+            vg_alerpf( fr->ang[0], fr1->ang[0], sub );
+         player->cam_override_angles[1] = 
+            vg_lerpf ( fr->ang[1], fr1->ang[1], sub );
+
+         float blend = player->rewind_time * 0.25f;
+         player->cam_override_strength = vg_clampf( blend, 0.0f, 1.0f );
+      }
+   }
+   else player->cam_override_strength = 0.0f;
+
+   player__cam_iterate( player );
+}
+
+PLAYER_API void player__render( camera *cam, player_instance *player )
+{
+   shader_model_character_view_use();
+
+       glActiveTexture( GL_TEXTURE0 );
+       glBindTexture( GL_TEXTURE_2D, player->playermodel->texture );
+   shader_model_character_view_uTexMain( 0 );
+   shader_model_character_view_uCamera( cam->transform[3] );
+   shader_model_character_view_uPv( cam->mtx.pv );
+   shader_model_character_view_uTexSceneDepth( 1 );
+   render_fb_bind_texture( gpipeline.fb_main, 2, 1 );
+   v3f inverse;
+   render_fb_inverse_ratio( gpipeline.fb_main, inverse );
+   inverse[2] = main_camera.farz-main_camera.nearz;
+
+   shader_model_character_view_uInverseRatioDepth( inverse );
+   render_fb_inverse_ratio( NULL, inverse );
+   inverse[2] = cam->farz-cam->nearz;
+   shader_model_character_view_uInverseRatioMain( inverse );
+
+   world_instance *world = get_active_world();
+   world_link_lighting_ub( world, _shader_model_character_view.id );
+   world_bind_position_texture( world, _shader_model_character_view.id,
+                              _uniform_model_character_view_g_world_depth, 2 );
+   world_bind_light_array( world, _shader_model_character_view.id,
+                              _uniform_model_character_view_uLightsArray, 3 );
+   world_bind_light_index( world, _shader_model_character_view.id,
+                              _uniform_model_character_view_uLightsIndex, 4 );
+
+   glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms,
+                         player->playeravatar->sk.bone_count,
+                         0,
+                         (float *)player->playeravatar->sk.final_mtx );
+   
+   mesh_bind( &player->playermodel->mesh );
+   mesh_draw( &player->playermodel->mesh );
+
+   /* draw skateboard */
+   shader_model_board_view_use();
+       glActiveTexture( GL_TEXTURE0 );
+   glBindTexture( GL_TEXTURE_2D, player->playerboard->texture );
+   shader_model_board_view_uTexMain( 0 );
+   shader_model_board_view_uCamera( cam->transform[3] );
+   shader_model_board_view_uPv( cam->mtx.pv );
+   shader_model_board_view_uTexSceneDepth( 1 );
+
+   render_fb_inverse_ratio( gpipeline.fb_main, inverse );
+   inverse[2] = main_camera.farz-main_camera.nearz;
+
+   shader_model_board_view_uInverseRatioDepth( inverse );
+   render_fb_inverse_ratio( NULL, inverse );
+   inverse[2] = cam->farz-cam->nearz;
+   shader_model_board_view_uInverseRatioMain( inverse );
+
+   world_link_lighting_ub( world, _shader_model_board_view.id );
+   world_bind_position_texture( world, _shader_model_board_view.id,
+                              _uniform_model_board_view_g_world_depth, 2 );
+   world_bind_light_array( world, _shader_model_board_view.id,
+                              _uniform_model_board_view_uLightsArray, 3 );
+   world_bind_light_index( world, _shader_model_board_view.id,
+                              _uniform_model_board_view_uLightsIndex, 4 );
+
+   m4x3f root;
+   m4x3_copy( player->playeravatar->sk.final_mtx[player->playeravatar->id_board]
+              , root );
+
+   struct player_board *board = player->playerboard;
+   mesh_bind( &board->mesh );
+
+   if( board->board.indice_count ){
+      m4x3f mlocal;
+      m3x3_identity( mlocal );
+      v3_copy( board->board_position, mlocal[3] );
+      m4x3_mul( root, mlocal, mlocal );
+
+      shader_model_board_view_uMdl( mlocal );
+      mdl_draw_submesh( &board->board );
+   }
+
+   for( int i=0; i<2; i++ ){
+      if( !board->trucks[i].indice_count )
+         continue;
+
+      m4x3f mlocal;
+      m3x3_identity( mlocal );
+      v3_copy( board->truck_positions[i], mlocal[3] );
+      m4x3_mul( root, mlocal, mlocal );
+
+      shader_model_board_view_uMdl( mlocal );
+      mdl_draw_submesh( &board->trucks[i] );
+   }
+
+   for( int i=0; i<4; i++ ){
+      if( !board->wheels[i].indice_count )
+         continue;
+
+      m4x3f mlocal;
+      m3x3_identity( mlocal );
+      v3_copy( board->wheel_positions[i], mlocal[3] );
+      m4x3_mul( root, mlocal, mlocal );
+
+      shader_model_board_view_uMdl( mlocal );
+      mdl_draw_submesh( &board->wheels[i] );
+   }
+}
+
+#endif /* PLAYER_RENDER_C */
diff --git a/player_render.h b/player_render.h
new file mode 100644 (file)
index 0000000..e9d17bb
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef PLAYER_RENDER_H
+#define PLAYER_RENDER_H
+
+#include "model.h"
+#include "skeleton.h"
+
+struct player_avatar
+{
+   mdl_context meta;
+   struct skeleton sk;
+
+   u32 id_hip,
+       id_ik_hand_l,
+       id_ik_hand_r,
+       id_ik_elbow_l,
+       id_ik_elbow_r,
+       id_head,
+       id_ik_foot_l,
+       id_ik_foot_r,
+       id_ik_knee_l,
+       id_ik_knee_r,
+       id_wheel_l,
+       id_wheel_r,
+       id_board;
+};
+
+struct player_model
+{
+   glmesh mesh;
+   GLuint texture;
+};
+
+enum eboard_truck{
+   k_board_truck_back = 0,
+   k_board_truck_front = 1
+};
+
+enum eboard_wheel{
+   k_board_wheel_fl = 0,
+   k_board_wheel_fr = 1,
+   k_board_wheel_bl = 2,
+   k_board_wheel_br = 3,
+};
+
+struct player_board
+{
+   glmesh mesh;
+   GLuint texture;
+
+   v4f wheel_positions[4],
+       truck_positions[2],
+       board_position;
+
+   mdl_submesh wheels[4],
+               trucks[2],
+               board;
+};
+
+#endif /* PLAYER_RENDER_H */
index fc10b7341fc0487cff6ba9b68ddde5f87efff120..7da514f7609f0639448d54ee899051c2f90ca345 100644 (file)
@@ -128,7 +128,7 @@ VG_STATIC int skate_grind_scansq( player_instance *player,
       v3f tri[3];
 
       struct world_surface *surf = world_tri_index_surface(world,ptri[0]);
-      if( !(surf->info.flags & k_material_flag_skate_surface) )
+      if( !(surf->info.flags & k_material_flag_grindable) )
          continue;
 
       for( int j=0; j<3; j++ )
@@ -532,11 +532,13 @@ void player__approximate_best_trajectory( player_instance *player )
             inf->score = -v3_dot( ve, inf->n );
             inf->land_dist = t + k_trace_delta * t1;
 
-            
             /* Bias prediction towords ramps */
-            if( !(surf->info.flags & k_material_flag_skate_surface) )
+            if( !(surf->info.flags & k_material_flag_skate_target) )
                inf->score *= 10.0f;
 
+            if( surf->info.flags & k_material_flag_boundary )
+               s->possible_jump_count --;
+
             break;
          }
          
@@ -2955,15 +2957,20 @@ VG_STATIC void player__skate_animate( player_instance *player,
       q_mul( kf_board->q, qtrick, kf_board->q );
       q_normalize( kf_board->q );
 
+      struct player_board *board = player->playerboard;
 
       /* foot weight distribution */
       if( s->blend_weight > 0.0f ){
-         kf_foot_l->co[2] += s->blend_weight * 0.2f;
-         kf_foot_r->co[2] += s->blend_weight * 0.1f;
+         kf_foot_l->co[2] = 
+            vg_lerpf( kf_foot_l->co[2], 
+                      board->truck_positions[k_board_truck_back][2]+0.3f, 
+                      0.5f*s->blend_weight );
       }
       else{
-         kf_foot_r->co[2] += s->blend_weight * 0.3f;
-         kf_foot_l->co[2] += s->blend_weight * 0.1f;
+         kf_foot_r->co[2] = 
+            vg_lerpf( kf_foot_r->co[2], 
+                      board->truck_positions[k_board_truck_front][2]-0.3f, 
+                      -0.5f*s->blend_weight );
       }
 
       float slapm = vg_maxf( 1.0f-v3_length2( s->state.trick_vel ), 0.0f );
diff --git a/shaders/model_board_view.h b/shaders/model_board_view.h
new file mode 100644 (file)
index 0000000..5b83ef2
--- /dev/null
@@ -0,0 +1,496 @@
+#ifndef SHADER_model_board_view_H
+#define SHADER_model_board_view_H
+static void shader_model_board_view_link(void);
+static void shader_model_board_view_register(void);
+static struct vg_shader _shader_model_board_view = {
+   .name = "model_board_view",
+   .link = shader_model_board_view_link,
+   .vs = 
+{
+.orig_file = "shaders/model.vs",
+.static_src = 
+"layout (location=0) in vec3 a_co;\n"
+"layout (location=1) in vec3 a_norm;\n"
+"layout (location=2) in vec2 a_uv;\n"
+"layout (location=3) in vec4 a_colour;\n"
+"layout (location=4) in vec4 a_weights;\n"
+"layout (location=5) in ivec4 a_groups;\n"
+"\n"
+"#line       1        1 \n"
+"const float k_motion_lerp_amount = 0.01;\n"
+"\n"
+"#line      2        0 \n"
+"\n"
+"out vec3 aMotionVec0;\n"
+"out vec3 aMotionVec1;\n"
+"\n"
+"void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n"
+"{\n"
+"   // This magically solves some artifacting errors!\n"
+"   //\n"
+"   vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n"
+"\n"
+"   aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n"
+"   aMotionVec1 = vec3( vproj1.xy, vproj1.w );\n"
+"}\n"
+"\n"
+"#line      9        0 \n"
+"\n"
+"uniform mat4x3 uMdl;\n"
+"uniform mat4 uPv;\n"
+"uniform mat4 uPvmPrev;\n"
+"\n"
+"out vec4 aColour;\n"
+"out vec2 aUv;\n"
+"out vec3 aNorm;\n"
+"out vec3 aCo;\n"
+"out vec3 aWorldCo;\n"
+"\n"
+"void main()\n"
+"{\n"
+"   vec3 world_pos0 = uMdl     * vec4( a_co, 1.0 );\n"
+"   vec4 vproj0     = uPv      * vec4( world_pos0, 1.0 );\n"
+"   vec4 vproj1     = uPvmPrev * vec4( a_co, 1.0 );\n"
+"\n"
+"   vs_motion_out( vproj0, vproj1 );\n"
+"\n"
+"   gl_Position = vproj0;\n"
+"   aWorldCo = world_pos0;\n"
+"   aColour = a_colour;\n"
+"   aUv = a_uv;\n"
+"   aNorm = mat3(uMdl) * a_norm;\n"
+"   aCo = a_co;\n"
+"}\n"
+""},
+   .fs = 
+{
+.orig_file = "shaders/model_character_view.fs",
+.static_src = 
+"uniform sampler2D uTexMain;\n"
+"uniform sampler2D uTexSceneDepth;\n"
+"uniform vec3 uCamera;\n"
+"uniform vec3 uInverseRatioDepth;\n"
+"uniform vec3 uInverseRatioMain;\n"
+"\n"
+"in vec4 aColour;\n"
+"in vec2 aUv;\n"
+"in vec3 aNorm;\n"
+"in vec3 aCo;\n"
+"in vec3 aWorldCo;\n"
+"\n"
+"#line       1        1 \n"
+"layout (location = 0) out vec4 oColour;\n"
+"\n"
+"// OpenGL wiki: Recommends do not use vec3 because of drivers. hence the v4s...\n"
+"layout (std140) uniform ub_world_lighting\n"
+"{\n"
+"   vec4 g_cube_min;\n"
+"   vec4 g_cube_inv_range;\n"
+"\n"
+"   vec4 g_water_plane;\n"
+"   vec4 g_depth_bounds;\n"
+"\n"
+"   vec4 g_daysky_colour;\n"
+"   vec4 g_nightsky_colour;\n"
+"   vec4 g_sunset_colour;\n"
+"   vec4 g_ambient_colour;\n"
+"   vec4 g_sunset_ambient;\n"
+"   vec4 g_sun_colour;\n"
+"   vec4 g_sun_dir;\n"
+"   vec4 g_board_0;\n"
+"   vec4 g_board_1;\n"
+"\n"
+"   float g_water_fog;\n"
+"   float g_time;\n"
+"   float g_realtime;\n"
+"   float g_shadow_length;\n"
+"   float g_shadow_spread;\n"
+"\n"
+"   float g_time_of_day;\n"
+"   float g_day_phase;\n"
+"   float g_sunset_phase;\n"
+"\n"
+"   int g_light_preview;\n"
+"   int g_shadow_samples;\n"
+"\n"
+"   int g_debug_indices;\n"
+"   int g_debug_complexity;\n"
+"};\n"
+"\n"
+"uniform sampler2D g_world_depth;\n"
+"uniform samplerBuffer uLightsArray;\n"
+"uniform usampler3D uLightsIndex;\n"
+"\n"
+"#line       1        1 \n"
+"//const vec3  DAYSKY_COLOUR   = vec3( 0.37, 0.54, 0.97 );\n"
+"//const vec3  NIGHTSKY_COLOUR = vec3( 0.03, 0.05, 0.20 );\n"
+"//const vec3  SUNSET_COLOUR   = vec3( 1.00, 0.32, 0.01 );\n"
+"//const vec3  AMBIENT_COLOUR  = vec3( 0.13, 0.17, 0.35 );\n"
+"//const vec3  SUNSET_AMBIENT  = vec3( 0.25, 0.17, 0.51 );\n"
+"//const vec3  SUN_COLOUR      = vec3( 1.10, 0.89, 0.35 );\n"
+"\n"
+"const float SUN_ANGLE       = 0.0001;\n"
+"const float PI              = 3.14159265;\n"
+"\n"
+"//struct world_info\n"
+"//{\n"
+"//   float time,\n"
+"//         time_of_day,\n"
+"//         day_phase,\n"
+"//         sunset_phase;\n"
+"//   \n"
+"//   vec3 sun_dir;\n"
+"//};\n"
+"\n"
+"float luminance( vec3 v )\n"
+"{\n"
+"   return dot( v, vec3(0.2126, 0.7152, 0.0722) );\n"
+"}\n"
+"\n"
+"vec3 clearskies_ambient( vec3 dir )\n"
+"{\n"
+"   float sun_azimuth  = g_sunset_phase * (dot( dir.xz, g_sun_dir.xz )*0.4+0.6);\n"
+"   float sky_gradient = dir.y;\n"
+"   \n"
+"   /* Blend phase colours */\n"
+"   vec3 ambient  = g_daysky_colour.rgb   * (g_day_phase-g_sunset_phase*0.1);\n"
+"        ambient += g_sunset_colour.rgb   * (1.0-dir.y*0.5)*sun_azimuth;\n"
+"        ambient += g_nightsky_colour.rgb * (1.0-g_day_phase);\n"
+"   \n"
+"   /* Add gradient */\n"
+"        ambient -= sky_gradient * luminance(ambient);\n"
+"        \n"
+"   return ambient;\n"
+"}\n"
+"\n"
+"vec3 clearskies_sky( vec3 ray_dir )\n"
+"{\n"
+"   ray_dir.y = abs( ray_dir.y );\n"
+"   vec3 sky_colour  = clearskies_ambient( ray_dir );\n"
+"   \n"
+"   /* Sun */\n"
+"   float sun_theta  = dot( ray_dir, g_sun_dir.xyz );\n"
+"   float sun_size   = max( 0.0, sun_theta * 0.5 + 0.5 + SUN_ANGLE );\n"
+"   float sun_shape  = pow( sun_size, 2000.0 );\n"
+"         sun_shape += sun_size * max(g_sun_dir.y,0.0) * 0.5;\n"
+"         \n"
+"   vec3 sun_colour  = mix( vec3(1.0), g_sunset_colour.rgb, g_sunset_phase*0.5 );\n"
+"        sun_colour *= sun_shape;\n"
+"   \n"
+"   vec3 composite   = sky_colour + sun_colour;\n"
+"   return composite;\n"
+"}\n"
+"\n"
+"vec3 clearskies_lighting( vec3 normal, float shadow, vec3 halfview )\n"
+"{\n"
+"   float fresnel = 1.0 - abs(dot(normal,halfview));\n"
+"\n"
+"   vec3  reflect_colour = mix( g_daysky_colour.rgb, g_sunset_colour.rgb, \n"
+"                               g_sunset_phase );\n"
+"\n"
+"   vec3  sky_reflection = 0.5 * fresnel * reflect_colour;\n"
+"   vec3  light_sun      = max(0.0,dot(normal,g_sun_dir.xyz)*0.75+0.25) \n"
+"                           * g_sun_colour.rgb * g_day_phase;\n"
+"\n"
+"   float scaled_shadow = max( shadow, 1.0 - max(g_sun_dir.y,0.0) );\n"
+"   vec3 ambient = mix( g_ambient_colour.rgb, g_sunset_ambient.rgb, \n"
+"                       g_sunset_phase );\n"
+"\n"
+"   return ambient + (light_sun + sky_reflection) * shadow;\n"
+"}\n"
+"\n"
+"#line     44        0 \n"
+"\n"
+"float world_depth_sample( vec3 pos )\n"
+"{\n"
+"   vec2 depth_coord = (pos.xz - g_depth_bounds.xy) * g_depth_bounds.zw; \n"
+"   return texture( g_world_depth, depth_coord ).r;\n"
+"}\n"
+"\n"
+"float world_water_depth( vec3 pos )\n"
+"{\n"
+"   float ref_depth = g_water_plane.y*g_water_plane.w;\n"
+"   return world_depth_sample( pos ) - ref_depth;\n"
+"}\n"
+"\n"
+"float shadow_sample( vec3 vdir )\n"
+"{\n"
+"   vec3 sample_pos = aWorldCo + vdir;\n"
+"   float height_sample = world_depth_sample( sample_pos );\n"
+"\n"
+"   float fdelta = height_sample - sample_pos.y;\n"
+"   return clamp( fdelta, 0.2, 0.4 )-0.2;\n"
+"}\n"
+"\n"
+"float newlight_compute_sun_shadow( vec3 dir )\n"
+"{\n"
+"   if( g_shadow_samples == 0 )\n"
+"   {\n"
+"      return 1.0;\n"
+"   }\n"
+"\n"
+"   float fspread = g_shadow_spread;\n"
+"   float flength = g_shadow_length;\n"
+"\n"
+"   float famt = 0.0;\n"
+"   famt += shadow_sample((dir+vec3(-0.56,0.55, 0.30)*fspread)*flength*0.1);\n"
+"   famt += shadow_sample((dir+vec3( 0.80,0.68, 0.34)*fspread)*flength*0.2);\n"
+"   famt += shadow_sample((dir+vec3( 0.78,0.07,-0.06)*fspread)*flength*0.3);\n"
+"   famt += shadow_sample((dir+vec3(-0.59,0.07,-0.42)*fspread)*flength*0.4);\n"
+"\n"
+"   //famt+=shadow_sample((dir+vec3(-0.790,-0.933,-0.875)*fspread)*flength*0.5);\n"
+"   //famt+=shadow_sample((dir+vec3( 0.807,-0.690, 0.472)*fspread)*flength*0.6);\n"
+"   //famt+=shadow_sample((dir+vec3( 0.522,-0.379, 0.350)*fspread)*flength*0.7);\n"
+"   //famt+=shadow_sample((dir+vec3( 0.483, 0.201, 0.306)*fspread)*flength*0.8);\n"
+"\n"
+"   return 1.0 - famt;\n"
+"}\n"
+"\n"
+"float newlight_specular( vec3 wnormal, vec3 dir, vec3 halfview, float exponent )\n"
+"{\n"
+"   vec3 specdir = reflect( -dir, wnormal );\n"
+"   return pow(max(dot( halfview, specdir ), 0.0), exponent);\n"
+"}\n"
+"\n"
+"vec3 scene_apply_fog( vec3 vfrag, vec3 colour, float fdist )\n"
+"{\n"
+"   float dist = pow(fdist*0.0010,0.78);\n"
+"   return mix( vfrag, colour, min( 1.0, dist ) );\n"
+"}\n"
+"\n"
+"vec3 rand33(vec3 p3)\n"
+"{\n"
+"      p3 = fract(p3 * vec3(.1031, .1030, .0973));\n"
+"   p3 += dot(p3, p3.yxz+33.33);\n"
+"   return fract((p3.xxy + p3.yxx)*p3.zyx);\n"
+"}\n"
+"\n"
+"vec3 scene_calculate_light( int light_index, \n"
+"                            vec3 halfview, vec3 co, vec3 normal )\n"
+"{\n"
+"   vec4 light_colour = texelFetch( uLightsArray, light_index+0 );\n"
+"   vec4 light_co     = texelFetch( uLightsArray, light_index+1 );\n"
+"   vec4 light_dir    = texelFetch( uLightsArray, light_index+2 );\n"
+"\n"
+"   vec3 light_delta = light_co.xyz-co;\n"
+"   float dist2 = dot(light_delta,light_delta);\n"
+"\n"
+"   light_delta = normalize( light_delta );\n"
+"\n"
+"   float quadratic = dist2*100.0;\n"
+"   float attenuation  = 1.0f/( 1.0f + quadratic );\n"
+"         attenuation *= max( dot( light_delta, normal ), 0.0 );\n"
+"\n"
+"   float falloff = max( 0.0, 1.0-(dist2*light_co.w) );\n"
+"\n"
+"   if( light_dir.w < 0.999999 ){\n"
+"      float spot_theta = max( 0.0, dot( light_delta, -light_dir.xyz ) );\n"
+"      falloff *= max( 0.0, (spot_theta - light_dir.w) / (1.0-light_dir.w) );\n"
+"   }\n"
+"\n"
+"   return light_colour.rgb * attenuation * falloff \n"
+"            * step( g_day_phase, light_colour.w );\n"
+"}\n"
+"\n"
+"vec3 scene_calculate_packed_light_patch( uint packed_index, \n"
+"                                         vec3 halfview, vec3 co, vec3 normal )\n"
+"{\n"
+"   uint light_count = packed_index & 0x3u;\n"
+"\n"
+"   vec3 l = vec3(0.0);\n"
+"\n"
+"   if( light_count >= 1u ){\n"
+"      int index_0 = int( ((packed_index >>  2u) & 0x3ffu) * 3u );\n"
+"      int index_1 = int( ((packed_index >> 12u) & 0x3ffu) * 3u );\n"
+"      int index_2 = int( ((packed_index >> 22u) & 0x3ffu) * 3u );\n"
+"\n"
+"      l += scene_calculate_light( index_0, halfview, co, normal );\n"
+"\n"
+"      if( light_count >= 2u ){\n"
+"         l += scene_calculate_light( index_1, halfview, co, normal );\n"
+"\n"
+"         if( light_count >= 3u ){\n"
+"            l += scene_calculate_light( index_2, halfview, co, normal );\n"
+"         }\n"
+"      }\n"
+"   }\n"
+"\n"
+"   return l;\n"
+"}\n"
+"\n"
+"vec3 world_compute_lighting( vec3 diffuse, vec3 normal, vec3 co,\n"
+"                             float light_mask )\n"
+"{\n"
+"   if( g_light_preview == 1 )\n"
+"      diffuse = vec3(0.75);\n"
+"\n"
+"   // Lighting\n"
+"   vec3 halfview = uCamera - co;\n"
+"   float fdist = length(halfview);\n"
+"   halfview /= fdist;\n"
+"\n"
+"   float world_shadow = newlight_compute_sun_shadow( g_sun_dir.xyz \n"
+"                                    * (1.0/(max(g_sun_dir.y,0.0)+0.2)) );\n"
+"\n"
+"   vec3 total_light = clearskies_lighting( \n"
+"                           normal, min( light_mask, world_shadow ), halfview );\n"
+"\n"
+"   vec3 cube_coord = (co - g_cube_min.xyz) * g_cube_inv_range.xyz;\n"
+"        cube_coord = floor( cube_coord );\n"
+"\n"
+"   if( g_debug_indices == 1 )\n"
+"   {\n"
+"      return rand33(cube_coord);\n"
+"   }\n"
+"\n"
+"   if( g_debug_complexity == 1 )\n"
+"   {\n"
+"      ivec3 coord = ivec3( cube_coord );\n"
+"      uvec4 index_sample = texelFetch( uLightsIndex, coord, 0 );\n"
+"\n"
+"      uint light_count = (index_sample.x & 0x3u) + (index_sample.y & 0x3u);\n"
+"      return vec3( float(light_count)*(1.0/6.0), 0.0, 0.5 );\n"
+"   }\n"
+"\n"
+"   // FIXME: this coord should absolutely must be clamped!\n"
+"   \n"
+"   ivec3 coord = ivec3( cube_coord );\n"
+"   uvec4 index_sample = texelFetch( uLightsIndex, coord, 0 );\n"
+"\n"
+"   total_light += \n"
+"      scene_calculate_packed_light_patch( index_sample.x,\n"
+"                                          halfview, co, normal ) \n"
+"                                          * light_mask;\n"
+"   total_light += \n"
+"      scene_calculate_packed_light_patch( index_sample.y,\n"
+"                                          halfview, co, normal )\n"
+"                                          * light_mask;\n"
+"\n"
+"   // Take a section of the sky function to give us a matching fog colour\n"
+"\n"
+"   vec3 fog_colour  = clearskies_ambient( -halfview );\n"
+"   float sun_theta  = dot( -halfview, g_sun_dir.xyz );\n"
+"   float sun_size   = max( 0.0, sun_theta * 0.5 + 0.5 );\n"
+"   float sun_shape  = sun_size * max(g_sun_dir.y,0.0) * 0.5;\n"
+"         \n"
+"   vec3 sun_colour  = mix( vec3(1.0), g_sunset_colour.rgb, g_sunset_phase*0.5 );\n"
+"        sun_colour *= sun_shape;\n"
+"\n"
+"   fog_colour += sun_colour;\n"
+"   return scene_apply_fog( diffuse * total_light, fog_colour, fdist );\n"
+"}\n"
+"\n"
+"#line     14        0 \n"
+"#line       1        2 \n"
+"const float k_motion_lerp_amount = 0.01;\n"
+"\n"
+"#line      2        0 \n"
+"\n"
+"layout (location = 1) out vec2 oMotionVec;\n"
+"\n"
+"in vec3 aMotionVec0;\n"
+"in vec3 aMotionVec1;\n"
+"\n"
+"void compute_motion_vectors()\n"
+"{\n"
+"   // Write motion vectors\n"
+"   vec2 vmotion0 = aMotionVec0.xy / aMotionVec0.z;\n"
+"   vec2 vmotion1 = aMotionVec1.xy / aMotionVec1.z;\n"
+"\n"
+"   oMotionVec = (vmotion1-vmotion0) * (1.0/k_motion_lerp_amount);\n"
+"}\n"
+"\n"
+"#line     15        0 \n"
+"\n"
+"float linear_depth( float depth, float near, float far ) \n"
+"{\n"
+"   float z = depth * 2.0 - 1.0;\n"
+"   return (2.0 * near * far) / (far + near - z * (far - near));       \n"
+"}\n"
+"\n"
+"void main()\n"
+"{\n"
+"   compute_motion_vectors();\n"
+"\n"
+"   vec3 qnorm     = normalize(floor(aNorm*2.0)*0.5) + vec3(0.001,0.0,0.0);\n"
+"   vec3 diffuse   = texture( uTexMain, aUv ).rgb;\n"
+"   vec3 composite = world_compute_lighting( diffuse, qnorm, aWorldCo, 1.0 );\n"
+"\n"
+"   float dist    = distance( aWorldCo, uCamera ) - 0.08;\n"
+"   float opacity = clamp( dist*dist, 0.0, 1.0 );\n"
+"\n"
+"   vec2 back_coord = gl_FragCoord.xy*uInverseRatioMain.xy*uInverseRatioDepth.xy;\n"
+"   float back_depth = texture( uTexSceneDepth, back_coord ).r;\n"
+"   float front_depth = gl_FragCoord.z/gl_FragCoord.w;\n"
+"\n"
+"   back_depth = linear_depth( back_depth, 0.1, 2100.0 );\n"
+"   float diff = back_depth - front_depth;\n"
+"\n"
+"   vec2 ssuv = gl_FragCoord.xy;\n"
+"   vec3 vDither = vec3( dot( vec2( 171.0, 231.0 ), ssuv) );\n"
+"   float dither = fract( vDither.g / 71.0 ) - 0.5;\n"
+"\n"
+"   if( step(0.0,diff)+dither<0.3 )\n"
+"      discard;\n"
+"\n"
+"   oColour = vec4( composite, opacity );\n"
+"}\n"
+""},
+};
+
+static GLuint _uniform_model_board_view_uMdl;
+static GLuint _uniform_model_board_view_uPv;
+static GLuint _uniform_model_board_view_uPvmPrev;
+static GLuint _uniform_model_board_view_uTexMain;
+static GLuint _uniform_model_board_view_uTexSceneDepth;
+static GLuint _uniform_model_board_view_uCamera;
+static GLuint _uniform_model_board_view_uInverseRatioDepth;
+static GLuint _uniform_model_board_view_uInverseRatioMain;
+static GLuint _uniform_model_board_view_g_world_depth;
+static GLuint _uniform_model_board_view_uLightsArray;
+static GLuint _uniform_model_board_view_uLightsIndex;
+static void shader_model_board_view_uMdl(m4x3f m){
+   glUniformMatrix4x3fv(_uniform_model_board_view_uMdl,1,GL_FALSE,(float*)m);
+}
+static void shader_model_board_view_uPv(m4x4f m){
+   glUniformMatrix4fv(_uniform_model_board_view_uPv,1,GL_FALSE,(float*)m);
+}
+static void shader_model_board_view_uPvmPrev(m4x4f m){
+   glUniformMatrix4fv(_uniform_model_board_view_uPvmPrev,1,GL_FALSE,(float*)m);
+}
+static void shader_model_board_view_uTexMain(int i){
+   glUniform1i(_uniform_model_board_view_uTexMain,i);
+}
+static void shader_model_board_view_uTexSceneDepth(int i){
+   glUniform1i(_uniform_model_board_view_uTexSceneDepth,i);
+}
+static void shader_model_board_view_uCamera(v3f v){
+   glUniform3fv(_uniform_model_board_view_uCamera,1,v);
+}
+static void shader_model_board_view_uInverseRatioDepth(v3f v){
+   glUniform3fv(_uniform_model_board_view_uInverseRatioDepth,1,v);
+}
+static void shader_model_board_view_uInverseRatioMain(v3f v){
+   glUniform3fv(_uniform_model_board_view_uInverseRatioMain,1,v);
+}
+static void shader_model_board_view_g_world_depth(int i){
+   glUniform1i(_uniform_model_board_view_g_world_depth,i);
+}
+static void shader_model_board_view_register(void){
+   vg_shader_register( &_shader_model_board_view );
+}
+static void shader_model_board_view_use(void){ glUseProgram(_shader_model_board_view.id); }
+static void shader_model_board_view_link(void){
+   _uniform_model_board_view_uMdl = glGetUniformLocation( _shader_model_board_view.id, "uMdl" );
+   _uniform_model_board_view_uPv = glGetUniformLocation( _shader_model_board_view.id, "uPv" );
+   _uniform_model_board_view_uPvmPrev = glGetUniformLocation( _shader_model_board_view.id, "uPvmPrev" );
+   _uniform_model_board_view_uTexMain = glGetUniformLocation( _shader_model_board_view.id, "uTexMain" );
+   _uniform_model_board_view_uTexSceneDepth = glGetUniformLocation( _shader_model_board_view.id, "uTexSceneDepth" );
+   _uniform_model_board_view_uCamera = glGetUniformLocation( _shader_model_board_view.id, "uCamera" );
+   _uniform_model_board_view_uInverseRatioDepth = glGetUniformLocation( _shader_model_board_view.id, "uInverseRatioDepth" );
+   _uniform_model_board_view_uInverseRatioMain = glGetUniformLocation( _shader_model_board_view.id, "uInverseRatioMain" );
+   _uniform_model_board_view_g_world_depth = glGetUniformLocation( _shader_model_board_view.id, "g_world_depth" );
+   _uniform_model_board_view_uLightsArray = glGetUniformLocation( _shader_model_board_view.id, "uLightsArray" );
+   _uniform_model_board_view_uLightsIndex = glGetUniformLocation( _shader_model_board_view.id, "uLightsIndex" );
+}
+#endif /* SHADER_model_board_view_H */
index 98c5797d429a19eb599805df412d7bc4da99b069..d943c2d07a13c55831527a4954d3031031dc913d 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 #define SR_NETWORKED
-//#define VG_DEVWINDOW
+#define VG_DEVWINDOW
 #include "common.h"
 #include "conf.h"
 #include "steam.h"
@@ -23,8 +23,8 @@
 #include "player.h"
 
 VG_STATIC struct player_avatar localplayer_avatar;
-VG_STATIC glmesh localplayer_meshes[3];
-vg_tex2d localplayer_texture = { .path = "textures/ch_gradient.qoi" };
+VG_STATIC struct player_model  localplayer_models[3];
+VG_STATIC struct player_board  localplayer_boards[1];
 
 #include "network.h"
 #include "menu.h"
@@ -88,50 +88,19 @@ vg_info("            '        ' '--' [] '----- '----- '     ' '---'  "
 
 VG_STATIC void load_playermodels(void)
 {
-   vg_linear_clear( vg_mem.scratch );
-
-   /* 
-    * 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_default,
-               ctx_outlaw,
-               ctx_jordan;
-
-   mdl_open( &ctx_default, "models/ch_new.mdl", vg_mem.scratch );
-   mdl_load_metadata_block( &ctx_default, vg_mem.scratch );
-   mdl_load_mesh_block( &ctx_default, vg_mem.scratch );
-   mdl_close( &ctx_default );
-
-   mdl_open( &ctx_outlaw, "models/ch_outlaw.mdl", vg_mem.scratch );
-   mdl_load_metadata_block( &ctx_outlaw, vg_mem.scratch );
-   mdl_load_mesh_block( &ctx_outlaw, vg_mem.scratch );
-   mdl_close( &ctx_outlaw );
-
-   mdl_open( &ctx_jordan, "models/ch_jordan.mdl", vg_mem.scratch );
-   mdl_load_metadata_block( &ctx_jordan, vg_mem.scratch );
-   mdl_load_mesh_block( &ctx_jordan, vg_mem.scratch );
-   mdl_close( &ctx_jordan );
+   player_model_load( &localplayer_models[0], "models/ch_new.mdl" );
+   player_model_load( &localplayer_models[1], "models/ch_outlaw.mdl" );
+   player_model_load( &localplayer_models[2], "models/ch_jordan.mdl" );
    
-   vg_acquire_thread_sync();
-   {
-      mdl_unpack_glmesh( &ctx_default, &localplayer_meshes[0] );
-      mdl_unpack_glmesh( &ctx_outlaw,  &localplayer_meshes[1] );
-      mdl_unpack_glmesh( &ctx_jordan,  &localplayer_meshes[2] );
-   }
-   vg_release_thread_sync();
+   player_board_load( &localplayer_boards[0], "models/board_fish.mdl" );
 
    /* FIXME: hack */
    shader_model_character_view_register();
-   vg_acquire_thread_sync();
-   {
-      vg_tex2d_init( (vg_tex2d *[]){ &localplayer_texture }, 1 );
-   }
-   vg_release_thread_sync();
+   shader_model_board_view_register();
 }
 
 void temp_update_playermodel(void){
-   player__use_mesh( &localplayer, &localplayer_meshes[cl_playermdl_id] );
+   player__use_model( &localplayer, &localplayer_models[cl_playermdl_id] );
 }
 
 VG_STATIC void vg_load(void)
@@ -154,8 +123,8 @@ VG_STATIC void vg_load(void)
    player__create( &localplayer );
    player_avatar_load( &localplayer_avatar, "models/ch_new.mdl" );
    player__use_avatar( &localplayer, &localplayer_avatar );
-   player__use_mesh( &localplayer, &localplayer_meshes[cl_playermdl_id] );
-   player__use_texture( &localplayer, &localplayer_texture );
+   player__use_model( &localplayer, &localplayer_models[cl_playermdl_id] );
+   player__use_board( &localplayer, &localplayer_boards[0] );
    player__bind( &localplayer );
 
    /* --------------------- */
@@ -167,7 +136,7 @@ VG_STATIC void vg_load(void)
 
    /* load home world */
 
-#if 0
+#if 1
    world_load( 0, "maps/mp_spawn.mdl" );
 #else
    world_load( 0, "maps/mp_mtzero.mdl" );
index f5add0bb6ba162d336509e66935debc6b2dd288d..820501a81c74b82ae514a8afbd33c47446995f85 100644 (file)
@@ -294,8 +294,8 @@ VG_STATIC void world_routes_place_curve( world_instance *world,
          struct world_surface *surfa = ray_hit_surface( world, &ha ),
                               *surfb = ray_hit_surface( world, &hb );
 
-         if( (surfa->info.flags & k_material_flag_skate_surface) &&
-             (surfb->info.flags & k_material_flag_skate_surface) )
+         if( (surfa->info.flags & k_material_flag_skate_target) &&
+             (surfb->info.flags & k_material_flag_skate_target) )
          {
             scene_vert va, vb;