From: hgn Date: Tue, 25 Apr 2023 15:20:29 +0000 (+0100) Subject: skateshop basics X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=872ad3e040f22df357929d3778a955ae8c4ac52b;hp=926a64f679a23d8b0f3594d73405d2486c398a59;p=carveJwlIkooP6JGAAIwe30JlM.git skateshop basics --- diff --git a/blender_export.py b/blender_export.py index 861d692..b533afe 100644 --- a/blender_export.py +++ b/blender_export.py @@ -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 fd0a102..ae1ff0f 100644 --- 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 index 0000000..b126abf --- /dev/null +++ b/ent_skateshop.c @@ -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; istate == 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; iref_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; istate == 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; ifilename ) ){ + + 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; ighost ) 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; ighost = 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; ifilename ) ){ + 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; idb ){ + 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; ient_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; istate = 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; idb ) + 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 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 */ diff --git a/entity.h b/entity.h index 7d6fabf..e8b9d41 100644 --- 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 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 */ diff --git a/maps_src/mp_mtzero.mdl b/maps_src/mp_mtzero.mdl index 0fb6064..e2f8b9e 100644 Binary files a/maps_src/mp_mtzero.mdl and b/maps_src/mp_mtzero.mdl differ diff --git a/maps_src/mp_spawn.mdl b/maps_src/mp_spawn.mdl index 48b5ecf..c33fb0d 100644 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 4834490..7e6649a 100644 --- 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 8f90d12..811f3a1 100644 --- 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 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 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 index 0000000..24feb86 Binary files /dev/null and b/models_src/boards/skaterift_striped.mdl differ diff --git a/network.h b/network.h index fc454c7..ffd2dbe 100644 --- 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), diff --git a/player.c b/player.c index da09707..e205202 100644 --- 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 ); } diff --git a/player.h b/player.h index dac0db4..77a01fc 100644 --- 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; diff --git a/player_render.c b/player_render.c index df0dd6b..171b339 100644 --- a/player_render.c +++ b/player_render.c @@ -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; ientity_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 */ diff --git a/player_skate.c b/player_skate.c index 7029edc..9b1aea1 100644 --- a/player_skate.c +++ b/player_skate.c @@ -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 ); diff --git a/player_walk.c b/player_walk.c index 7d160a7..d8fe3d1 100644 --- a/player_walk.c +++ b/player_walk.c @@ -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", diff --git a/player_walk.h b/player_walk.h index 4c6b7a3..989384c 100644 --- a/player_walk.h +++ b/player_walk.h @@ -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 index 0000000..b14d120 --- /dev/null +++ b/shaders/model_entity.fs @@ -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 index 0000000..777f660 --- /dev/null +++ b/shaders/model_entity.h @@ -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 */ diff --git a/skaterift.c b/skaterift.c index 6246be3..73767a2 100644 --- a/skaterift.c +++ b/skaterift.c @@ -22,9 +22,10 @@ #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 7084ff1..01b12b9 100644 --- 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; jent_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 index d6e9d11..0000000 --- a/world_logic_bricks.h +++ /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; ilogic_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; iusage_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; imax_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, © ); - } - } - - 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; imeta->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 */ diff --git a/world_render.h b/world_render.h index a01c056..6a415e6 100644 --- a/world_render.h +++ b/world_render.h @@ -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; ient_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; ient_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 )