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