basic cutscene player (armatures only)
authorhgn <hgodden00@gmail.com>
Sun, 22 Sep 2024 13:40:18 +0000 (14:40 +0100)
committerhgn <hgodden00@gmail.com>
Sun, 22 Sep 2024 13:40:18 +0000 (14:40 +0100)
16 files changed:
content_skaterift/maps/mp_hq/main.mdl [new file with mode: 0644]
content_skaterift/metascenes/test_scene.ms [new file with mode: 0644]
content_skaterift/playermodels/skaterift_john/ch_john.mdl
playermodels/skaterift_john/ch_john.mdl [new file with mode: 0644]
skaterift_blender/sr_main.py
skaterift_blender/sr_metascene.py
src/array_file.c
src/ent_npc.c
src/entity.h
src/metascene.c
src/metascene.h
src/model.c
src/player_render.c
src/skaterift.c
src/skeleton.h
src/world_render.c

diff --git a/content_skaterift/maps/mp_hq/main.mdl b/content_skaterift/maps/mp_hq/main.mdl
new file mode 100644 (file)
index 0000000..e64efab
Binary files /dev/null and b/content_skaterift/maps/mp_hq/main.mdl differ
diff --git a/content_skaterift/metascenes/test_scene.ms b/content_skaterift/metascenes/test_scene.ms
new file mode 100644 (file)
index 0000000..a112cfa
Binary files /dev/null and b/content_skaterift/metascenes/test_scene.ms differ
index f5f3239df3bc5eb9568769f099f43dede3dca778..717ce52790341f33d32a0848132702c2d5d2fd82 100644 (file)
Binary files a/content_skaterift/playermodels/skaterift_john/ch_john.mdl and b/content_skaterift/playermodels/skaterift_john/ch_john.mdl differ
diff --git a/playermodels/skaterift_john/ch_john.mdl b/playermodels/skaterift_john/ch_john.mdl
new file mode 100644 (file)
index 0000000..3a313d6
Binary files /dev/null and b/playermodels/skaterift_john/ch_john.mdl differ
index 1ec554fd3e65e2e6eaffa57613267db963ede1bc..289bf1e866867468c17379179ae49326ff3c43ef 100644 (file)
@@ -31,12 +31,14 @@ sr_entity_list = [
    ('ent_objective',    'Objective',      '', 18 ),
    ('ent_challenge',    'Challenge',      '', 19 ),
    ('ent_relay',        'Relay',          '', 20 ),
+   # reserved 21.. cubemap.
    ('ent_miniworld',    'Mini World',     '', 22 ),
    ('ent_prop',         'Prop',           '', 23 ),
    ('ent_list',         'Entity List',    '', 24 ),
    ('ent_region',       'Region',         '', 25 ),
    ('ent_glider',       'Glider',         '', 26 ),
-   ('ent_npc',          'npc',            '', 27 )
+   ('ent_npc',          'npc',            '', 27 ),
+   # reserved 28.. armature
 ]
 
 MDL_VERSION_NR = 107
@@ -54,6 +56,7 @@ def get_entity_enum_id( alias ):
    #}
 
    if alias == 'ent_cubemap': return 21
+   if alias == 'mdl_armature': return 28
 
    return 0
 #}
@@ -745,7 +748,7 @@ def sr_compile_mesh_internal( obj ):
          armature = mod.object
          rig_weight_groups = \
                ['0 [ROOT]']+[_.name for _ in sr_armature_bones(mod.object)]
-         armature_id = sr_compile.entity_ids[armature.name]
+         armature_id = sr_entity_id( armature )
 
          POSE_OR_REST_CACHE = armature.data.pose_position
          armature.data.pose_position = 'REST'
index 73d3b9137b81962b4ad5f872e296687b8906823a..cf076bf7495fcb1c9d6afa256ea498ab4dfe53b7 100644 (file)
@@ -90,7 +90,7 @@ class ms_instance(Structure):
 
 class ms_override(Structure):
 #{
-   _fields_ = [("pstr_name",c_uint32),
+   _fields_ = [("entity_type",c_uint32), ("pstr_name",c_uint32),
                ("transform",mdl_transform)]
 #}
 
@@ -138,7 +138,11 @@ def _metascene_armature_anims( obj, instance_id, override_id ):
          out_strip.instance_id = instance_id
          out_strip.object_id = override_id
 
-         if _metascene_action_cache( out_strip, action ): continue
+         if _metascene_action_cache( out_strip, action ):
+         #{
+            _ms_compiler.strips.append( out_strip )
+            continue
+         #}
 
          out_strip.data_mode = 0
          out_strip.data_start = len( _ms_compiler.keyframes )
@@ -209,6 +213,7 @@ def _metascene_armature_anims( obj, instance_id, override_id ):
          #
          _ms_compiler.strips.append( out_strip )
          print( F"[MS]    | anim( {NLAStrip.action.name} )" )
+         _ms_compiler.action_cache[ action.name ] = out_strip
       #}
    #}
    
@@ -277,6 +282,8 @@ def _metascene_camera_anims( obj, entity_id ):
 
          out_strip = ms_strip()
          _metascene_compile_action_curves( out_strip, NLAStrip.action )
+         out_strip.instance_id = 0xffffffff
+         out_strip.object_id = 0 # TODO
          out_strip.offset = math.floor( NLAStrip.frame_start )
          out_strip.length = math.ceil( NLAStrip.frame_end - out_strip.offset )
          out_strip.pstr_name = \
@@ -292,6 +299,15 @@ def _metascene_camera_anims( obj, entity_id ):
       for NLAStrip in NLALayer.strips:
       #{
          print( F"    have strip {NLAStrip.name}" )
+         out_strip = ms_strip()
+         _metascene_compile_action_curves( out_strip, NLAStrip.action )
+         out_strip.instance_id = 0xffffffff
+         out_strip.object_id = 0 # TODO
+         out_strip.offset = math.floor( NLAStrip.frame_start )
+         out_strip.length = math.ceil( NLAStrip.frame_end - out_strip.offset )
+         out_strip.pstr_name = \
+               pack_string( _ms_compiler.strings, NLAStrip.name )
+         _ms_compiler.strips.append( out_strip )
       #}
    #}
 #}
@@ -354,6 +370,7 @@ def _sr_export_metascene( path ):
             
             override_id = instance.override_count
             init = ms_override()
+            init.entity_type = get_entity_enum_id( obj_ent_type( o ) )
             init.pstr_name = pack_string( _ms_compiler.strings, obj_name )
             compile_obj_transform( o, init.transform )
 
@@ -382,7 +399,7 @@ def _sr_export_metascene( path ):
                return False
             #}
 
-            _metascene_camera_anims( o )
+            _metascene_camera_anims( o, 0 )
          #}
       #}
 
@@ -412,6 +429,8 @@ def _sr_export_metascene( path ):
       print( F"Marker {marker.name}: {marker.camera}" )
    #}
 
+   _ms_compiler.strips.sort( key=lambda s: s.offset )
+
    arrays = {
       'strings': _ms_compiler.strings.buffer,
       'ms_strip': _ms_compiler.strips,
index 080b85c5c2b10814a288092428738f451682b1ce..6a50eb9923a0ddd0989a2b3b97f22b5f9a3545c0 100644 (file)
@@ -35,8 +35,8 @@ static void af_load_array_file_buffer( FILE *fp, array_file_meta *arr,
       }
       else 
       {
-         vg_warn( "Applying alignment fixup to array @%p [%u -> %u] x %u\n", 
-                  buffer, arr->item_size, stride, arr->item_count );
+         vg_warn( "Applying alignment fixup to array '%s' [%u -> %u] x %u\n", 
+                  arr->name, arr->item_size, stride, arr->item_count );
 
          if( stride > arr->item_size )
             memset( buffer, 0, stride*arr->item_count );
index ce0ac3de47a4d75a94f26afc53c315fec3ccde7d..dac28f67dfa1c5376dc4fb93c5264c6df8c26fe2 100644 (file)
@@ -21,7 +21,7 @@ void npc_load_model( struct npc *npc, const char *path )
    mdl_load_metadata_block( meta, vg_mem.rtmemory );
 
    struct skeleton *sk = &npc->skeleton;
-   skeleton_setup( sk, vg_mem.rtmemory, meta );
+   skeleton_setup( sk, meta, 0, vg_mem.rtmemory );
 
    u32 mtx_size = sizeof(m4x3f)*sk->bone_count;
    npc->final_mtx = vg_linear_alloc( vg_mem.rtmemory, mtx_size );
index 5120052586965c29c725a83678b36f3ee97d9ffd..d7d7360cea4982d36d0fb2e17d07d37abe24809f 100644 (file)
@@ -66,7 +66,9 @@ enum entity_alias{
    k_ent_list        = 24,
    k_ent_region      = 25,
    k_ent_glider      = 26,
-   k_ent_npc         = 27
+   k_ent_npc         = 27,
+   k_ent_armature    = 28,
+   k_ent_max
 };
 
 typedef struct ent_call ent_call;
index 4bb0ca18d731d21d630030c324d36ae2e841b881..7c7c92cf37ac9799862ca28ec732fd57e67d9317 100644 (file)
@@ -43,3 +43,569 @@ void metascene_load( ms_context *ms, const char *path, void *alloc )
                      alloc, sizeof(ms_curve_keyframe) );
    fclose( fp );
 }
+
+struct
+{
+   ms_context meta;
+   void *arena;
+
+   bool ready;
+
+   struct model_ref
+   {
+      const char *name;
+      u32 name_hash;
+
+      mdl_context mdl;
+
+      struct cs_skeleton
+      {
+         struct skeleton sk;
+         u32 skinning_offset;
+      }
+      *skeletons;
+      u32 total_skinning_bones;
+   }
+   * refs;
+   u32 unique_refs;
+
+   struct cs_instance
+   {
+      u32 ref_id;
+      m4x3f *skinning_data;
+   }
+   * instances;
+   u32 instance_count;
+
+   struct cs_sampler
+   {
+      ms_strip *strip;
+      ms_override *override;
+      union
+      {
+         struct
+         {
+            ms_track *track;
+            f32 *target;
+         }
+         curves;
+
+         struct
+         {
+            struct skeleton *ref_sk;
+            m4x3f *skinning_data;
+         }
+         skeleton;
+      };
+   }
+   samplers[32];
+   u32 active_samplers;
+
+   u32 strip;
+   f32 time;
+}
+_cutscene;
+
+void cutscene_debug_ui( ui_context *ctx )
+{
+   ms_strip *usage[8];
+   for( u32 i=0; i<VG_ARRAY_LEN(usage); i ++ ) usage[i] = NULL;
+
+   for( u32 i=0; i<af_arrcount(&_cutscene.meta.strips); i ++ )
+   {
+      ms_strip *strip = af_arritm(&_cutscene.meta.strips, i );
+      
+      u32 layer = 0;
+      for( u32 k=0; k<VG_ARRAY_LEN(usage); k ++ )
+      {
+         if( usage[k] )
+         {
+            if( usage[k]->offset + usage[k]->length < strip->offset )
+            {
+               usage[k] = NULL;
+            }
+         }
+
+         if( !usage[k] )
+         {
+            usage[k] = strip;
+            layer = k;
+            break;
+         }
+      }
+
+      ui_rect box = { strip->offset, layer*32, strip->length, 30 };
+      u32 ps = strip->pstr_name,
+          colour = *((u32 *)af_arritm( &_cutscene.meta.strings, ps ));
+
+      ui_fill( ctx, box, colour | 0xff000000 );
+      ui_text( ctx, box, ps_get( &_cutscene.meta.strings, ps ), 1,
+               k_ui_align_middle_center, 0 );
+   }
+
+   ui_fill( ctx, (ui_rect){ (f32)_cutscene.time*_cutscene.meta.info.framerate,
+                            0, 1, VG_ARRAY_LEN(usage)*32 }, 0xffffffff );
+}
+
+/*
+ * Find associated entity data. We should also probably do this on the world
+ * thingy
+ */
+struct cs_asoc
+{
+   mdl_context *orig_data;
+   u16 entity_type,
+       entity_index;
+   ms_override *override;
+};
+
+static void _cutscene_override_asoc( u32 instance_id, u32 override_index,
+                                     struct cs_asoc *out_asoc )
+{
+   struct cs_instance *instance = &_cutscene.instances[ instance_id ];
+   mdl_context *mdl = &_cutscene.refs[ instance->ref_id ].mdl;
+
+   ms_instance *oins = af_arritm( &_cutscene.meta.instances, instance_id );
+   ms_override *override = 
+      af_arritm( &_cutscene.meta.overrides,
+                   oins->override_start + override_index );
+
+   out_asoc->orig_data = mdl;
+   out_asoc->entity_type = override->entity_type;
+   out_asoc->override = override;
+   const char *name = ps_get( &_cutscene.meta.strings, override->pstr_name );
+
+   if( out_asoc->entity_type != 28 ) 
+      goto NOT_IMPLEMENTED;
+
+   u32 name_hash = vg_strdjb2( name );
+   for( u32 j=0; j<af_arrcount( &mdl->armatures ); j ++ )
+   {
+      mdl_armature *armature = af_arritm( &mdl->armatures, j );
+      if( ps_consteq( &mdl->strings, armature->pstr_name,
+                       name, name_hash ) )
+      {
+         out_asoc->entity_index = j;
+         return;
+      }
+   }
+
+NOT_IMPLEMENTED:
+
+   vg_fatal_condition();
+   vg_warn( "The data association was not found.\n"
+            "  Entity Type: %u\n"
+            "  Entity name: %s\n", override->entity_type, name );
+   vg_fatal_exit();
+}
+
+static void _cutscene_get_strip_asoc( ms_strip *strip, 
+                                      struct cs_asoc *out_asoc )
+{
+   if( strip->instance_id == 0xffffffff )
+   {
+      out_asoc->orig_data = NULL;// &_cutscene.meta;
+      out_asoc->entity_type = mdl_entity_id_type( strip->object_id );
+      out_asoc->entity_index = mdl_entity_id_id( strip->object_id );
+      out_asoc->override = NULL;
+   }
+   else
+   {
+      _cutscene_override_asoc( strip->instance_id, strip->object_id, out_asoc );
+   }
+}
+
+static void sync_cutscene_loaded( void *payload, u32 size )
+{
+   vg_info( "Cutscene ready\n" );
+   _cutscene.ready = 1;
+}
+
+static void cutscene_load_thread( void *data )
+{
+   const char *path = data;
+   vg_info( "Loading cutscene: %s\n", path );
+
+   u32 size = 20*1024*1024;
+   _cutscene.arena = 
+      _vg_create_linear_allocator( NULL, size, VG_MEMORY_SYSTEM, "Cutscene" );
+
+   metascene_load( &_cutscene.meta, path, _cutscene.arena );
+
+   _cutscene.instance_count = af_arrcount( &_cutscene.meta.instances );
+   _cutscene.instances = vg_linear_alloc( _cutscene.arena, 
+      sizeof(struct cs_instance) * _cutscene.instance_count );
+
+   _cutscene.refs = NULL;
+   _cutscene.unique_refs = 0;
+   for( u32 i=0; i < _cutscene.instance_count; i ++ )
+   {
+      ms_instance *instance = af_arritm( &_cutscene.meta.instances, i );
+      const char *name = ps_get( &_cutscene.meta.strings, instance->pstr_name );
+
+      struct model_ref *ref = NULL;
+      u32 ref_id = 0;
+
+      for( u32 j=0; j<_cutscene.unique_refs; j ++ )
+      {
+         struct model_ref *ref_j = &_cutscene.refs[ j ];
+
+         if( ps_consteq( &_cutscene.meta.strings, instance->pstr_name, 
+                         ref_j->name, ref_j->name_hash ) )
+         {
+            ref = ref_j;
+            ref_id = j;
+            break;
+         }
+      }
+
+      if( !ref )
+      {
+         _cutscene.refs = vg_linear_extend( _cutscene.arena, _cutscene.refs, 
+                              sizeof( struct model_ref ) );
+         ref_id = _cutscene.unique_refs;
+         ref = &_cutscene.refs[ ref_id ];
+         ref->name = name;
+         ref->name_hash = vg_strdjb2( name );
+         vg_info( "Indexed reference '%s'\n", name );
+         _cutscene.unique_refs ++;
+      }
+
+      _cutscene.instances[ i ].ref_id = ref_id;
+      _cutscene.instances[ i ].skinning_data = NULL;
+   }
+
+   /* load model data */
+   for( u32 i=0; i<_cutscene.unique_refs; i ++ )
+   {
+      struct model_ref *ref = &_cutscene.refs[ i ];
+      char mdl_path_buf[ 512 ];
+      vg_str mdl_path;
+      vg_strnull( &mdl_path, mdl_path_buf, sizeof(mdl_path_buf) );
+      vg_strcat( &mdl_path, ref->name );
+      vg_strcat( &mdl_path, ".mdl" );
+
+      vg_info( "Loading instance model: %s\n", mdl_path.buffer );
+      mdl_open( &ref->mdl, mdl_path.buffer, _cutscene.arena );
+      mdl_load_metadata_block( &ref->mdl, _cutscene.arena );
+      mdl_async_full_load_std( &ref->mdl );
+      mdl_close( &ref->mdl );
+
+      u32 skeleton_count = af_arrcount( &ref->mdl.armatures );
+      if( skeleton_count )
+      {
+         ref->skeletons = vg_linear_alloc( _cutscene.arena, 
+               sizeof(struct cs_skeleton) * skeleton_count );
+
+         ref->total_skinning_bones = 0;
+         for( u32 j=0; j<skeleton_count; j ++ )
+         {
+            struct cs_skeleton *skele = &ref->skeletons[ j ];
+            skeleton_setup( &skele->sk, &ref->mdl, j, _cutscene.arena );
+            skele->skinning_offset = ref->total_skinning_bones;
+            ref->total_skinning_bones += skele->sk.bone_count;
+         }
+      }
+      else 
+      {
+         ref->skeletons = NULL;
+         ref->total_skinning_bones = 0;
+      }
+   }
+
+   /* allocate skinning memory per-instance */
+   for( u32 i=0; i<_cutscene.instance_count; i ++ )
+   {
+      struct cs_instance *ins = &_cutscene.instances[ i ];
+      struct model_ref *ref = &_cutscene.refs[ ins->ref_id ];
+
+      ins->skinning_data = vg_linear_alloc( _cutscene.arena,
+            sizeof(m4x3f) * ref->total_skinning_bones );
+
+      for( u32 j=0; j<ref->total_skinning_bones; j ++ )
+      {
+         m4x3_identity( ins->skinning_data[ j ] );
+      }
+
+      /* load overrides */
+      ms_instance *oins = af_arritm( &_cutscene.meta.instances, i );
+      for( u32 j=0; j<oins->override_count; j ++ )
+      {
+         ms_override *override = 
+            af_arritm( &_cutscene.meta.overrides, oins->override_start + j );
+
+         struct cs_asoc asoc;
+         _cutscene_override_asoc( i, j, &asoc );
+
+         VG_ASSERT( asoc.entity_type == 28 );
+
+         struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ];
+
+         m4x3f mmdl;
+         mdl_transform_m4x3( &override->transform, mmdl );
+
+         for( u32 l=0; l<skele->sk.bone_count; l ++ )
+         {
+            m4x3_copy( mmdl, ins->skinning_data[skele->skinning_offset+l] );
+         }
+      }
+   }
+
+   vg_async_call( sync_cutscene_loaded, NULL, 0 );
+}
+
+static int ccmd_cutscene_play( int argc, const char *argv[] )
+{
+   if( argc == 1 )
+   {
+      if( _cutscene.ready )
+      {
+         vg_info( "Resetting cutscene..\n" );
+         _cutscene.time = 0.0f;
+         _cutscene.strip = 0;
+         _cutscene.active_samplers = 0;
+         return 1;
+      }
+
+      if( vg_loader_availible() )
+      {
+         _cutscene.ready = 0;
+         _cutscene.time = 0.0f;
+         _cutscene.strip = 0;
+         _cutscene.active_samplers = 0;
+
+         vg_linear_clear( vg_async.buffer );
+         u32 len = strlen( argv[0] ) +1;
+         char *path_buf = vg_linear_alloc( vg_async.buffer, len );
+         strcpy( path_buf, argv[0] );
+         vg_loader_start( cutscene_load_thread, path_buf );
+         return 1;
+      }
+      else
+      {
+         vg_error( "The loading thread is currently occupied.\n" );
+         return 0;
+      }
+   }
+   else
+   {
+      vg_error( "Usage: cutscene path/to/cutscene.ms\n" );
+      return 0;
+   }
+}
+
+void cutscene_init(void)
+{
+   vg_console_reg_cmd( "cutscene", ccmd_cutscene_play, NULL );
+}
+
+/*
+ * Currently draws everything as skinned meshes.
+ */
+void cutscene_render_instance( struct cs_instance *ins, 
+                               world_instance *world, vg_camera *cam )
+{
+   struct model_ref *ref = &_cutscene.refs[ ins->ref_id ];
+   mdl_context *mdl = &ref->mdl;
+   mesh_bind( &mdl->mesh );
+
+   shader_model_character_view_use();
+   shader_model_character_view_uCamera( cam->transform[3] );
+   shader_model_character_view_uPv( cam->mtx.pv );
+   shader_model_character_view_uDepthMode( 0 );
+
+   WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_character_view );
+
+       glActiveTexture( GL_TEXTURE0 );
+   shader_model_character_view_uTexMain( 0 );
+
+   u32 armature_id = 0x00;
+   u32 material_id = 0x00;
+
+   for( u32 i=0; i<af_arrcount( &mdl->meshs ); i ++ )
+   {
+      mdl_mesh *mesh = af_arritm( &mdl->meshs, i );
+      VG_ASSERT( mesh->armature_id );
+
+      if( mesh->armature_id != armature_id )
+      {
+         armature_id = mesh->armature_id;
+         u32 sk_index = mdl_entity_id_id( armature_id );
+
+         struct cs_skeleton *skele = &ref->skeletons[ sk_index ];
+
+         m4x3f *skinning_data = ins->skinning_data + skele->skinning_offset;
+         glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms,
+                               skele->sk.bone_count,
+                               0,
+                               (const GLfloat *)skinning_data );
+      }
+
+      for( u32 j=0; j<mesh->submesh_count; j ++ )
+      {
+         mdl_submesh *sm = af_arritm( &mdl->submeshs, mesh->submesh_start+j );
+         VG_ASSERT( sm->material_id );
+         
+         if( sm->material_id != material_id )
+         {
+            mdl_material *m = af_arritm( &mdl->materials, sm->material_id-1 );
+            VG_ASSERT( m->shader == k_shader_standard );
+
+            struct shader_props_standard *props = m->props.compiled;
+            VG_ASSERT( props->tex_diffuse );
+
+            mdl_texture *tex = af_arritm( &mdl->textures, props->tex_diffuse-1);
+            glBindTexture( GL_TEXTURE_2D, tex->glname );
+         }
+
+         mdl_draw_submesh( sm );
+      }
+   }
+}
+
+void cutscene_update( f32 delta )
+{
+   _cutscene.time += delta;
+   u32 frame = _cutscene.time * _cutscene.meta.info.framerate;
+
+   /* clear out finished samplers */
+   bool move = 0;
+   u32 j = 0;
+   for( u32 i=0; i<_cutscene.active_samplers; i ++ )
+   {
+      struct cs_sampler *si = &_cutscene.samplers[i];
+      
+      if( frame > (si->strip->offset + si->strip->length) )
+      {
+         move = 1;
+      }
+      else
+      {
+         if( move )
+         {
+            struct cs_sampler *sj = &_cutscene.samplers[j];
+            *sj = *si;
+         }
+         
+         j ++;
+      }
+   }
+   _cutscene.active_samplers = j;
+
+   /* add new samplers as we get to them */
+   for( u32 i=_cutscene.strip; i<af_arrcount(&_cutscene.meta.strips); i ++ )
+   {
+      ms_strip *strip = af_arritm(&_cutscene.meta.strips, i);
+
+      if( frame < strip->offset )
+      {
+         break;
+      }
+
+      if( frame > strip->offset + strip->length )
+      {
+         vg_warn( "Skipping?\n" );
+         _cutscene.strip ++;
+         continue;
+      }
+
+      if( strip->instance_id == 0xffffffff )
+      {
+         // TODO
+         _cutscene.strip ++;
+         continue;
+      }
+
+      struct cs_instance *ins = &_cutscene.instances[ strip->instance_id ];
+
+      struct cs_asoc asoc;
+      _cutscene_get_strip_asoc( strip, &asoc );
+      VG_ASSERT( asoc.entity_type == 28 );
+
+      if( strip->data_mode == 1 )
+      {
+         for( u32 j=0; j<strip->data_count; j ++ )
+         {
+            ms_track *track = af_arritm( &_cutscene.meta.tracks,
+                  strip->data_start + j );
+            
+            VG_ASSERT( _cutscene.active_samplers < 
+                        VG_ARRAY_LEN(_cutscene.samplers) );
+
+            struct cs_sampler *samp =
+               &_cutscene.samplers[ _cutscene.active_samplers ++ ];
+            samp->strip = strip;
+            samp->curves.track = track;
+            samp->curves.target = NULL; /* DOTO */
+            samp->override = asoc.override;
+         }
+      }
+      else
+      {
+         VG_ASSERT( _cutscene.active_samplers < 
+                     VG_ARRAY_LEN(_cutscene.samplers) );
+
+         struct cs_sampler *samp = 
+            &_cutscene.samplers[ _cutscene.active_samplers ++ ];
+
+         struct model_ref *ref = &_cutscene.refs[ ins->ref_id ];
+         struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ];
+
+         samp->strip = strip;
+         samp->skeleton.skinning_data = 
+            &ins->skinning_data[ skele->skinning_offset ];
+         samp->skeleton.ref_sk = &skele->sk;
+         samp->override = asoc.override;
+      }
+      
+      _cutscene.strip ++;
+   }
+
+   /* sample da samplers */
+   for( u32 i=0; i<_cutscene.active_samplers; i ++ )
+   {
+      struct cs_sampler *samp = &_cutscene.samplers[ i ];
+
+      struct skeleton_anim temp_anim = 
+      {
+         .strip = samp->strip,
+         .framerate = _cutscene.meta.info.framerate,
+         .keyframes_base = af_arritm( &_cutscene.meta.keyframes,
+                     samp->strip->data_start )
+      };
+
+      f32 t  = _cutscene.time;
+          t -= (f32)samp->strip->offset / _cutscene.meta.info.framerate;
+
+      struct skeleton *ref_sk = samp->skeleton.ref_sk;
+      m4x3f *final_mtx = samp->skeleton.skinning_data;
+
+      ms_keyframe pose[32];
+      skeleton_sample_anim( ref_sk, &temp_anim, t, pose );
+
+      skeleton_apply_pose( ref_sk, pose, 
+                           k_anim_apply_defer_ik, final_mtx );
+      skeleton_apply_ik_pass( ref_sk, final_mtx );
+      skeleton_apply_pose( ref_sk, pose,
+                           k_anim_apply_deffered_only, final_mtx );
+      skeleton_apply_inverses( ref_sk, final_mtx );
+
+      if( samp->override )
+      {
+         m4x3f mmdl;
+         mdl_transform_m4x3( &samp->override->transform, mmdl );
+         skeleton_apply_transform( ref_sk, mmdl, final_mtx );
+      }
+   }
+}
+
+void cutscene_render( world_instance *world, vg_camera *cam )
+{
+   if( _cutscene.ready )
+   {
+      for( u32 i=0; i<_cutscene.instance_count; i ++ )
+      {
+         cutscene_render_instance( &_cutscene.instances[i], world, cam );
+      }
+   }
+}
index 6b7685db2809624d0bc2822431fa20f85d74b088..f95eedc205955002e9ef772c02483300726d8eff 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 #include "model.h"
+#include "world.h"
 
 #define MS_VERSION_NR 1
 #define MS_VERSION_MIN 1
@@ -43,7 +44,7 @@ struct ms_instance
 
 struct ms_override
 {
-   u32 pstr_name;
+   u32 entity_type, pstr_name;
    mdl_transform transform;
 };
 
@@ -74,3 +75,7 @@ struct ms_curve_keyframe
 };
 
 void metascene_load( ms_context *ms, const char *path, void *alloc );
+void cutscene_init(void);
+void cutscene_render( world_instance *world, vg_camera *cam );
+void cutscene_debug_ui( ui_context *ctx );
+void cutscene_update( f32 delta );
index fc7e38749fed830b421359119afe4720421578f6..e49309650a8fb4f3f333baa174245d05f7801648 100644 (file)
@@ -528,4 +528,5 @@ void mdl_async_full_load_std( mdl_context *mdl )
                                VG_TEX2D_CLAMP|VG_TEX2D_NEAREST, &tex->glname );
    }
 }
+
 #endif
index 1531c34ffdf3dd3493be7aa52537f6f1bf5b8612..31346d7a72fc2cb9354e87d923bf49977f515b55 100644 (file)
@@ -54,7 +54,7 @@ void player_load_animation_reference( const char *path )
    mdl_close( meta );
 
    struct skeleton *sk = &localplayer.skeleton;
-   skeleton_setup( sk, vg_mem.rtmemory, meta );
+   skeleton_setup( sk, meta, 0, vg_mem.rtmemory );
 
    localplayer.id_world      = skeleton_bone_id( sk, "world" );
    localplayer.id_hip        = skeleton_bone_id( sk, "hips" );
index b28ee453234b9dfdd2e20774342d9cc224beca68..113754864c9807ded8be21314c88cc2c50a558ab 100644 (file)
@@ -163,6 +163,7 @@ void game_load(void)
    vg_loader_step( player_init, NULL );
    vg_loader_step( player_ragdoll_init, NULL );
    vg_loader_step( npc_init, NULL );
+   vg_loader_step( cutscene_init, NULL );
 
    /* content stuff */
    vg_loader_step( addon_system_init, NULL );
@@ -240,6 +241,8 @@ void vg_pre_update(void)
 
    vg_slewf( &skaterift.time_rate, target, vg.time_frame_delta * (1.0f/0.3f) );
    vg.time_rate = vg_smoothstepf( skaterift.time_rate );
+
+   cutscene_update( vg.time_rate * vg.time_frame_delta );
    
    /* TODO: how can we compress this? */
    ent_miniworld_preupdate();
@@ -607,6 +610,7 @@ void vg_gui( ui_context *ctx )
    skaterift_replay_imgui( ctx );
    workshop_form_gui( ctx );
    remote_player_network_imgui( ctx, vg.pv );
+   cutscene_debug_ui( ctx );
 
    if( menu_viewing_map() )
    {
index 9a3be61639f11bf8eff84ed51f6ea7178909ecd3..a62c3e31ff6e17afcbcf7b49660f066ea2a3be95 100644 (file)
@@ -16,7 +16,7 @@ struct skeleton
       u32 flags;
       int defer;
 
-      ms_keyframe kf;
+      //ms_keyframe kf;
       mdl_bone *orig_bone;
 
       u32 collider;
@@ -34,8 +34,7 @@ struct skeleton
    *ik;
    u32 ik_count;
 
-   u32 
-       collider_count,
+   u32 collider_count,
        bindable_count;
 };
 
@@ -442,8 +441,7 @@ static void skeleton_alloc_from( struct skeleton *skele,
    }
 
    u32 bone_size = sizeof(struct skeleton_bone) * skele->bone_count,
-       ik_size   = sizeof(struct skeleton_ik)   * skele->ik_count,
-       mtx_size  = sizeof(m4x3f)                * skele->bone_count;
+       ik_size   = sizeof(struct skeleton_ik)   * skele->ik_count;
 
    skele->bones      = vg_linear_alloc( lin_alloc, bone_size );
    skele->ik         = vg_linear_alloc( lin_alloc, ik_size );
@@ -457,18 +455,20 @@ static void skeleton_fatal_err(void){
 }
 
 /* Setup a skeleton from model. mdl's metadata should stick around */
-static void skeleton_setup( struct skeleton *skele,
-                            void *lin_alloc, mdl_context *mdl ){
+void skeleton_setup( struct skeleton *skele, mdl_context *mdl, u32 index,
+                     void *lin_alloc )
+{
    u32 ik_count = 0, collider_count = 0;
    skele->bone_count = 0;
    skele->bones = NULL;
 
-   if( !mdl->armatures.count ){
+   if( !mdl->armatures.count )
+   {
       vg_error( "No skeleton in model\n" );
       skeleton_fatal_err();
    }
 
-   mdl_armature *armature = af_arritm( &mdl->armatures, 0 );
+   mdl_armature *armature = af_arritm( &mdl->armatures, index );
    skeleton_alloc_from( skele, lin_alloc, mdl, armature );
 
    for( u32 i=0; i<armature->bone_count; i++ )
@@ -520,22 +520,6 @@ static void skeleton_setup( struct skeleton *skele,
    skele->bones[0].parent = 0xffffffff;
    skele->bones[0].flags = 0;
    skele->bones[0].name = "[root]";
-   
-   /* process animation quick refs */
-   // for( u32 i=0; i<skele->anim_count; i++ ){
-   //    mdl_animation *anim = 
-   //       af_arritm( &mdl->animations, armature->anim_start+i );
-
-   //    skele->anims[i].rate       = anim->rate;
-   //    skele->anims[i].length     = anim->length;
-   //    skele->anims[i].name       = mdl_pstr(mdl, anim->pstr_name);
-   //    skele->anims[i].anim_data  = 
-   //       af_arritm( &mdl->keyframes, anim->offset );
-
-   //    vg_info( "animation[ %f, %u ] '%s'\n", anim->rate,
-   //                                           anim->length,
-   //                                           skele->anims[i].name );
-   // }
 
    skeleton_create_inverses( skele );
    vg_success( "Loaded skeleton with %u bones\n", skele->bone_count );
index b7a673216b869559bd6ed90df14aa660b6fa6e29..40759810136bc814cd86286c436e53f08974b587 100644 (file)
@@ -1018,6 +1018,8 @@ static void render_other_entities( world_instance *world, vg_camera *cam )
       npc_update( npc );
       npc_render( npc, world, cam );
    }
+
+   cutscene_render( world, cam );
 }
 
 void render_world( world_instance *world, vg_camera *cam,