skateshop basics
authorhgn <hgodden00@gmail.com>
Tue, 25 Apr 2023 15:20:29 +0000 (16:20 +0100)
committerhgn <hgodden00@gmail.com>
Tue, 25 Apr 2023 15:20:29 +0000 (16:20 +0100)
27 files changed:
blender_export.py
build.c
ent_skateshop.c [new file with mode: 0644]
entity.c [new file with mode: 0644]
entity.h
gui.h [new file with mode: 0644]
maps_src/mp_mtzero.mdl
maps_src/mp_spawn.mdl
menu.h
model.h
models_src/board_fish.mdl [deleted file]
models_src/boards/skaterift_fish.mdl [new file with mode: 0644]
models_src/boards/skaterift_striped.mdl [new file with mode: 0644]
network.h
player.c
player.h
player_render.c
player_skate.c
player_walk.c
player_walk.h
shaders/model_entity.fs [new file with mode: 0644]
shaders/model_entity.h [new file with mode: 0644]
skaterift.c
world.h
world_gen.h
world_logic_bricks.h [deleted file]
world_render.h

index 861d69249efbbfa640412cbe35b216dbbd42229c..b533afee8927e6aa01a6b3ac6c70775b9c76cde9 100644 (file)
@@ -30,6 +30,7 @@ sr_entity_list = [
    ('ent_font',         'Font',           '', 9  ),
    ('ent_font_variant', 'Font:Variant',   '', 10 ),
    ('ent_traffic',      'Traffic Model',  '', 11 ),
+   ('ent_skateshop',    'Skate Shop',     '', 12 )
 ]
 
 def get_entity_enum_id( alias ):
@@ -271,19 +272,13 @@ class volume_union(Union):
                ("particles",volume_particles)]
 #}
 
-class ent_index(Structure):
-#{
-   _fields_ = [("type",c_uint32),
-               ("index",c_uint32)]
-#}
-
 class ent_volume(Structure):
 #{
    _fields_ = [("transform",mdl_transform),
                ("to_world",(c_float*3)*4),
                ("to_local",(c_float*3)*4),
                ("type",c_uint32),
-               ("target",ent_index),
+               ("target",c_uint32),
                ("_anon",volume_union)]
 #}
 
@@ -342,6 +337,14 @@ class ent_traffic(Structure):
                ("index",c_uint32)]
 #}
 
+class ent_skateshop(Structure):
+#{
+   _fields_ = [("transform",mdl_transform),
+               ("id_display",c_uint32),
+               ("id_info",c_uint32),
+               ("id_rack",c_uint32)]
+#}
+
 def obj_ent_type( obj ):
 #{
    if obj.type == 'ARMATURE': return 'mdl_armature'
@@ -677,6 +680,14 @@ def sr_armature_bones( armature ):
          yield from _recurse_bone( b )
 #}
 
+def sr_entity_id( obj ):
+#{
+   tipo = get_entity_enum_id( obj_ent_type(obj) )
+   index = sr_compile.entity_ids[ obj.name ]
+
+   return (tipo&0xffff)<<16 | (index&0xffff)
+#}
+
 # Returns submesh_start,count and armature_id
 def sr_compile_mesh_internal( obj ):
 #{
@@ -1470,9 +1481,7 @@ def sr_compile( collection ):
             compile_obj_transform( obj, volume.transform )
 
             if obj_data.target:#{
-               target = obj_data.target
-               volume.target.type = get_entity_enum_id( obj_ent_type(target) )
-               volume.target.index = sr_compile.entity_ids[ target.name ]
+               volume.target = sr_entity_id( obj_data.target )
             #}
 
             sr_ent_push(volume)
@@ -1483,6 +1492,15 @@ def sr_compile( collection ):
             compile_obj_transform( obj, marker.transform )
             sr_ent_push(marker)
          #}
+         elif ent_type == 'ent_skateshop':#{
+            skateshop = ent_skateshop()
+            obj_data = obj.SR_data.ent_skateshop[0]
+            skateshop.id_display = sr_entity_id( obj_data.mark_display )
+            skateshop.id_info = sr_entity_id( obj_data.mark_info )
+            skateshop.id_rack = sr_entity_id( obj_data.mark_rack )
+            compile_obj_transform( obj, skateshop.transform )
+            sr_ent_push(skateshop)
+         #}
       #}
    #}
 
@@ -2428,7 +2446,8 @@ class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup):
 
    target: bpy.props.PointerProperty( \
            type=bpy.types.Object, name="Target", \
-           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_audio']))
+           poll=lambda self,obj: sr_filter_ent_type(obj,\
+                                    ['ent_audio','ent_skateshop']))
 
    @staticmethod
    def sr_inspector( layout, data ):
@@ -2579,6 +2598,19 @@ class SR_OBJECT_ENT_TRAFFIC(bpy.types.PropertyGroup):
    speed: bpy.props.FloatProperty(default=1.0)
 #}
 
+class SR_OBJECT_ENT_SKATESHOP(bpy.types.PropertyGroup):
+#{
+   mark_rack: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Board Rack", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker']))
+   mark_display: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Selected Board Display", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker']))
+   mark_info: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Selected Board Info", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker']))
+#}
+
 class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
 #{
    ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE)
@@ -2590,6 +2622,7 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
    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_skateshop: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_SKATESHOP)
    ent_type: bpy.props.EnumProperty(
       name="Type",
       items=sr_entity_list,
@@ -3540,6 +3573,30 @@ def cv_draw():
                #}
             #}
          #}
+         elif ent_type == 'ent_skateshop':#{
+            cc = (0.0,0.9,0.6)
+            cc1 = (0.4,0.9,0.2)
+            cc2 = (0.9,0.6,0.1)
+
+            data = obj.SR_data.ent_skateshop[0]
+            display = data.mark_display
+            info = data.mark_info
+            rack = data.mark_rack
+
+            rack_cu = Vector((3.15,2.0,0.1))*0.5
+            rack_co = Vector((0.0,0.0,0.0))
+            display_cu = Vector((0.2,1.2,0.1))*0.5
+            display_co = Vector((0.0,0.0,0.1))*0.5
+            info_cu = Vector((1.2,0.01,0.3))*0.5
+            info_co = Vector((0.0,0.0,0.0))*0.5
+
+            if rack:
+               cv_draw_ucube( rack.matrix_world, cc, rack_cu, rack_co )
+            if display:
+               cv_draw_ucube( display.matrix_world, cc1, display_cu, display_co)
+            if info:
+               cv_draw_ucube( info.matrix_world, cc2, info_cu, info_co )
+         #}
       #}
    #}
 
@@ -3573,7 +3630,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_TRAFFIC,\
+            SR_OBJECT_ENT_FONT,SR_OBJECT_ENT_TRAFFIC,SR_OBJECT_ENT_SKATESHOP,\
             \
             SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, 
             SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \
diff --git a/build.c b/build.c
index fd0a1026ea3b165947334236b76e115c3a6793a0..ae1ff0f9a64cf6e8c2b09a3ebe21320e5062dc2b 100644 (file)
--- a/build.c
+++ b/build.c
@@ -133,6 +133,7 @@ void build_shaders(void)
    _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_entity",         "model.vs",         "model_entity.fs" );
    _S( "model_gate",           "model_gate.vs",    "model_gate_lq.fs" );
    _S( "model_font",           "model_font.vs",    "model_font.fs" );
 
diff --git a/ent_skateshop.c b/ent_skateshop.c
new file mode 100644 (file)
index 0000000..b126abf
--- /dev/null
@@ -0,0 +1,599 @@
+#ifndef ENT_SKATESHOP_C
+#define ENT_SKATESHOP_C
+
+#include "world.h"
+#include "player.h"
+
+#define MAX_LOCAL_BOARDS 64
+#define BILL_TIN_BOARDS  1
+#define MAX_DYNAMIC_BOARDS 9
+
+struct{
+   v3f look_target;
+   mdl_transform rack_root,
+                 display_root,
+                 info_root;
+
+   enum camera_mode prev_camera_mode;
+
+   int active;
+   float factive;
+
+   enum skateshop_loc{
+      k_skateshop_loc_page__viewing,
+
+      k_skateshop_loc_select_use,
+      k_skateshop_loc_select_cancel,
+      k_skateshop_loc_select_upload,
+      k_skateshop_loc_page__selected,
+
+      k_skateshop_loc_page__upload,
+   }
+   interface_loc;
+
+   struct dynamic_board
+   {
+      enum dynamic_board_state{
+         k_dynamic_board_state_none,
+         k_dynamic_board_state_loaded,
+         k_dynamic_board_state_loading,
+      }
+      state;
+
+      u32 ref_count;
+
+      struct player_board board;
+
+      u32 registry_id;
+
+      double last_use_time;
+   }
+   *dynamic_boards,
+   *localplayer_slot;
+
+   struct shop_view_slot
+   {
+      struct dynamic_board *db;
+      float view_blend;
+   }
+   shop_view_slots[6];
+
+   struct board_registry
+   {
+      int workshop;
+      u64 uid;
+
+      struct dynamic_board *dynamic;
+
+      char filename[64];   /* if workshop, string version of uid. */
+      u32 filename_hash;
+
+      int ghost;
+   } 
+   *registry;
+   u32 registry_count;
+
+   int loading;
+   float interaction_cooldown;
+
+   u32 selected_registry_id;
+}
+static global_skateshop;
+
+static inline int const_str_eq( u32 hash, const char *str, const char *cmp )
+{
+   if( hash == vg_strdjb2(cmp) )
+      if( !strcmp( str, cmp ) )
+         return 1;
+   return 0;
+}
+
+static int skateshop_workshop_name_blacklisted( u32 hash, const char *name )
+{
+   if( const_str_eq( hash, name, "skaterift_fish.mdl" ) ) return 1;
+   return 0;
+}
+
+VG_STATIC void skateshop_loader_start( void (*pfn)(void) )
+{
+   if( global_skateshop.loading )
+      vg_fatal_error( "skateshop thread sync failure\n" );
+
+   global_skateshop.loading = 1;
+   vg_loader_start( pfn );
+}
+
+VG_STATIC void skateshop_async_post( void *payload, u32 size )
+{
+   global_skateshop.loading = 0;
+}
+
+VG_STATIC 
+struct dynamic_board *skateshop_lru_alloc( u32 id )
+{
+   double min_time = 1e300;
+   struct dynamic_board *min_board = NULL;
+
+   for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
+      struct dynamic_board *db = &global_skateshop.dynamic_boards[i];
+
+      if( db->state == k_dynamic_board_state_loading )
+         continue;
+
+      if( db->ref_count )
+         continue;
+
+      if( db->last_use_time < min_time ){
+         min_time = db->last_use_time;
+         min_board = db;
+      }
+   }
+
+   if( min_board ){
+      localplayer.board = NULL; /* temp */
+
+      if( min_board->state == k_dynamic_board_state_loaded ){
+         struct board_registry *other = 
+            &global_skateshop.registry[min_board->registry_id];
+
+         vg_info( "Deallocating board: '%s'\n", min_board, other->filename );
+
+         player_board_unload( &min_board->board );
+         other->dynamic = NULL;
+      }
+
+      struct board_registry *reg = &global_skateshop.registry[id];
+
+      vg_info( "Allocating board '%s' @%p\n", reg->filename, min_board );
+
+      min_board->state = k_dynamic_board_state_loading;
+      min_board->registry_id = id;
+      min_board->last_use_time = vg.time;
+      min_board->ref_count = 0;
+   }
+   else{
+      vg_error( "No free boards to load registry!\n" );
+   }
+
+   return min_board;
+}
+
+VG_STATIC 
+void skateshop_board_registry_path( struct board_registry *reg, char path[256] )
+{
+   if( reg->workshop ){
+      snprintf( path, 256, "models/boards/workshop/%s/something.mdl", 
+                reg->filename );
+   }
+   else{
+      snprintf( path, 256, "models/boards/%s", reg->filename );
+   }
+}
+
+VG_STATIC void skateshop_async_board_complete( void *payload, u32 size )
+{
+   struct dynamic_board *db = payload;
+
+   if( db == global_skateshop.localplayer_slot ){
+      localplayer.board = &db->board;
+      db->ref_count ++;
+   }
+   else{
+      for( u32 i=0; i<vg_list_size(global_skateshop.shop_view_slots); i++ ){
+         if( global_skateshop.shop_view_slots[i].db == db ){
+            db->ref_count ++;
+         }
+      }
+   }
+
+   db->last_use_time = vg.time;
+   db->state = k_dynamic_board_state_loaded;
+
+   struct board_registry *reg = &global_skateshop.registry[ db->registry_id ];
+   reg->dynamic = db;
+
+   vg_success( "Async board loaded (%s)\n", reg->filename );
+}
+
+VG_STATIC void skateshop_load_requested_boards(void)
+{
+   char path[256];
+   for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
+      struct dynamic_board *db = &global_skateshop.dynamic_boards[i];
+   
+      if( db->state == k_dynamic_board_state_loading ){
+         struct board_registry *reg = 
+            &global_skateshop.registry[ db->registry_id ];
+
+         skateshop_board_registry_path( reg, path );
+         player_board_load( &db->board, path );
+         vg_async_call( skateshop_async_board_complete, db, 0 );
+      }
+   }
+}
+
+VG_STATIC void skateshop_thread1_refresh(void)
+{
+   skateshop_load_requested_boards();
+   vg_async_call( skateshop_async_post, NULL, 0 );
+}
+
+VG_STATIC int skateshop_use_board( int argc, const char *argv[] )
+{
+   if( global_skateshop.loading ){
+      vg_error( "Cannot use skateshop currently (loader thread missing)\n" );
+      return 0;
+   }
+
+   if( argc == 1 ){
+      u32 hash = vg_strdjb2( argv[0] );
+
+      for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+         struct board_registry *reg = &global_skateshop.registry[i];
+
+         if( const_str_eq( hash, argv[0], reg->filename ) ){
+            
+            if( reg->dynamic ){
+               struct dynamic_board *db = reg->dynamic;
+
+               if( db->state == k_dynamic_board_state_loaded ){
+                  localplayer.board = &db->board;
+                  db->last_use_time = vg.time;
+               }
+               else{
+                  vg_fatal_error( "Invalid state while loading board\n" );
+               }
+            }
+            else{
+               struct dynamic_board *db = skateshop_lru_alloc( i );
+               db->state = k_dynamic_board_state_loading;
+               skateshop_loader_start( skateshop_thread1_refresh );
+            }
+            return 1;
+         }
+      }
+   }
+   return 0;
+}
+
+VG_STATIC void skateshop_use_board_suggest( int argc, const char *argv[] )
+{
+   if( argc == 1 ){
+      for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+         struct board_registry *reg = &global_skateshop.registry[i];
+
+         if( reg->ghost ) continue; /* we probably can't load these */
+
+         console_suggest_score_text( reg->filename, argv[0], 0 );
+      }
+   }
+}
+
+VG_STATIC void skateshop_scan_for_items(void)
+{
+   vg_linear_clear( vg_mem.scratch );
+
+   for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+      struct board_registry *reg = &global_skateshop.registry[i];
+      reg->ghost = 1;
+   }
+
+   tinydir_dir dir;
+   tinydir_open( &dir, "models/boards" );
+
+   while( dir.has_next ){
+      tinydir_file file;
+      tinydir_readfile( &dir, &file );
+      
+      if( file.is_reg ){
+         u32 hash = vg_strdjb2( file.name );
+
+         for( u32 i=0; i<global_skateshop.registry_count; i++ ){
+            struct board_registry *reg = &global_skateshop.registry[i];
+
+            if( const_str_eq( hash, file.name, reg->filename ) ){
+               reg->ghost = 0;
+               goto next_file;
+            }
+         }
+
+         if( global_skateshop.registry_count == MAX_LOCAL_BOARDS ){
+            vg_error( "You have too many boards installed!\n" );
+            break;
+         }
+
+         vg_info( "new listing!: %s\n", file.name );
+
+         struct board_registry *reg = &global_skateshop.registry[
+                                          global_skateshop.registry_count ++ ];
+
+         reg->dynamic = NULL;
+         vg_strncpy( file.name, reg->filename, 64, k_strncpy_always_add_null );
+         reg->filename_hash = hash;
+         reg->uid = 0;
+         reg->workshop = 0;
+         reg->ghost = 0;
+      }
+
+next_file: tinydir_next( &dir );
+   }
+
+   tinydir_close(&dir);
+
+   skateshop_load_requested_boards();
+   vg_async_call( skateshop_async_post, NULL, 0 );
+}
+
+VG_STATIC void global_skateshop_exit(void)
+{
+   global_skateshop.active = 0;
+   localplayer.camera_mode = global_skateshop.prev_camera_mode;
+}
+
+VG_STATIC void skateshop_request_viewpage( u32 page )
+{
+   u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
+   u32 start = page * slot_count;
+
+   for( u32 i=0; i<slot_count; i++ ){
+      struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
+      
+      if( slot->db ){
+         slot->db->ref_count --;
+         slot->db = NULL;
+      }
+
+      u32 reg_index = start+i;
+      if( reg_index < global_skateshop.registry_count ){
+         struct board_registry *reg = &global_skateshop.registry[ reg_index ];
+
+         if( reg->dynamic ){
+            struct dynamic_board *db = reg->dynamic;
+
+            if( db->state == k_dynamic_board_state_loaded ){
+               db->last_use_time = vg.time;
+               db->ref_count ++;
+               slot->db = db;
+            }
+            else{
+               vg_fatal_error( "Invalid state while loading page\n" );
+            }
+         }
+         else{
+            struct dynamic_board *db = skateshop_lru_alloc( reg_index );
+
+            if( db ){
+               db->ref_count ++;
+               slot->db = db;
+            }
+         }
+      }
+   }
+}
+
+VG_STATIC void ent_skateshop_call( world_instance *world, ent_call *call )
+{
+   u32 index = mdl_entity_id_id( call->id );
+   ent_skateshop *shop = mdl_arritm( &world->ent_skateshop, index );
+   vg_info( "skateshop_call\n" );
+
+   if( global_skateshop.loading ){
+      vg_error( "Cannot enter skateshop currently (loader thread missing)\n" );
+      return;
+   }
+
+   if( call->function == k_ent_function_trigger ){
+      if( localplayer.subsystem != k_player_subsystem_walk ){
+         return;
+      }
+      
+      vg_info( "Entering skateshop\n" );
+
+      localplayer.immobile = 1;
+      global_skateshop.prev_camera_mode = localplayer.camera_mode;
+      localplayer.camera_mode = k_cam_firstperson;
+      global_skateshop.active = 1;
+      global_skateshop.interface_loc = k_skateshop_loc_page__viewing;
+
+      v3_zero( localplayer.rb.v );
+      v3_zero( localplayer.rb.w );
+      localplayer._walk.move_speed = 0.0f;
+
+      struct{
+         mdl_transform *transform;
+         u32 id;
+      }
+      targets[] = {
+         { &global_skateshop.rack_root, shop->id_rack, },
+         { &global_skateshop.info_root, shop->id_info, },
+         { &global_skateshop.display_root, shop->id_display, },
+      };
+      
+      v3_copy( shop->transform.co, global_skateshop.look_target );
+
+      for( u32 i=0; i<vg_list_size(targets); i++ ){
+         
+         u32 type = mdl_entity_id_type( targets[i].id ),
+             index = mdl_entity_id_id( targets[i].id );
+
+         if( type == k_ent_marker ){
+            ent_marker *m = mdl_arritm( &world->ent_marker, index );
+
+            *targets[i].transform = m->transform;
+         }
+         else{
+            transform_identity( targets[i].transform );
+         }
+      }
+
+      skateshop_request_viewpage(0);
+      skateshop_loader_start( skateshop_scan_for_items );
+   }
+}
+
+VG_STATIC void global_skateshop_preupdate(void)
+{
+   float rate = vg_minf( 1.0f, vg.time_frame_delta * 2.0f );
+   global_skateshop.factive = vg_lerpf( global_skateshop.factive, 
+                                        global_skateshop.active, rate );
+
+
+   if( !global_skateshop.active ) return;
+
+   v3f delta;
+   v3_sub( global_skateshop.look_target, localplayer.cam.pos, delta );
+   v3_normalize( delta );
+
+   v3f target;
+   player_vector_angles( target, delta, 1.0f, 0.0f );
+
+   camera_lerp_angles( localplayer.angles, target,
+                       global_skateshop.factive, localplayer.angles);
+
+   if( global_skateshop.interaction_cooldown > 0.0f ){
+      global_skateshop.interaction_cooldown -= vg.time_delta;
+      return;
+   }
+
+   float h = localplayer.input_js1h->axis.value;
+
+   if( global_skateshop.interface_loc <= k_skateshop_loc_page__viewing ){
+      if( fabsf(h) > 0.25f ){
+         if( h < 0.0f ){
+            if( global_skateshop.selected_registry_id > 0 )
+               global_skateshop.selected_registry_id --;
+         }
+         else{
+            if( global_skateshop.selected_registry_id < 
+                     global_skateshop.registry_count-1 )
+            {
+               global_skateshop.selected_registry_id ++;
+            }
+         }
+
+         vg_info( "Select registry: %u\n", 
+                  global_skateshop.selected_registry_id );
+         global_skateshop.interaction_cooldown = 0.125f;
+         return;
+      }
+
+      if( vg_input_button_down( &input_menu_back ) ){
+         global_skateshop.active = 0;
+         return;
+      }
+   }
+   else if( global_skateshop.interface_loc <= k_skateshop_loc_page__selected ){
+      if( vg_input_button_down( &input_menu_back ) ){
+         global_skateshop.interface_loc = k_skateshop_loc_page__viewing;
+         return;
+      }
+
+      if( fabsf(h) > 0.25f ){
+         if( global_skateshop.interface_loc == k_skateshop_loc_select_use ){
+            global_skateshop.interface_loc = k_skateshop_loc_select_cancel;
+            return;
+         }
+      }
+      else{
+         if( global_skateshop.interface_loc == k_skateshop_loc_select_cancel ){
+            global_skateshop.interface_loc = k_skateshop_loc_select_use;
+            return;
+         }
+      }
+   }
+}
+
+VG_STATIC void skateshop_init(void)
+{
+   global_skateshop.registry =
+      vg_linear_alloc( vg_mem.rtmemory, 
+                       sizeof(struct board_registry)*MAX_LOCAL_BOARDS );
+   global_skateshop.registry_count = 0;
+   global_skateshop.dynamic_boards =
+      vg_linear_alloc( vg_mem.rtmemory, 
+                       sizeof(struct dynamic_board)*MAX_DYNAMIC_BOARDS );
+
+   memset( global_skateshop.dynamic_boards, 0,
+            sizeof(struct dynamic_board)*MAX_DYNAMIC_BOARDS );
+
+   for( u32 i=0; i<MAX_DYNAMIC_BOARDS; i++ ){
+      struct dynamic_board *board = &global_skateshop.dynamic_boards[i];
+      board->state = k_dynamic_board_state_none;
+      board->registry_id = 0xffffffff;
+      board->last_use_time = -99999.9;
+      board->ref_count = 0;
+   }
+
+   vg_console_reg_cmd( "use_board", 
+                       skateshop_use_board, skateshop_use_board_suggest );
+
+   skateshop_scan_for_items();
+}
+
+VG_STATIC void skateshop_render(void)
+{
+   if( !global_skateshop.active ) return;
+      
+   world_instance *world = get_active_world();
+
+   u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
+   
+   for( u32 i=0; i<slot_count; i++ ){
+      struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
+
+      float selected = 0.0f;
+      
+      if( !slot->db ) 
+         goto set_fade_amt;
+
+      if( slot->db->state != k_dynamic_board_state_loaded ) 
+         goto set_fade_amt;
+
+      mdl_transform rack_xform;
+      transform_identity( &rack_xform );
+
+      rack_xform.co[0] = -((float)i - ((float)slot_count)*0.5f)*0.45f;
+
+      mdl_transform_mul( &global_skateshop.rack_root, 
+                         &rack_xform, &rack_xform );
+
+      if( slot->db->registry_id == global_skateshop.selected_registry_id ){
+         selected = 1.0f;
+      }
+
+      float t = slot->view_blend;
+      v3_lerp( rack_xform.co, global_skateshop.display_root.co, 
+               t, rack_xform.co );
+      q_nlerp( rack_xform.q, global_skateshop.display_root.q, 
+               t, rack_xform.q );
+      v3_lerp( rack_xform.s, global_skateshop.display_root.s, 
+               t, rack_xform.s );
+
+      m4x3f mmdl;
+      mdl_transform_m4x3( &rack_xform, mmdl );
+      render_board( &main_camera, world, &slot->db->board, mmdl,
+                    k_board_shader_entity );
+
+set_fade_amt:;
+      float rate = 5.0f*vg.time_delta;
+      slot->view_blend = vg_lerpf( slot->view_blend, selected, rate );
+   }
+
+   m4x3f mtext;
+   mdl_transform_m4x3( &global_skateshop.info_root, mtext );
+
+   m4x3f mlocal = {{0.2f,0.0f,0.0f},{0.0f,0.2f,0.0f},{0.0f,0.0f,0.03f},
+                   {-font3d_string_width( &world_global.font,0, 
+                        "Made by... Bob man 123" )*0.2f*0.5f,0.0f,0.0f}
+   };
+
+   m4x3_mul( mtext, mlocal, mtext );
+
+   font3d_bind( &world_global.font, &main_camera );
+
+   shader_model_font_uColour( (v4f){1.0f,0.5f,0.1f,1.0f} );
+   font3d_simple_draw( &world_global.font, 0, "Made by... Bob man 123",
+                       &main_camera, mtext );
+}
+
+#endif /* ENT_SKATESHOP_C */
diff --git a/entity.c b/entity.c
new file mode 100644 (file)
index 0000000..1d91c24
--- /dev/null
+++ b/entity.c
@@ -0,0 +1,22 @@
+#ifndef ENTITY_C
+#define ENTITY_C
+
+#include "entity.h"
+#include "world.h"
+
+#include "ent_skateshop.c"
+
+VG_STATIC void entity_call( world_instance *world, ent_call *call )
+{
+   u32 type = mdl_entity_id_type( call->id );
+
+   if( type == k_ent_volume ){
+      ent_volume_call( world, call );
+   } else if( type == k_ent_audio ){
+      ent_audio_call( world, call );
+   } else if( type == k_ent_skateshop ){
+      ent_skateshop_call( world, call );
+   }
+}
+
+#endif /* ENTITY_C */
index 7d6fabfbdeaf909e71a12d7abf53a205c4e2a7c8..e8b9d411a91d04452e5e7b58216bfacb714b9297 100644 (file)
--- a/entity.h
+++ b/entity.h
@@ -16,12 +16,12 @@ typedef struct volume_particles volume_particles;
 typedef struct volume_trigger volume_trigger;
 typedef struct ent_volume ent_volume;
 typedef struct ent_audio ent_audio;
-typedef struct ent_index ent_index;
 typedef struct ent_marker ent_marker;
 typedef struct ent_traffic ent_traffic;
 typedef struct ent_font ent_font;
 typedef struct ent_font_variant ent_font_variant;
 typedef struct ent_glyph ent_glyph;
+typedef struct ent_skateshop ent_skateshop;
 
 enum entity_alias{
    k_ent_none        = 0,
@@ -35,7 +35,8 @@ enum entity_alias{
    k_ent_marker      = 8,
    k_ent_font        = 9,
    k_ent_font_variant= 10,
-   k_ent_traffic     = 11
+   k_ent_traffic     = 11,
+   k_ent_skateshop   = 12
 };
 
 static u32 mdl_entity_id_type( u32 entity_id )
@@ -48,10 +49,10 @@ static u32 mdl_entity_id_id( u32 entity_id )
    return entity_id & 0x0000ffff;
 }
 
-struct ent_index{
-   u32 type,
-       index;
-};
+static u32 mdl_entity_id( u32 type, u32 index )
+{
+   return (type & 0xfffff)<<16 | (index & 0xfffff);
+}
 
 enum entity_function{
    k_ent_function_trigger,
@@ -184,7 +185,7 @@ struct ent_volume{
    m4x3f to_world, to_local;
    u32 type;
 
-   ent_index target;
+   u32 target;
 
    union{
       volume_trigger trigger;
@@ -209,6 +210,13 @@ struct ent_marker{
    u32 pstr_alias;
 };
 
+struct ent_skateshop{
+   mdl_transform transform;
+   u32 id_display,
+       id_info,
+       id_rack;
+};
+
 struct ent_traffic{
    mdl_transform transform;
    u32 submesh_start,
@@ -266,4 +274,15 @@ struct ent_glyph{
        indice_count;
 };
 
+
+typedef struct ent_call ent_call;
+struct ent_call{
+   u32 id, function;
+   void *data;
+};
+
+#include "world.h"
+
+VG_STATIC void entity_call( world_instance *world, ent_call *call );
+
 #endif /* ENTITY_H */
diff --git a/gui.h b/gui.h
new file mode 100644 (file)
index 0000000..cf381af
--- /dev/null
+++ b/gui.h
@@ -0,0 +1,11 @@
+#ifndef GUI_H
+#define GUI_H
+
+#include "font.h"
+
+VG_STATIC void gui_example( void )
+{
+   
+}
+
+#endif /* GUI_H */
index 0fb6064d7c7b40fe1aaea8378cd649ba03a23401..e2f8b9e52654cd6ddfbc0a2ed9f4b03f0ea4f1a0 100644 (file)
Binary files a/maps_src/mp_mtzero.mdl and b/maps_src/mp_mtzero.mdl differ
index 48b5ecf5821042284b5c80c280e72ab889a3db41..c33fb0d3db9f48a0b5a8ccc1a89a6c464662754e 100644 (file)
Binary files a/maps_src/mp_spawn.mdl and b/maps_src/mp_spawn.mdl differ
diff --git a/menu.h b/menu.h
index 483449038620f4f6350e6ef96a8f56def46ba31a..7e6649a2ca5bf71cd9ca0a1d36757c9498402eca 100644 (file)
--- a/menu.h
+++ b/menu.h
@@ -9,7 +9,6 @@
 
 #include "shaders/model_menu.h"
 #include "vg_steam_friends.h"
-#include "submodules/tinydir/tinydir.h"
 
 VG_STATIC mdl_context menu_model;
 VG_STATIC mdl_array_ptr   menu_markers;
@@ -299,7 +298,8 @@ VG_STATIC void menu_btn_map( int event )
          struct menu_map_file *mf = &game_menu.maps_list[ game_menu.map_count ];
          
          vg_strncpy( file.name, mf->name, 
-                                vg_list_size(game_menu.maps_list[0].name)-1 );
+                                vg_list_size(game_menu.maps_list[0].name),
+                                k_strncpy_always_add_null );
 
          game_menu.map_count ++;
          if( game_menu.map_count == vg_list_size(game_menu.maps_list) )
diff --git a/model.h b/model.h
index 8f90d128ad0a9637edb7a2624eed66ee1c2cc35b..811f3a12034c92634abc504902e02bfbceb179ed 100644 (file)
--- a/model.h
+++ b/model.h
@@ -77,6 +77,34 @@ struct mdl_transform
    v4f q;
 };
 
+static void transform_identity( mdl_transform *transform )
+{
+   v3_zero( transform->co );
+   q_identity( transform->q );
+   v3_fill( transform->s, 1.0f );
+}
+
+static void mdl_transform_vector( mdl_transform *transform, v3f vec, v3f dest )
+{
+   v3_mul( transform->s, vec, dest );
+   q_mulv( transform->q, dest, dest );
+}
+
+static void mdl_transform_point( mdl_transform *transform, v3f co, v3f dest )
+{
+   mdl_transform_vector( transform, co, dest );
+   v3_add( transform->co, dest, dest );
+}
+
+static void mdl_transform_mul( mdl_transform *a, mdl_transform *b, 
+                               mdl_transform *d )
+{
+   mdl_transform_point( a, b->co, d->co );
+   q_mul( a->q, b->q, d->q );
+   q_normalize( d->q );
+   v3_mul( a->s, b->s, d->s );
+}
+
 struct mdl_material
 {
    u32 pstr_name,
diff --git a/models_src/board_fish.mdl b/models_src/board_fish.mdl
deleted file mode 100644 (file)
index 33af54e..0000000
Binary files a/models_src/board_fish.mdl and /dev/null differ
diff --git a/models_src/boards/skaterift_fish.mdl b/models_src/boards/skaterift_fish.mdl
new file mode 100644 (file)
index 0000000..33af54e
Binary files /dev/null and b/models_src/boards/skaterift_fish.mdl differ
diff --git a/models_src/boards/skaterift_striped.mdl b/models_src/boards/skaterift_striped.mdl
new file mode 100644 (file)
index 0000000..24feb86
Binary files /dev/null and b/models_src/boards/skaterift_striped.mdl differ
index fc454c75afbf7cf643aefe861def63250a2ed0a7..ffd2dbe3cf4d0d98eb454a9281032e4467ae77b0 100644 (file)
--- a/network.h
+++ b/network.h
@@ -174,7 +174,8 @@ VG_STATIC void send_nickname(void)
    nick.inetmsg_id = k_inetmsg_set_nickname;
 
    memset( nick.nickname, 0, 16 );
-   vg_strncpy( steam_username_at_startup, nick.nickname, 16 );
+   vg_strncpy( steam_username_at_startup, nick.nickname, 16,
+               k_strncpy_allow_cutoff );
    
    SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
          hSteamNetworkingSockets, cremote, &nick, sizeof(netmsg_set_nickname),
index da097071804d7a6e18d5faaef5a1c56c59451bb7..e2052029635dc3cc40cd8a7ab036fd0461043d54 100644 (file)
--- a/player.c
+++ b/player.c
@@ -154,12 +154,6 @@ void player__use_model( player_instance *player, struct player_model *mdl )
    player->playermodel = mdl;
 }
 
-PLAYER_API
-void player__use_board( player_instance *player, struct player_board *mdl )
-{
-   player->playerboard = mdl;
-}
-
 PLAYER_API
 void player__bind( player_instance *player )
 {
@@ -198,7 +192,7 @@ void player__pre_update( player_instance *player )
       return;
    }
 
-   if( vg_input_button_down( player->input_reset ) ){
+   if( vg_input_button_down( player->input_reset ) && !player->immobile ){
       double delta = world_global.time - world_global.last_use;
 
       if( (delta <= RESET_MAX_TIME) && (world_global.last_use != 0.0) ){
@@ -242,7 +236,7 @@ void player__pre_update( player_instance *player )
       }
    }
 
-   if( vg_input_button_down( player->input_camera ) ){
+   if( vg_input_button_down( player->input_camera ) && !player->immobile ){
       if( player->camera_mode == k_cam_firstperson )
          player->camera_mode = k_cam_thirdperson;
       else
@@ -383,6 +377,7 @@ PLAYER_API void player__im_gui( player_instance *player )
    b[3].co[1] = vg_uictx.cursor[1];
 }
 
+VG_STATIC void global_skateshop_exit(void);
 PLAYER_API void player__spawn( player_instance *player, 
                                ent_spawn *rp )
 {
@@ -397,8 +392,11 @@ PLAYER_API void player__spawn( player_instance *player,
    m3x3_identity( player->invbasis );
 
    player->subsystem = k_player_subsystem_walk;
+   player->immobile = 0;
    player->gate_waiting = NULL;
 
+   global_skateshop_exit();
+
    if( _player_reset[ player->subsystem ] )
       _player_reset[ player->subsystem ]( player, rp );
 }
index dac0db44fd121079074b0ee2b19227c99ef4e7ba..77a01fc512d9896dc627b3578f13b5bcbff4992b 100644 (file)
--- a/player.h
+++ b/player.h
@@ -81,16 +81,17 @@ struct player_instance
                         *input_grab,
                         *input_camera;
 
+   int immobile;
+
    /*
     * Animation
     * --------------------------------------------------
     */
 
-
    struct player_avatar  *playeravatar;
    struct player_model   *playermodel;
-   struct player_board   *playerboard;
    struct player_ragdoll  ragdoll;
+   struct player_board   *board;
 
    player_pose            holdout_pose;
    float                  holdout_time;
index df0dd6b1d3717e12b84529aecaf7edb90a38dc1e..171b339ebe4e88bb52b7f782d649e0504909c045 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "shaders/model_character_view.h"
 #include "shaders/model_board_view.h"
+#include "shaders/model_entity.h"
 
 VG_STATIC void player_avatar_load( struct player_avatar *av, const char *path )
 {
@@ -93,10 +94,6 @@ VG_STATIC void player_board_load( struct player_board *mdl, const char *path )
    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;
 
@@ -125,6 +122,12 @@ VG_STATIC void player_board_load( struct player_board *mdl, const char *path )
    }
 }
 
+VG_STATIC void player_board_unload( struct player_board *mdl )
+{
+   mesh_free( &mdl->mesh );
+   glDeleteTextures( 1, &mdl->texture );
+}
+
 VG_STATIC void player__pre_render( player_instance *player )
 {
    if( _player_animate[ player->subsystem ] ){
@@ -157,8 +160,18 @@ VG_STATIC void player__pre_render( player_instance *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 player_board *board = player->board;
+
+   v3f vp0, vp1;
+
+   if( board ){
+      v3_copy((v3f){0.0f,0.1f, board->truck_positions[0][2]}, vp0 );
+      v3_copy((v3f){0.0f,0.1f, board->truck_positions[1][2]}, vp1 );
+   }
+   else{
+      v3_zero( vp0 );
+      v3_zero( vp1 );
+   }
 
    struct ub_world_lighting *ubo = &get_active_world()->ub_lighting;
    m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, ubo->g_board_0 );
@@ -262,82 +275,80 @@ VG_STATIC void player__pre_render( player_instance *player )
    player__cam_iterate( player );
 }
 
-PLAYER_API void player__render( camera *cam, player_instance *player )
+enum board_shader{
+   k_board_shader_player,
+   k_board_shader_entity
+};
+
+VG_STATIC void render_board( camera *cam, world_instance *world,
+                             struct player_board *board, m4x3f root,
+                             enum board_shader shader )
 {
-   shader_model_character_view_use();
+   if( !board ) return;
 
-       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 );
+   glActiveTexture( GL_TEXTURE0 );
+   glBindTexture( GL_TEXTURE_2D, board->texture );
+
+   if( shader == k_board_shader_player ){
+      shader_model_board_view_use();
+      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 );
+   }
+   else if( shader == k_board_shader_entity ){
+      shader_model_entity_use();
+      shader_model_entity_uTexMain( 0 );
+      shader_model_entity_uCamera( cam->transform[3] );
+      shader_model_entity_uPv( cam->mtx.pv );
+      
+      world_link_lighting_ub( world, _shader_model_entity.id );
+      world_bind_position_texture( world, _shader_model_entity.id,
+                                 _uniform_model_entity_g_world_depth, 2 );
+      world_bind_light_array( world, _shader_model_entity.id,
+                                 _uniform_model_entity_uLightsArray, 3 );
+      world_bind_light_index( world, _shader_model_entity.id,
+                                 _uniform_model_entity_uLightsIndex, 4 );
+   }
 
-   struct player_board *board = player->playerboard;
    mesh_bind( &board->mesh );
 
+   m4x4f m4mdl;
+
    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 );
+      if( shader == k_board_shader_entity ){
+         /* TODO: provide a way to supply previous mdl mtx? */
+         m4x3_expand( mlocal, m4mdl );
+         m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl );
+         shader_model_entity_uPvmPrev( m4mdl );
+         shader_model_entity_uMdl( mlocal );
+      }
+      else
+         shader_model_board_view_uMdl( mlocal );
+
       mdl_draw_submesh( &board->board );
    }
 
@@ -350,7 +361,15 @@ PLAYER_API void player__render( camera *cam, player_instance *player )
       v3_copy( board->truck_positions[i], mlocal[3] );
       m4x3_mul( root, mlocal, mlocal );
 
-      shader_model_board_view_uMdl( mlocal );
+      if( shader == k_board_shader_entity ){
+         m4x3_expand( mlocal, m4mdl );
+         m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl );
+         shader_model_entity_uPvmPrev( m4mdl );
+         shader_model_entity_uMdl( mlocal );
+      }
+      else
+         shader_model_board_view_uMdl( mlocal );
+
       mdl_draw_submesh( &board->trucks[i] );
    }
 
@@ -363,9 +382,61 @@ PLAYER_API void player__render( camera *cam, player_instance *player )
       v3_copy( board->wheel_positions[i], mlocal[3] );
       m4x3_mul( root, mlocal, mlocal );
 
-      shader_model_board_view_uMdl( mlocal );
+      if( shader == k_board_shader_entity ){
+         m4x3_expand( mlocal, m4mdl );
+         m4x4_mul( cam->mtx_prev.pv, m4mdl, m4mdl );
+         shader_model_entity_uPvmPrev( m4mdl );
+         shader_model_entity_uMdl( mlocal );
+      }
+      else
+         shader_model_board_view_uMdl( mlocal );
+
       mdl_draw_submesh( &board->wheels[i] );
    }
 }
 
+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 );
+
+   struct player_board *board = player->board;
+
+   render_board( cam, world, board, player->playeravatar->sk.final_mtx[
+                                       player->playeravatar->id_board],
+                                       k_board_shader_player );
+}
+
 #endif /* PLAYER_RENDER_C */
index 7029edc774f1fe9b6bdb722d7b0a31141d45a86f..9b1aea11a47c83f7b35af6553dcecfc0287919f3 100644 (file)
@@ -2957,20 +2957,22 @@ 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] = 
-            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] = 
-            vg_lerpf( kf_foot_r->co[2], 
-                      board->truck_positions[k_board_truck_front][2]-0.3f, 
-                      -0.5f*s->blend_weight );
+      struct player_board *board = player->board;
+      
+      if( board ){
+         /* foot weight distribution */
+         if( s->blend_weight > 0.0f ){
+            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] = 
+               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 );
index 7d160a7a09d0d801cb19f15bc230cb5f9b37c8f1..d8fe3d1fc86868af333c1155b1acc538d8435dc7 100644 (file)
@@ -252,7 +252,7 @@ VG_STATIC void player__walk_pre_update( player_instance *player )
 {
    struct player_walk *w = &player->_walk;
 
-   if( w->state.activity != k_walk_activity_immobile )
+   if( !player->immobile )
       player_look( player, player->angles );
 
    if( w->state.outro_anim ){
@@ -276,7 +276,7 @@ VG_STATIC void player__walk_pre_update( player_instance *player )
          return;
       }
    }
-   else if( vg_input_button_down( player->input_use ) ){
+   else if( vg_input_button_down( player->input_use ) && !player->immobile ){
       if( v3_dist2( player->rb.co, gzoomer.obj.rb.co ) <= 4.0f*4.0f ){
          player->subsystem = k_player_subsystem_drive;
       }
@@ -286,7 +286,7 @@ VG_STATIC void player__walk_pre_update( player_instance *player )
                w->state.outro_type = k_walk_outro_drop_in;
                w->state.outro_anim = w->anim_drop_in;
                w->state.outro_start_time = vg.time;
-               w->state.activity = k_walk_activity_immobile;
+               player->immobile = 1;
 
                struct player_avatar *av = player->playeravatar;
                m4x3_mulv( av->sk.final_mtx[ av->id_ik_foot_r ], 
@@ -358,7 +358,7 @@ VG_STATIC void player__walk_update( player_instance *player )
 
    enum walk_activity prev_state = w->state.activity;
 
-   if( w->state.activity == k_walk_activity_immobile )
+   if( player->immobile )
       return;
 
    w->collider.height = 2.0f;
@@ -844,7 +844,6 @@ VG_STATIC void player__walk_im_gui( player_instance *player )
                            (const char *[]){ "k_walk_activity_air",
                                              "k_walk_activity_ground",
                                              "k_walk_activity_sleep",
-                                             "k_walk_activity_immobile",
                                              "k_walk_activity_lockedmove" }
                                              [w->state.activity] );
    player__debugtext( 1, "surface: %s\n",
index 4c6b7a39af89ce320966403f10d8b4d151ae0314..989384c1fc9661cffe259296ef71952d47ce6c2b 100644 (file)
@@ -2,6 +2,7 @@
 #define PLAYER_WALK_H
 
 #include "player_api.h"
+#include "rigidbody.h"
 
 struct player_walk{
    rb_capsule collider;
@@ -20,7 +21,6 @@ struct player_walk{
          k_walk_activity_air,
          k_walk_activity_ground,
          k_walk_activity_sleep,
-         k_walk_activity_immobile,
          k_walk_activity_lockedmove
       }
       activity;
diff --git a/shaders/model_entity.fs b/shaders/model_entity.fs
new file mode 100644 (file)
index 0000000..b14d120
--- /dev/null
@@ -0,0 +1,22 @@
+uniform sampler2D uTexMain;
+uniform vec3 uCamera;
+
+in vec4 aColour;
+in vec2 aUv;
+in vec3 aNorm;
+in vec3 aCo;
+in vec3 aWorldCo;
+
+#include "common_world.glsl"
+#include "motion_vectors_fs.glsl"
+
+void main()
+{
+   compute_motion_vectors();
+
+   vec3 qnorm     = normalize(floor(aNorm*2.0)*0.5) + vec3(0.001,0.0,0.0);
+   vec3 diffuse   = texture( uTexMain, aUv ).rgb;
+   vec3 composite = world_compute_lighting( diffuse, qnorm, aWorldCo, 1.0 );
+
+   oColour = vec4( composite, 1.0 );
+}
diff --git a/shaders/model_entity.h b/shaders/model_entity.h
new file mode 100644 (file)
index 0000000..777f660
--- /dev/null
@@ -0,0 +1,455 @@
+#ifndef SHADER_model_entity_H
+#define SHADER_model_entity_H
+static void shader_model_entity_link(void);
+static void shader_model_entity_register(void);
+static struct vg_shader _shader_model_entity = {
+   .name = "model_entity",
+   .link = shader_model_entity_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_entity.fs",
+.static_src = 
+"uniform sampler2D uTexMain;\n"
+"uniform vec3 uCamera;\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     11        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     12        0 \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"
+"   oColour = vec4( composite, 1.0 );\n"
+"}\n"
+""},
+};
+
+static GLuint _uniform_model_entity_uMdl;
+static GLuint _uniform_model_entity_uPv;
+static GLuint _uniform_model_entity_uPvmPrev;
+static GLuint _uniform_model_entity_uTexMain;
+static GLuint _uniform_model_entity_uCamera;
+static GLuint _uniform_model_entity_g_world_depth;
+static GLuint _uniform_model_entity_uLightsArray;
+static GLuint _uniform_model_entity_uLightsIndex;
+static void shader_model_entity_uMdl(m4x3f m){
+   glUniformMatrix4x3fv(_uniform_model_entity_uMdl,1,GL_FALSE,(float*)m);
+}
+static void shader_model_entity_uPv(m4x4f m){
+   glUniformMatrix4fv(_uniform_model_entity_uPv,1,GL_FALSE,(float*)m);
+}
+static void shader_model_entity_uPvmPrev(m4x4f m){
+   glUniformMatrix4fv(_uniform_model_entity_uPvmPrev,1,GL_FALSE,(float*)m);
+}
+static void shader_model_entity_uTexMain(int i){
+   glUniform1i(_uniform_model_entity_uTexMain,i);
+}
+static void shader_model_entity_uCamera(v3f v){
+   glUniform3fv(_uniform_model_entity_uCamera,1,v);
+}
+static void shader_model_entity_g_world_depth(int i){
+   glUniform1i(_uniform_model_entity_g_world_depth,i);
+}
+static void shader_model_entity_register(void){
+   vg_shader_register( &_shader_model_entity );
+}
+static void shader_model_entity_use(void){ glUseProgram(_shader_model_entity.id); }
+static void shader_model_entity_link(void){
+   _uniform_model_entity_uMdl = glGetUniformLocation( _shader_model_entity.id, "uMdl" );
+   _uniform_model_entity_uPv = glGetUniformLocation( _shader_model_entity.id, "uPv" );
+   _uniform_model_entity_uPvmPrev = glGetUniformLocation( _shader_model_entity.id, "uPvmPrev" );
+   _uniform_model_entity_uTexMain = glGetUniformLocation( _shader_model_entity.id, "uTexMain" );
+   _uniform_model_entity_uCamera = glGetUniformLocation( _shader_model_entity.id, "uCamera" );
+   _uniform_model_entity_g_world_depth = glGetUniformLocation( _shader_model_entity.id, "g_world_depth" );
+   _uniform_model_entity_uLightsArray = glGetUniformLocation( _shader_model_entity.id, "uLightsArray" );
+   _uniform_model_entity_uLightsIndex = glGetUniformLocation( _shader_model_entity.id, "uLightsIndex" );
+}
+#endif /* SHADER_model_entity_H */
index 6246be38d722a9b4651cdbddc578bdb1195713e4..73767a22ca3580898d32fda5604239f9d1933076 100644 (file)
 #include "font.h"
 #include "player.h"
 
+#include "entity.c"
+
 VG_STATIC struct player_avatar localplayer_avatar;
 VG_STATIC struct player_model  localplayer_models[3];
-VG_STATIC struct player_board  localplayer_boards[1];
 VG_STATIC int skaterift_status = 0;
 
 #include "network.h"
@@ -93,11 +94,16 @@ VG_STATIC void load_playermodels(void)
    player_model_load( &localplayer_models[1], "models/ch_outlaw.mdl" );
    player_model_load( &localplayer_models[2], "models/ch_jordan.mdl" );
    
-   player_board_load( &localplayer_boards[0], "models/board_fish.mdl" );
+   /* load default board */
+#if 0
+   player_board_load( &localplayer_boards[0], 
+                      "models/boards/skaterift_fish.mdl" );
+#endif
 
    /* FIXME: hack */
    shader_model_character_view_register();
    shader_model_board_view_register();
+   shader_model_entity_register();
 }
 
 void temp_update_playermodel(void){
@@ -124,6 +130,7 @@ VG_STATIC void vg_load(void)
 
    vg_loader_step( player_init, NULL );
    vg_loader_step( player_ragdoll_init, NULL );
+   vg_loader_step( skateshop_init, NULL );
    
    /* ----------------- */
    vg_loader_step( load_playermodels, NULL );
@@ -133,7 +140,7 @@ VG_STATIC void vg_load(void)
    player_avatar_load( &localplayer_avatar, "models/ch_new.mdl" );
    player__use_avatar( &localplayer, &localplayer_avatar );
    player__use_model( &localplayer, &localplayer_models[cl_playermdl_id] );
-   player__use_board( &localplayer, &localplayer_boards[0] );
+   //localplayer.board = &localplayer_boards[0];
    player__bind( &localplayer );
 
    /* --------------------- */
@@ -179,6 +186,7 @@ VG_STATIC void vg_update(void)
       network_update();
       
       player__pre_update( &localplayer );
+      global_skateshop_preupdate();
 
       world_update( get_active_world(), localplayer.rb.co );
       audio_ambient_sprites_update( get_active_world(), localplayer.rb.co );
@@ -392,6 +400,9 @@ VG_STATIC void render_main_game(void)
 
    main_camera.fov = vg_lerpf( localplayer.cam.fov, menu_smooth_fov,
                                menu_opacity );
+
+   main_camera.fov = vg_lerpf( main_camera.fov, 90.0f, 
+                               global_skateshop.factive );
    main_camera.nearz = 0.1f;
    main_camera.farz  = 2100.0f;
 
diff --git a/world.h b/world.h
index 7084ff17334e7b9195abfc2ff584576bccefcbc1..01b12b9d3d090ae6c2cc0fbbed56d4cec31a6b22 100644 (file)
--- a/world.h
+++ b/world.h
@@ -165,7 +165,9 @@ struct world_instance {
                  ent_audio_clip,
                  ent_audio,
                  ent_volume,
-                 ent_traffic;
+                 ent_traffic,
+                 ent_skateshop,
+                 ent_marker;
 
    ent_gate *rendering_gate;
 
@@ -405,22 +407,14 @@ VG_STATIC void world_init(void)
                                                    VG_MEMORY_SYSTEM );
 }
 
-typedef struct ent_call ent_call;
-struct ent_call{
-   ent_index ent;
-   u32 function;
-   void *data;
-};
-
-VG_STATIC void entity_call( world_instance *world, ent_call *call );
-
 VG_STATIC void ent_volume_call( world_instance *world, ent_call *call )
 {
-   ent_volume *volume = mdl_arritm( &world->ent_volume, call->ent.index );
-   if( !volume->target.type ) return;
+   u32 index = mdl_entity_id_id( call->id );
+   ent_volume *volume = mdl_arritm( &world->ent_volume, index );
+   if( !volume->target ) return;
 
    if( call->function == k_ent_function_trigger ){
-      call->ent = volume->target;
+      call->id = volume->target;
 
       if( volume->type == k_volume_subtype_particle ){
          float *co = alloca( sizeof(float)*3 );
@@ -433,14 +427,16 @@ VG_STATIC void ent_volume_call( world_instance *world, ent_call *call )
          call->data = co;
          entity_call( world, call );
       }
-      else
+      else{
          entity_call( world, call );
+      }
    }
 }
 
 VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
 {
-   ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.index );
+   u32 index = mdl_entity_id_id( call->id );
+   ent_audio *audio = mdl_arritm( &world->ent_audio, index );
 
    v3f sound_co;
 
@@ -524,15 +520,6 @@ VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
    }
 }
 
-VG_STATIC void entity_call( world_instance *world, ent_call *call )
-{
-   if( call->ent.type == k_ent_volume ){
-      ent_volume_call( world, call );
-   } else if( call->ent.type == k_ent_audio ){
-      ent_audio_call( world, call );
-   }
-}
-
 VG_STATIC void world_update( world_instance *world, v3f pos )
 {
    world_global.sky_time += world_global.sky_rate * vg.time_delta;
@@ -684,9 +671,8 @@ VG_STATIC void world_update( world_instance *world, v3f pos )
 
             if( !world_global.in_volume ){
                ent_call basecall;
-               basecall.ent.index = idx;
-               basecall.ent.type = k_ent_volume;
                basecall.function = k_ent_function_trigger;
+               basecall.id = mdl_entity_id( k_ent_volume, idx );
                basecall.data = NULL;
 
                entity_call( world, &basecall );
@@ -700,9 +686,7 @@ VG_STATIC void world_update( world_instance *world, v3f pos )
 
          for( int j=0; j<random_ticks; j++ ){
             ent_call basecall;
-            basecall.ent.index = idx;
-            basecall.ent.type = k_ent_volume;
-            basecall.function = k_ent_function_trigger;
+            basecall.id = mdl_entity_id( k_ent_volume, idx );
             basecall.data = NULL;
 
             entity_call( world, &basecall );
index cf713fd69c5438ff2da5a673a98a29f1b915a323..a9cd91fd68726281bffb70a02cf123f442d5001e 100644 (file)
@@ -831,6 +831,8 @@ VG_STATIC void world_load( u32 index, const char *path )
    mdl_load_array( meta, &world->ent_audio,     "ent_audio",      heap );
    mdl_load_array( meta, &world->ent_volume,    "ent_volume",     heap );
    mdl_load_array( meta, &world->ent_traffic,   "ent_traffic",    heap );
+   mdl_load_array( meta, &world->ent_marker,    "ent_marker",     heap );
+   mdl_load_array( meta, &world->ent_skateshop, "ent_skateshop",  heap );
 
    /* process resources from pack */
    world_process_resources( world );
diff --git a/world_logic_bricks.h b/world_logic_bricks.h
deleted file mode 100644 (file)
index d6e9d11..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-#include "common.h"
-
-#ifndef WORLD_LOGIC_BRICKS_H
-#define WORLD_LOGIC_BRICKS_H
-
-#include "world.h"
-
-#if 0
-
-typedef struct logic_packet logic_packet;
-struct logic_packet
-{
-   u32 location, function;
-   union mdl_128bit_union data;
-   enum mdl_128bit_datatype type;
-};
-
-VG_STATIC void logic_bricks_debug_connection( world_instance *world,
-                                              mdl_node *from, u32 next,
-                                              v3f colour )
-{
-   if( next == 0 )
-      return;
-
-   mdl_node *to = mdl_node_from_id( world->meta, next );
-
-   v3f c;
-   float brightness = 0.8f + world->logic_bricks[ from->sub_uid ].usage * 4.0f;
-   v3_muls( colour, brightness, c );
-
-   u32 clamped = 0xff000000;
-
-   for( int i=0; i<3; i++ )
-   {
-      u8 byte = vg_minf( 1.0f, c[i] ) * 255.0f;
-      clamped |= byte << (i*8);
-   }
-
-   vg_line( from->co, to->co, clamped );
-}
-
-VG_STATIC void logic_bricks_debug( world_instance *world, v3f pos )
-{
-   v3f white = {1.0f,1.0f,1.0f},
-       red   = {1.0f,0.2f,0.1f},
-       black = {0.2f,0.2f,0.2f};
-
-   glLineWidth( 2.0f );
-
-   for( int i=0; i<world->logic_brick_count; i++ )
-   {
-      struct logic_brick_ref *ref = &world->logic_bricks[i];
-      mdl_node *node = ref->node;
-
-      if( v3_dist2( node->co, pos ) > 50.0f*50.0f )
-         continue;
-
-      void *entdata = mdl_get_entdata( world->meta, node );
-
-      if( ref->node->classtype == k_classtype_logic_wire )
-      {
-         struct classtype_logic_wire *wire = entdata;
-
-         logic_bricks_debug_connection( world, node, wire->next, white );
-      }
-      else if( ref->node->classtype == k_classtype_logic_chances )
-      {
-         struct classtype_logic_chances *chances = entdata;
-
-         logic_bricks_debug_connection(world, node, chances->targets[0], red );
-         logic_bricks_debug_connection(world, node, chances->targets[1], black);
-      }
-      else if( ref->node->classtype == k_classtype_signal_splitter )
-      {
-         struct classtype_signal_splitter *splitter = entdata;
-         logic_bricks_debug_connection( world, node, splitter->next[0], white );
-         logic_bricks_debug_connection( world, node, splitter->next[1], white );
-         logic_bricks_debug_connection( world, node, splitter->next[2], white );
-         logic_bricks_debug_connection( world, node, splitter->next[3], white );
-      }
-      else if( ref->node->classtype == k_classtype_soundscape )
-      {
-         struct classtype_soundscape *inf = entdata;
-         struct soundscape *s = &world->soundscapes[ ref->internal_id ];
-
-         v3f co;
-         v3_copy( ref->node->co, co );
-
-         boxf box;
-         box[0][0] = co[0]-0.12f;
-         box[0][1] = co[1]-0.12f;
-         box[0][2] = co[2]-0.12f;
-         box[1][0] = co[0]+0.12f;
-         box[1][1] = co[1]+0.12f + 0.1f*(float)inf->max_instances;
-         box[1][2] = co[2]+0.12f;
-
-         vg_line_boxf( box, VG__WHITE );
-
-         for( int i=0; i<s->usage_count; i++ )
-         {
-            vg_line_pt3( co, 0.09f, VG__GREEN );
-            co[1] += 0.2f;
-         }
-      }
-      else if( ref->node->classtype == k_classtype_trigger )
-      {
-         struct classtype_trigger *trigger = entdata;
-         logic_bricks_debug_connection( world, node, trigger->target, white );
-      }
-      else if( ref->node->classtype == k_classtype_particle_box )
-      {
-         struct classtype_particle_box *pb = entdata;
-         logic_bricks_debug_connection( world, node, pb->target, white );
-      }
-
-      ref->usage *= vg_maxf( 0.0f, 1.0f-vg.time_delta*5.0f );
-   }
-}
-
-VG_STATIC void logic_packet_terminate( logic_packet *packet )
-{
-   packet->location = 0xffffffff;
-}
-
-VG_STATIC void logic_wire_call( world_instance *world, 
-                                struct logic_brick_ref *ref, 
-                                logic_packet *packet )
-{
-   struct classtype_logic_wire *inf = mdl_get_entdata( world->meta, ref->node );
-
-   if( packet->function == 0 )         /* pass onwards */
-   {
-      if( inf->next )
-      {
-         if( inf->data_type != k_mdl_128bit_datatype_nothing )
-         {
-            packet->data = inf->data;
-            packet->type = inf->data_type;
-         }
-
-         mdl_node *next = mdl_node_from_id( world->meta, inf->next );
-         packet->location = next->sub_uid;
-         packet->function = inf->function;
-      }
-      else
-         logic_packet_terminate( packet );
-   }
-   else if( packet->function == 1 )    /* TODO enable */
-   {
-      logic_packet_terminate( packet );
-   }
-   else if( packet->function == 2 )    /* TODO disable */
-   {
-      logic_packet_terminate( packet );
-   }
-   else
-   {
-      vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
-      logic_packet_terminate( packet );
-   }
-}
-
-VG_STATIC void logic_chances_call( world_instance *world,
-                                   struct logic_brick_ref *ref,
-                                   logic_packet *packet )
-{
-   struct classtype_logic_chances *inf = 
-      mdl_get_entdata( world->meta, ref->node );
-
-   if( packet->function == 0 )      /* pass along */
-   {
-      int red = 1;
-
-      if( vg_randf() > inf->p )
-         red = 0;
-
-      if( inf->targets[red] )
-      {
-         mdl_node *pnext = mdl_node_from_id( world->meta, inf->targets[red] );
-
-         if( (pnext->classtype == k_classtype_logic_wire) ||
-             (pnext->classtype == k_classtype_logic_chances) ||
-             (pnext->classtype == k_classtype_signal_splitter) )
-         {
-            packet->location = pnext->sub_uid;
-         }
-         else
-         {
-            vg_error( "[INVALID TARGET] logic_chances:pass( ... )\n" );
-            vg_warn(  "   target[%d] must be classtype logic_wire\n", red );
-            logic_packet_terminate( packet );
-         }
-      }
-      else
-      {
-         logic_packet_terminate( packet );
-      }
-   }
-   else if( packet->function == 1 ) /* set ratio */
-   {
-      if( packet->type == k_mdl_128bit_datatype_number )
-      {
-         inf->p = packet->data._f32;
-      }
-      else
-      {
-         vg_error( "[INVALID ARGUMENT] logic_chances:set_ratio( f32 p )\n" );
-      }
-
-      logic_packet_terminate( packet );
-   }
-   else
-   {
-      vg_error( "[INVALID FUNCTION] logic_chances:[%u]\n", packet->function );
-      logic_packet_terminate( packet );
-   }
-}
-
-VG_STATIC void logic_soundscape_call( world_instance *world,
-                                      struct logic_brick_ref *ref,
-                                      logic_packet *packet )
-{
-   struct classtype_soundscape *inf = mdl_get_entdata( world->meta, ref->node );
-   struct soundscape *soundscape = &world->soundscapes[ ref->internal_id ];
-
-   if( packet->function == 0 )   /* play */
-   {
-      /* TODO: Only spawn within certain range of player */
-
-      if( packet->type != k_mdl_128bit_datatype_target )
-      {
-         vg_error( "[INVALID ARGUMENT] logic_soundscape:play( ref sound )\n" );
-         vg_warn( "  got datatype: %u\n", packet->type );
-         logic_packet_terminate( packet );
-         return;
-      }
-
-      mdl_node *data = mdl_node_from_id( world->meta, packet->data._u32 );
-
-      if( data->classtype != k_classtype_audio )
-      {
-         vg_error( "[INVALID TARGET] logic_soundscape:play( ref sound )\n" );
-         logic_packet_terminate( packet );
-         return;
-      }
-
-      if( soundscape->usage_count < soundscape->max_instances )
-      {
-         struct world_audio_thing *audio = &world->audio_things[data->sub_uid];
-
-
-         for( int i=0; i<soundscape->max_instances; i++ )
-         {
-            if( !soundscape->channels[i] )
-            {
-               audio_lock();
-               soundscape->channels[i] = audio_request_channel(
-                                          &audio->temp_embedded_clip,
-                                           audio->flags );
-
-               if( soundscape->channels[i] )
-               {
-                  if( audio->flags & AUDIO_FLAG_SPACIAL_3D )
-                  {
-                     audio_channel_set_spacial( soundscape->channels[i],
-                                                soundscape->spawn_position,
-                                                audio->range );
-                  }
-
-                  audio_channel_edit_volume( soundscape->channels[i],
-                                             audio->volume,
-                                             1 );
-               }
-
-               audio_unlock();
-
-               soundscape->usage_count ++;
-               break;
-            }
-         }
-
-      }
-
-      logic_packet_terminate( packet );
-   }
-   else if( packet->function == 1 ) /* set position */
-   {
-      if( packet->type != k_mdl_128bit_datatype_vec3 )
-      {
-         vg_error( "[INVALID ARGUMENT] logic_soundscape:position( v3f co )\n" );
-         logic_packet_terminate( packet );
-         return;
-      }
-
-      v3_copy( packet->data._v4f, soundscape->spawn_position );
-      logic_packet_terminate( packet );
-   }
-   else
-   {
-      vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
-      logic_packet_terminate( packet );
-   }
-}
-
-VG_STATIC void _logic_trigger_base_call( world_instance *world, u32 target,
-                                         logic_packet *packet )
-{
-   if( packet->function == 0 )         /* pass onwards */
-   {
-      if( target )
-      {
-         mdl_node *next = mdl_node_from_id( world->meta, target );
-         packet->location = next->sub_uid;
-         packet->function = 0; /* always call the default function */
-      }
-      else
-         logic_packet_terminate( packet );
-   }
-   else
-   {
-      vg_error( "[INVALID FUNCTION] logic_trigger:[%u]\n", packet->function );
-      logic_packet_terminate( packet );
-   }
-}
-
-VG_STATIC void logic_trigger_call( world_instance *world,
-                                   struct logic_brick_ref *ref,
-                                   logic_packet *packet )
-{
-   struct classtype_trigger *inf = mdl_get_entdata( world->meta, ref->node );
-   _logic_trigger_base_call( world, inf->target, packet );
-}
-
-VG_STATIC void logic_particle_call( world_instance *world, 
-                                    struct logic_brick_ref *ref,
-                                    logic_packet *packet )
-{
-   struct classtype_particle_box *inf = 
-      mdl_get_entdata( world->meta, ref->node );
-
-   /* rate of 1.0 means we get one a second or 0.1 per tick */
-
-   if( vg_randf() < inf->rate * 0.1f )
-   {
-      ref->usage += 1.0f;
-      _logic_trigger_base_call( world, inf->target, packet );
-   }
-   else
-   {
-      logic_packet_terminate( packet );
-   }
-}
-
-VG_STATIC void logic_bricks_send_packet( world_instance *world,
-                                         logic_packet *packet );
-
-VG_STATIC void logic_splitter( world_instance *world,
-                               struct logic_brick_ref *ref,
-                               logic_packet *packet )
-{
-   struct classtype_signal_splitter *inf 
-      = mdl_get_entdata( world->meta, ref->node );
-
-   if( packet->function == 0 )         /* pass onwards */
-   {
-      for( int i=0; i<4; i++ )
-      {
-         if( inf->next[i] )
-         {
-            logic_packet copy = *packet;
-
-            mdl_node *next = mdl_node_from_id( world->meta, inf->next[i] );
-            copy.location = next->sub_uid;
-            copy.function = 0; /* always call the default function */
-
-            logic_bricks_send_packet( world, &copy );
-         }
-      }
-
-      logic_packet_terminate( packet );
-   }
-   else
-   {
-      vg_error( "[INVALID FUNCTION] logic_splitter:[%u]\n", packet->function );
-      logic_packet_terminate( packet );
-   }
-}
-
-VG_STATIC void logic_bricks_send_packet( world_instance *world,
-                                         logic_packet *packet )
-{
-   while( packet->location != 0xffffffff )
-   {
-      struct logic_brick_ref *ref = &world->logic_bricks[ packet->location ];
-      enum classtype type = ref->node->classtype;
-
-      if( type == k_classtype_logic_wire )
-      {
-         logic_wire_call( world, ref, packet );
-      }
-      else if( type == k_classtype_logic_chances )
-      {
-         logic_chances_call( world, ref, packet );
-      }
-      else if( type == k_classtype_soundscape )
-      {
-         logic_soundscape_call( world, ref, packet );
-      }
-      else if( type == k_classtype_trigger )
-      {
-         logic_trigger_call( world, ref, packet );
-      }
-      else if( type == k_classtype_particle_box )
-      {
-         logic_particle_call( world, ref, packet );
-         continue;
-      }
-      else if( type == k_classtype_signal_splitter )
-      {
-         logic_splitter( world, ref, packet );
-      }
-      else
-      {
-         vg_error( "Undefined logic brick (entity type %d)\n", type );
-         logic_packet_terminate( packet );
-      }
-
-      ref->usage += 1.0f;
-   }
-}
-
-VG_STATIC void logic_bricks_world_gen_allocate( world_instance *world )
-{
-   /* REVISION: unify allocations, loaders and extensions for entities.
-    *           we currently seem to do every which entity a different way */
-
-   world->logic_brick_count = 0;
-   world->logic_bricks = NULL;
-   world->soundscape_count = 0;
-   world->trigger_count = 0;
-
-   for( int i=0; i<world->meta->info.node_count; i++ )
-   {
-      mdl_node *pnode = mdl_node_from_id( world->meta, i );
-
-      if( pnode->classtype == k_classtype_logic_wire ||
-          pnode->classtype == k_classtype_logic_chances ||
-          pnode->classtype == k_classtype_soundscape ||
-          pnode->classtype == k_classtype_trigger ||
-          pnode->classtype == k_classtype_particle_box ||
-          pnode->classtype == k_classtype_signal_splitter )
-      {
-         world->logic_bricks = 
-            vg_linear_extend( world_global.generic_heap, 
-                              world->logic_bricks,
-                              sizeof( struct logic_brick_ref ) );
-
-         pnode->sub_uid = world->logic_brick_count;
-
-         struct logic_brick_ref *ref = 
-            &world->logic_bricks[ world->logic_brick_count ];
-         ref->node = pnode;
-         ref->internal_id = 0;
-
-         if( pnode->classtype == k_classtype_soundscape )
-         {
-            u32 id = world->soundscape_count;
-
-            struct soundscape *soundscape = &world->soundscapes[ id ];
-
-            struct classtype_soundscape *inf =
-               mdl_get_entdata( world->meta, pnode );
-
-            soundscape->label = mdl_pstr( world->meta, inf->label );
-            soundscape->max_instances = inf->max_instances;
-            soundscape->allow_transitions = inf->allow_transitions;
-            soundscape->transition_duration = inf->transition_duration;
-            v3_copy( pnode->co, soundscape->spawn_position );
-
-            ref->internal_id = id;
-            world->soundscape_count ++;
-         }
-         else if( pnode->classtype == k_classtype_trigger ||
-                  pnode->classtype == k_classtype_particle_box )
-         {
-            u32 id = world->trigger_count;
-            struct trigger_zone *trigger = &world->triggers[ id ];
-
-            mdl_node_transform( pnode, trigger->transform );
-            m4x3_invert_full( trigger->transform, trigger->inv_transform );
-            trigger->target_logic_brick = world->logic_brick_count;
-            trigger->classtype = pnode->classtype;
-
-            world->trigger_count ++;
-         }
-
-         world->logic_brick_count ++;
-      }
-   }
-}
-
-#endif
-
-
-
-
-
-#endif /* WORLD_LOGIC_BRICKS_H */
index a01c056c32aebe5e332979461cfdbb1d74bc4e2c..6a415e631ac4c48882b4472d36f98f28d2547811 100644 (file)
@@ -454,6 +454,7 @@ state->g_time_of_day = vg_fractf( g_time );
                     sizeof(struct ub_world_lighting), &world->ub_lighting );
 }
 
+VG_STATIC void skateshop_render(void);
 VG_STATIC void render_world( world_instance *world, camera *cam,
                              int layer_depth )
 {
@@ -465,25 +466,29 @@ VG_STATIC void render_world( world_instance *world, camera *cam,
    render_world_alphatest( world, cam );
    render_terrain( world, cam );
 
-   /* Render SFD's */
-   u32 closest = 0;
-   float min_dist = INFINITY;
+   if( layer_depth == 0 ){
+      skateshop_render();
 
-   if( !mdl_arrcount( &world->ent_route ) )
-      return;
+      /* Render SFD's */
+      u32 closest = 0;
+      float min_dist = INFINITY;
 
-   for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
-      ent_route *route = mdl_arritm( &world->ent_route, i );
-      float dist = v3_dist2( route->board_transform[3], cam->pos );
+      if( !mdl_arrcount( &world->ent_route ) )
+         return;
 
-      if( dist < min_dist ){
-         min_dist = dist;
-         closest = i;
+      for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
+         ent_route *route = mdl_arritm( &world->ent_route, i );
+         float dist = v3_dist2( route->board_transform[3], cam->pos );
+
+         if( dist < min_dist ){
+            min_dist = dist;
+            closest = i;
+         }
       }
-   }
 
-   ent_route *route = mdl_arritm( &world->ent_route, closest );
-   sfd_render( world, cam, route->board_transform );
+      ent_route *route = mdl_arritm( &world->ent_route, closest );
+      sfd_render( world, cam, route->board_transform );
+   }
 }
 
 VG_STATIC void render_world_depth( world_instance *world, camera *cam )