"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
("submesh_start",c_uint32),
("submesh_count",c_uint32),
("pstr_name",c_uint32),
- ("flags",c_uint32),
+ ("entity_id",c_uint32),
("armature_id",c_uint32)]
#}
class mdl_texture(Structure):
#{
_fields_ = [("file",mdl_file),
- ("type",c_uint32)]
+ ("glname",c_uint32)]
#}
class mdl_array(Structure):
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 )
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)
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 )
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
#}
if mod.type == 'ARMATURE': #{
- node.flags = 1
armature = mod.object
rig_weight_groups = \
['0 [ROOT]']+[_.name for _ in sr_armature_bones(mod.object)]
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 ]
#}
_.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":#{
#}
#}
+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)
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
)
#}
('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(
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", \
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 \
_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" );
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;
#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
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)
u32 submesh_start,
submesh_count,
pstr_name,
- flags,
+ entity_id, /* upper 16 bits: type, lower 16 bits: index */
armature_id;
};
struct mdl_texture
{
mdl_file file;
- u32 type;
+ u32 glname;
};
struct mdl_array
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 );
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
*/
}
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
}
}
-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
*/
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 )
#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"
* --------------------------------------------------
*/
+
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;
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"
#include "player_skate.c"
#include "player_dead.c"
#include "player_drive.c"
+#include "player_render.c"
+#include "player_ragdoll.c"
#endif /* PLAYER_H */
#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;
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 */
#include "shaders/model_character_view.h"
-struct player_avatar
-{
- mdl_context meta;
- struct skeleton sk;
-
- u32 id_hip,
- id_ik_hand_l,
- id_ik_hand_r,
- id_ik_elbow_l,
- id_ik_elbow_r,
- id_head,
- id_ik_foot_l,
- id_ik_foot_r,
- id_ik_knee_l,
- id_ik_knee_r,
- id_wheel_l,
- id_wheel_r,
- id_board;
-};
-
-#if 0
-glmesh player_meshes[3];
-#endif
-
-VG_STATIC void player_avatar_load( struct player_avatar *av, const char *path )
-{
- /* load in reference player model, with animations and such */
- /* FIXME: This is allocated as un-freeable systems memory */
-
- mdl_open( &av->meta, path, vg_mem.rtmemory );
- mdl_load_metadata_block( &av->meta, vg_mem.rtmemory );
- mdl_load_animation_block( &av->meta, vg_mem.rtmemory );
- mdl_close( &av->meta );
-
- struct skeleton *sk = &av->sk;
- skeleton_setup( sk, vg_mem.rtmemory, &av->meta );
-
- av->id_hip = skeleton_bone_id( sk, "hips" );
- av->id_ik_hand_l = skeleton_bone_id( sk, "hand.IK.L" );
- av->id_ik_hand_r = skeleton_bone_id( sk, "hand.IK.R" );
- av->id_ik_elbow_l = skeleton_bone_id( sk, "elbow.L" );
- av->id_ik_elbow_r = skeleton_bone_id( sk, "elbow.R" );
- av->id_head = skeleton_bone_id( sk, "head" );
- av->id_ik_foot_l = skeleton_bone_id( sk, "foot.IK.L" );
- av->id_ik_foot_r = skeleton_bone_id( sk, "foot.IK.R" );
- av->id_board = skeleton_bone_id( sk, "board" );
- av->id_wheel_l = skeleton_bone_id( sk, "wheel.L" );
- av->id_wheel_r = skeleton_bone_id( sk, "wheel.R" );
- av->id_ik_knee_l = skeleton_bone_id( sk, "knee.L" );
- av->id_ik_knee_r = skeleton_bone_id( sk, "knee.R" );
-}
-
-#if 0
-VG_STATIC void player_load_reference( struct player_model *pmodel )
-{
- shader_viewchar_register();
- vg_acquire_thread_sync();
- {
- vg_tex2d_init( (vg_tex2d *[]){ &tex_characters }, 1 );
- }
- vg_release_thread_sync();
-
- /* load in reference player model, with animations and such */
- mdl_open( &player.mdl.meta, "models/ch_new.mdl" );
- mdl_load_metadata( &player.mdl.meta, vg_mem.rtmemory );
- mdl_load_anim_data( &player.mdl.meta, vg_mem.rtmemory );
-
- vg_linear_clear( vg_mem.scratch );
- mdl_load_mesh_data( &player.mdl.meta, vg_mem.scratch );
- mdl_close( &player.mdl.meta );
-
- /*
- * load in other player models. This may need to be more sophisticated in
- * the futre if we have more of these guys
- */
- mdl_context ctx_outlaw,
- ctx_jordan;
-
- mdl_open( &ctx_outlaw, "models/ch_outlaw.mdl" );
- mdl_load_metadata( &ctx_outlaw, vg_mem.scratch );
- mdl_load_mesh_data( &ctx_outlaw, vg_mem.scratch );
- mdl_close( &ctx_outlaw );
-
- mdl_open( &ctx_jordan, "models/ch_jordan.mdl" );
- mdl_load_metadata( &ctx_jordan, vg_mem.scratch );
- mdl_load_mesh_data( &ctx_jordan, vg_mem.scratch );
- mdl_close( &ctx_jordan );
-
- vg_acquire_thread_sync();
- {
- mdl_unpack_glmesh( &player.mdl.meta, &player.mdl.player_meshes[0] );
- mdl_unpack_glmesh( &ctx_outlaw, &player.mdl.player_meshes[1] );
- mdl_unpack_glmesh( &ctx_jordan, &player.mdl.player_meshes[2] );
- }
- vg_release_thread_sync();
-
- skeleton_setup( &player.mdl.sk, vg_mem.rtmemory, &player.mdl.meta );
- player_init_ragdoll();
-
- /*
- * Link animations
- */
- struct _load_anim
- {
- const char *name;
- struct skeleton_anim **anim;
- }
- anims[] = {
- { "pose_stand", &player.mdl.anim_stand },
- { "pose_highg", &player.mdl.anim_highg },
- { "pose_slide", &player.mdl.anim_slide },
- { "pose_air", &player.mdl.anim_air },
- { "push", &player.mdl.anim_push },
- { "push_reverse", &player.mdl.anim_push_reverse },
- { "ollie", &player.mdl.anim_ollie },
- { "ollie_reverse",&player.mdl.anim_ollie_reverse },
- { "grabs", &player.mdl.anim_grabs },
- { "walk", &player.mdl.anim_walk },
- { "run", &player.mdl.anim_run },
- { "idle_cycle", &player.mdl.anim_idle },
- { "jump", &player.mdl.anim_jump }
- };
-
- for( int i=0; i<vg_list_size(anims); i++ )
- {
- *anims[i].anim = skeleton_get_anim( &player.mdl.sk, anims[i].name );
-
- if( !(*anims[i].anim) )
- {
- vg_error( "Animation '%s' is missing\n", anims[i].name );
- vg_fatal_exit_loop( "Invalid character file" );
- }
- }
-
- /*
- * Link bones
- */
- struct _load_bone
- {
- const char *name;
- u32 *bone_id;
- }
- bones[] = {
- { "hips", &player.mdl.id_hip },
- { "hand.IK.L", &player.mdl.id_ik_hand_l },
- { "hand.IK.R", &player.mdl.id_ik_hand_r },
- { "elbow.L", &player.mdl.id_ik_elbow_l },
- { "elbow.R", &player.mdl.id_ik_elbow_r },
- { "head", &player.mdl.id_head },
- { "foot.IK.L", &player.mdl.id_ik_foot_l },
- { "foot.IK.R", &player.mdl.id_ik_foot_r },
- { "board", &player.mdl.id_board }
- };
-
- for( int i=0; i<vg_list_size(bones); i++ )
- {
- *bones[i].bone_id = skeleton_bone_id( &player.mdl.sk, bones[i].name );
-
- if( !(*bones[i].bone_id) )
- {
- vg_error( "Required bone '%s' is missing\n", bones[i].name );
- vg_fatal_exit_loop( "Invalid character file" );
- }
- }
-}
-#endif
-
#endif
--- /dev/null
+#ifndef PLAYER_RAGDOLL_C
+#define PLAYER_RAGDOLL_C
+
+#include "player.h"
+#include "audio.h"
+
+VG_STATIC void player_ragdoll_init(void)
+{
+ VG_VAR_F32( k_ragdoll_limit_scale );
+ VG_VAR_I32( k_ragdoll_div );
+ VG_VAR_I32( k_ragdoll_debug_collider );
+ VG_VAR_I32( k_ragdoll_debug_constraints );
+}
+
+VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
+ struct ragdoll_part *rp )
+{
+ m4x3_identity( rp->collider_mtx );
+
+ if( bone->collider == k_bone_collider_box ){
+ v3f delta;
+ v3_sub( bone->hitbox[1], bone->hitbox[0], delta );
+ v3_muls( delta, 0.5f, delta );
+ v3_add( bone->hitbox[0], delta, rp->collider_mtx[3] );
+
+ v3_copy( delta, rp->obj.rb.bbx[1] );
+ v3_muls( delta, -1.0f, rp->obj.rb.bbx[0] );
+
+ q_identity( rp->obj.rb.q );
+ rp->obj.type = k_rb_shape_box;
+ rp->colour = 0xffcccccc;
+ }
+ else if( bone->collider == k_bone_collider_capsule ){
+ v3f v0, v1, tx, ty;
+ v3_sub( bone->hitbox[1], bone->hitbox[0], v0 );
+
+ int major_axis = 0;
+ float largest = -1.0f;
+
+ for( int i=0; i<3; i ++ ){
+ if( fabsf( v0[i] ) > largest ){
+ largest = fabsf( v0[i] );
+ major_axis = i;
+ }
+ }
+
+ v3_zero( v1 );
+ v1[ major_axis ] = 1.0f;
+ rb_tangent_basis( v1, tx, ty );
+
+ float r = (fabsf(v3_dot(tx,v0)) + fabsf(v3_dot(ty,v0))) * 0.25f,
+ l = fabsf(v0[ major_axis ]);
+
+ /* orientation */
+ v3_muls( tx, -1.0f, rp->collider_mtx[0] );
+ v3_muls( v1, -1.0f, rp->collider_mtx[1] );
+ v3_muls( ty, -1.0f, rp->collider_mtx[2] );
+ v3_add( bone->hitbox[0], bone->hitbox[1], rp->collider_mtx[3] );
+ v3_muls( rp->collider_mtx[3], 0.5f, rp->collider_mtx[3] );
+
+ rp->obj.type = k_rb_shape_capsule;
+ rp->obj.inf.capsule.height = l;
+ rp->obj.inf.capsule.radius = r;
+
+ rp->colour = 0xff000000 | (0xff << (major_axis*8));
+ }
+ else{
+ vg_warn( "type: %u\n", bone->collider );
+ vg_fatal_exit_loop( "Invalid bone collider type" );
+ }
+
+ m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx );
+
+ /* Position collider into rest */
+ m3x3_q( rp->collider_mtx, rp->obj.rb.q );
+ v3_add( rp->collider_mtx[3], bone->co, rp->obj.rb.co );
+ v3_zero( rp->obj.rb.v );
+ v3_zero( rp->obj.rb.w );
+ rb_init_object( &rp->obj );
+}
+
+/*
+ * Get parent index in the ragdoll
+ */
+VG_STATIC u32 ragdoll_bone_parent( struct player_ragdoll *rd,
+ struct player_avatar *av, u32 bone_id )
+{
+ for( u32 j=0; j<rd->part_count; j++ )
+ if( rd->parts[ j ].bone_id == bone_id )
+ return j;
+
+ vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" );
+ return 0;
+}
+
+/*
+ * Setup ragdoll colliders
+ */
+VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd,
+ struct player_avatar *av )
+{
+ rd->part_count = 0;
+
+ if( !av->sk.collider_count )
+ return;
+
+ rd->position_constraints_count = 0;
+ rd->cone_constraints_count = 0;
+
+ for( u32 i=1; i<av->sk.bone_count; i ++ ){
+ struct skeleton_bone *bone = &av->sk.bones[i];
+
+ /*
+ * Bones with colliders
+ */
+ if( !(bone->collider) )
+ continue;
+
+ if( rd->part_count > vg_list_size(rd->parts) )
+ vg_fatal_exit_loop( "Playermodel has too many colliders" );
+
+ struct ragdoll_part *rp = &rd->parts[ rd->part_count ++ ];
+ rp->bone_id = i;
+ rp->parent = 0xffffffff;
+
+ player_init_ragdoll_bone_collider( bone, rp );
+
+ /*
+ * Bones with collider and parent
+ */
+ if( !bone->parent )
+ continue;
+
+ rp->parent = ragdoll_bone_parent( rd, av, bone->parent );
+
+
+ if( bone->orig_bone->flags & k_bone_flag_cone_constraint ){
+ struct rb_constr_pos *c =
+ &rd->position_constraints[ rd->position_constraints_count ++ ];
+
+ struct skeleton_bone *bj = &av->sk.bones[rp->bone_id];
+ struct ragdoll_part *pp = &rd->parts[rp->parent];
+ struct skeleton_bone *bp = &av->sk.bones[pp->bone_id];
+
+ /* Convention: rba -- parent, rbb -- child */
+ c->rba = &pp->obj.rb;
+ c->rbb = &rp->obj.rb;
+
+ v3f delta;
+ v3_sub( bj->co, bp->co, delta );
+ m4x3_mulv( rp->inv_collider_mtx, (v3f){0.0f,0.0f,0.0f}, c->lcb );
+ m4x3_mulv( pp->inv_collider_mtx, delta, c->lca );
+
+
+ mdl_bone *inf = bone->orig_bone;
+
+ struct rb_constr_swingtwist *a =
+ &rd->cone_constraints[ rd->cone_constraints_count ++ ];
+
+ a->rba = &pp->obj.rb;
+ a->rbb = &rp->obj.rb;
+ a->conet = cosf( inf->conet )-0.0001f;
+
+ /* Store constraint in local space vectors */
+ m3x3_mulv( c->rba->to_local, inf->conevx, a->conevx );
+ m3x3_mulv( c->rba->to_local, inf->conevy, a->conevy );
+ m3x3_mulv( c->rbb->to_local, inf->coneva, a->coneva );
+ v3_copy( c->lca, a->view_offset );
+
+ v3_cross( inf->coneva, inf->conevy, a->conevxb );
+ m3x3_mulv( c->rbb->to_local, a->conevxb, a->conevxb );
+
+ v3_normalize( a->conevxb );
+ v3_normalize( a->conevx );
+ v3_normalize( a->conevy );
+ v3_normalize( a->coneva );
+
+ a->conevx[3] = v3_length( inf->conevx );
+ a->conevy[3] = v3_length( inf->conevy );
+
+ rp->use_limits = 1;
+ }
+ }
+}
+
+/*
+ * Make avatar copy the ragdoll
+ */
+VG_STATIC void copy_ragdoll_pose_to_avatar( struct player_ragdoll *rd,
+ struct player_avatar *av )
+{
+ for( int i=0; i<rd->part_count; i++ ){
+ struct ragdoll_part *part = &rd->parts[i];
+
+ m4x3f mtx;
+
+ v4f q_int;
+ v3f co_int;
+
+ float substep = vg.time_fixed_extrapolate;
+ v3_lerp( part->prev_co, part->obj.rb.co, substep, co_int );
+ q_nlerp( part->prev_q, part->obj.rb.q, substep, q_int );
+
+ q_m3x3( q_int, mtx );
+ v3_copy( co_int, mtx[3] );
+
+ m4x3_mul( mtx, part->inv_collider_mtx, av->sk.final_mtx[part->bone_id] );
+ }
+
+ for( u32 i=1; i<av->sk.bone_count; i++ ){
+ struct skeleton_bone *sb = &av->sk.bones[i];
+
+ if( sb->parent && !sb->collider ){
+ v3f delta;
+ v3_sub( av->sk.bones[i].co, av->sk.bones[sb->parent].co, delta );
+
+ m4x3f posemtx;
+ m3x3_identity( posemtx );
+ v3_copy( delta, posemtx[3] );
+
+ /* final matrix */
+ m4x3_mul( av->sk.final_mtx[sb->parent], posemtx, av->sk.final_mtx[i] );
+ }
+ }
+
+ skeleton_apply_inverses( &av->sk );
+}
+
+/*
+ * Make the ragdoll copy the player model
+ */
+VG_STATIC void copy_avatar_pose_to_ragdoll( struct player_avatar *av,
+ struct player_ragdoll *rd,
+ v3f velocity )
+{
+ for( int i=0; i<rd->part_count; i++ ){
+ struct ragdoll_part *part = &rd->parts[i];
+
+ v3f pos, offset;
+ u32 bone = part->bone_id;
+
+ m4x3_mulv( av->sk.final_mtx[bone], av->sk.bones[bone].co, pos );
+ m3x3_mulv( av->sk.final_mtx[bone], part->collider_mtx[3], offset );
+ v3_add( pos, offset, part->obj.rb.co );
+
+ m3x3f r;
+ m3x3_mul( av->sk.final_mtx[bone], part->collider_mtx, r );
+ m3x3_q( r, part->obj.rb.q );
+
+ v3_copy( velocity, part->obj.rb.v );
+ v3_zero( part->obj.rb.w );
+
+ v3_copy( part->obj.rb.co, part->prev_co );
+ v4_copy( part->obj.rb.q, part->prev_q );
+
+ rb_update_transform( &part->obj.rb );
+ }
+}
+
+/*
+ * Draw rigidbody colliders for ragdoll
+ */
+VG_STATIC void player_debug_ragdoll(void)
+{
+}
+
+/*
+ * Ragdoll physics step
+ */
+VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd )
+{
+ world_instance *world = get_active_world();
+
+ int run_sim = 0;
+ ragdoll_frame ++;
+
+ if( ragdoll_frame >= k_ragdoll_div ){
+ ragdoll_frame = 0;
+ run_sim = 1;
+ }
+
+ rb_solver_reset();
+
+ float contact_velocities[256];
+
+ for( int i=0; i<rd->part_count; i ++ ){
+ v4_copy( rd->parts[i].obj.rb.q, rd->parts[i].prev_q );
+ v3_copy( rd->parts[i].obj.rb.co, rd->parts[i].prev_co );
+
+ if( rb_global_has_space() ){
+ rb_ct *buf = rb_global_buffer();
+
+ int l;
+
+ if( rd->parts[i].obj.type == k_rb_shape_capsule ){
+ l = rb_capsule__scene( rd->parts[i].obj.rb.to_world,
+ &rd->parts[i].obj.inf.capsule,
+ NULL, &world->rb_geo.inf.scene, buf );
+ }
+ else if( rd->parts[i].obj.type == k_rb_shape_box ){
+ l = rb_box__scene( rd->parts[i].obj.rb.to_world,
+ rd->parts[i].obj.rb.bbx,
+ NULL, &world->rb_geo.inf.scene, buf );
+ }
+ else continue;
+
+ for( int j=0; j<l; j++ ){
+ buf[j].rba = &rd->parts[i].obj.rb;
+ buf[j].rbb = &world->rb_geo.rb;
+ }
+
+ rb_contact_count += l;
+ }
+ }
+
+ /*
+ * self-collision
+ */
+ for( int i=0; i<rd->part_count-1; i ++ ){
+ for( int j=i+1; j<rd->part_count; j ++ ){
+ if( rd->parts[j].parent != i ){
+ if( !rb_global_has_space() )
+ break;
+
+ if( rd->parts[j].obj.type != k_rb_shape_capsule )
+ continue;
+
+ if( rd->parts[i].obj.type != k_rb_shape_capsule )
+ continue;
+
+ rb_ct *buf = rb_global_buffer();
+
+ int l = rb_capsule__capsule( rd->parts[i].obj.rb.to_world,
+ &rd->parts[i].obj.inf.capsule,
+ rd->parts[j].obj.rb.to_world,
+ &rd->parts[j].obj.inf.capsule,
+ buf );
+
+ for( int k=0; k<l; k++ ){
+ buf[k].rba = &rd->parts[i].obj.rb;
+ buf[k].rbb = &rd->parts[j].obj.rb;
+ }
+
+ rb_contact_count += l;
+ }
+ }
+ }
+
+ for( int j=0; j<rd->part_count; j++ ){
+ struct ragdoll_part *pj = &rd->parts[j];
+
+ if( run_sim ){
+ v4f plane = {0.0f,1.0f,0.0f,0.0f};
+ rb_effect_simple_bouyency( &pj->obj.rb, plane,
+ k_ragdoll_floatyiness,
+ k_ragdoll_floatydrag );
+ }
+ }
+
+ /*
+ * PRESOLVE
+ */
+ for( u32 i=0; i<rb_contact_count; i++ ){
+ rb_ct *ct = &rb_contact_buffer[i];
+
+ v3f rv, ra, rb;
+ v3_sub( ct->co, ct->rba->co, ra );
+ v3_sub( ct->co, ct->rbb->co, rb );
+ rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
+ float vn = v3_dot( rv, ct->n );
+
+ contact_velocities[i] = vn;
+ }
+
+ rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
+ rb_presolve_swingtwist_constraints( rd->cone_constraints,
+ rd->cone_constraints_count );
+
+ /*
+ * DEBUG
+ */
+ if( k_ragdoll_debug_collider ){
+ for( u32 i=0; i<rd->part_count; i ++ )
+ rb_object_debug( &rd->parts[i].obj, rd->parts[i].colour );
+ }
+
+ if( k_ragdoll_debug_constraints ){
+ rb_debug_position_constraints( rd->position_constraints,
+ rd->position_constraints_count );
+
+ rb_debug_swingtwist_constraints( rd->cone_constraints,
+ rd->cone_constraints_count );
+ }
+
+ /*
+ * SOLVE CONSTRAINTS
+ */
+ if( run_sim ){
+ for( int i=0; i<16; i++ ){
+ rb_solve_contacts( rb_contact_buffer, rb_contact_count );
+ rb_solve_swingtwist_constraints( rd->cone_constraints,
+ rd->cone_constraints_count );
+ rb_solve_position_constraints( rd->position_constraints,
+ rd->position_constraints_count );
+ }
+
+ for( int i=0; i<rd->part_count; i++ )
+ rb_iter( &rd->parts[i].obj.rb );
+
+ for( int i=0; i<rd->part_count; i++ )
+ rb_update_transform( &rd->parts[i].obj.rb );
+
+ rb_correct_swingtwist_constraints( rd->cone_constraints,
+ rd->cone_constraints_count, 0.25f );
+
+ rb_correct_position_constraints( rd->position_constraints,
+ rd->position_constraints_count, 0.5f );
+ }
+
+ rb_ct *stress = NULL;
+ float max_stress = 1.0f;
+
+ for( u32 i=0; i<rb_contact_count; i++ ){
+ rb_ct *ct = &rb_contact_buffer[i];
+
+ v3f rv, ra, rb;
+ v3_sub( ct->co, ct->rba->co, ra );
+ v3_sub( ct->co, ct->rbb->co, rb );
+ rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
+ float vn = v3_dot( rv, ct->n );
+
+ float s = fabsf(vn - contact_velocities[i]);
+ if( s > max_stress ){
+ stress = ct;
+ max_stress = s;
+ }
+ }
+
+ static u32 temp_filter = 0;
+
+ if( temp_filter ){
+ temp_filter --;
+ return;
+ }
+
+ if( stress ){
+ temp_filter = 20;
+ audio_lock();
+ audio_oneshot_3d( &audio_hits[rand()%5], stress->co, 20.0f, 1.0f );
+ audio_unlock();
+ }
+}
+
+#endif /* PLAYER_RAGDOLL_C */
#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{
k_ragdoll_debug_collider = 1,
k_ragdoll_debug_constraints = 0;
-VG_STATIC void player_ragdoll_init(void)
-{
- VG_VAR_F32( k_ragdoll_limit_scale );
- VG_VAR_I32( k_ragdoll_div );
- VG_VAR_I32( k_ragdoll_debug_collider );
- VG_VAR_I32( k_ragdoll_debug_constraints );
-}
-
+VG_STATIC void player_ragdoll_init(void);
VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
- struct ragdoll_part *rp )
-{
- m4x3_identity( rp->collider_mtx );
-
- if( bone->collider == k_bone_collider_box ){
- v3f delta;
- v3_sub( bone->hitbox[1], bone->hitbox[0], delta );
- v3_muls( delta, 0.5f, delta );
- v3_add( bone->hitbox[0], delta, rp->collider_mtx[3] );
-
- v3_copy( delta, rp->obj.rb.bbx[1] );
- v3_muls( delta, -1.0f, rp->obj.rb.bbx[0] );
-
- q_identity( rp->obj.rb.q );
- rp->obj.type = k_rb_shape_box;
- rp->colour = 0xffcccccc;
- }
- else if( bone->collider == k_bone_collider_capsule ){
- v3f v0, v1, tx, ty;
- v3_sub( bone->hitbox[1], bone->hitbox[0], v0 );
-
- int major_axis = 0;
- float largest = -1.0f;
-
- for( int i=0; i<3; i ++ ){
- if( fabsf( v0[i] ) > largest ){
- largest = fabsf( v0[i] );
- major_axis = i;
- }
- }
-
- v3_zero( v1 );
- v1[ major_axis ] = 1.0f;
- rb_tangent_basis( v1, tx, ty );
-
- float r = (fabsf(v3_dot(tx,v0)) + fabsf(v3_dot(ty,v0))) * 0.25f,
- l = fabsf(v0[ major_axis ]);
-
- /* orientation */
- v3_muls( tx, -1.0f, rp->collider_mtx[0] );
- v3_muls( v1, -1.0f, rp->collider_mtx[1] );
- v3_muls( ty, -1.0f, rp->collider_mtx[2] );
- v3_add( bone->hitbox[0], bone->hitbox[1], rp->collider_mtx[3] );
- v3_muls( rp->collider_mtx[3], 0.5f, rp->collider_mtx[3] );
-
- rp->obj.type = k_rb_shape_capsule;
- rp->obj.inf.capsule.height = l;
- rp->obj.inf.capsule.radius = r;
-
- rp->colour = 0xff000000 | (0xff << (major_axis*8));
- }
- else{
- vg_warn( "type: %u\n", bone->collider );
- vg_fatal_exit_loop( "Invalid bone collider type" );
- }
-
- m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx );
-
- /* Position collider into rest */
- m3x3_q( rp->collider_mtx, rp->obj.rb.q );
- v3_add( rp->collider_mtx[3], bone->co, rp->obj.rb.co );
- v3_zero( rp->obj.rb.v );
- v3_zero( rp->obj.rb.w );
- rb_init_object( &rp->obj );
-}
-
-/*
- * Get parent index in the ragdoll
- */
+ struct ragdoll_part *rp );
VG_STATIC u32 ragdoll_bone_parent( struct player_ragdoll *rd,
- struct player_avatar *av, u32 bone_id )
-{
- for( u32 j=0; j<rd->part_count; j++ )
- if( rd->parts[ j ].bone_id == bone_id )
- return j;
-
- vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" );
- return 0;
-}
-
-/*
- * Setup ragdoll colliders
- */
+ struct player_avatar *av, u32 bone_id );
VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd,
- struct player_avatar *av )
-{
- rd->part_count = 0;
-
- if( !av->sk.collider_count )
- return;
-
- rd->position_constraints_count = 0;
- rd->cone_constraints_count = 0;
-
- for( u32 i=1; i<av->sk.bone_count; i ++ ){
- struct skeleton_bone *bone = &av->sk.bones[i];
-
- /*
- * Bones with colliders
- */
- if( !(bone->collider) )
- continue;
-
- if( rd->part_count > vg_list_size(rd->parts) )
- vg_fatal_exit_loop( "Playermodel has too many colliders" );
-
- struct ragdoll_part *rp = &rd->parts[ rd->part_count ++ ];
- rp->bone_id = i;
- rp->parent = 0xffffffff;
-
- player_init_ragdoll_bone_collider( bone, rp );
-
- /*
- * Bones with collider and parent
- */
- if( !bone->parent )
- continue;
-
- rp->parent = ragdoll_bone_parent( rd, av, bone->parent );
-
-
- if( bone->orig_bone->flags & k_bone_flag_cone_constraint ){
- struct rb_constr_pos *c =
- &rd->position_constraints[ rd->position_constraints_count ++ ];
-
- struct skeleton_bone *bj = &av->sk.bones[rp->bone_id];
- struct ragdoll_part *pp = &rd->parts[rp->parent];
- struct skeleton_bone *bp = &av->sk.bones[pp->bone_id];
-
- /* Convention: rba -- parent, rbb -- child */
- c->rba = &pp->obj.rb;
- c->rbb = &rp->obj.rb;
-
- v3f delta;
- v3_sub( bj->co, bp->co, delta );
- m4x3_mulv( rp->inv_collider_mtx, (v3f){0.0f,0.0f,0.0f}, c->lcb );
- m4x3_mulv( pp->inv_collider_mtx, delta, c->lca );
-
-
- mdl_bone *inf = bone->orig_bone;
-
- struct rb_constr_swingtwist *a =
- &rd->cone_constraints[ rd->cone_constraints_count ++ ];
-
- a->rba = &pp->obj.rb;
- a->rbb = &rp->obj.rb;
- a->conet = cosf( inf->conet )-0.0001f;
-
- /* Store constraint in local space vectors */
- m3x3_mulv( c->rba->to_local, inf->conevx, a->conevx );
- m3x3_mulv( c->rba->to_local, inf->conevy, a->conevy );
- m3x3_mulv( c->rbb->to_local, inf->coneva, a->coneva );
- v3_copy( c->lca, a->view_offset );
-
- v3_cross( inf->coneva, inf->conevy, a->conevxb );
- m3x3_mulv( c->rbb->to_local, a->conevxb, a->conevxb );
-
- v3_normalize( a->conevxb );
- v3_normalize( a->conevx );
- v3_normalize( a->conevy );
- v3_normalize( a->coneva );
-
- a->conevx[3] = v3_length( inf->conevx );
- a->conevy[3] = v3_length( inf->conevy );
-
- rp->use_limits = 1;
- }
- }
-}
-
-/*
- * Make avatar copy the ragdoll
- */
+ struct player_avatar *av );
VG_STATIC void copy_ragdoll_pose_to_avatar( struct player_ragdoll *rd,
- struct player_avatar *av )
-{
- for( int i=0; i<rd->part_count; i++ ){
- struct ragdoll_part *part = &rd->parts[i];
-
- m4x3f mtx;
-
- v4f q_int;
- v3f co_int;
-
- float substep = vg.time_fixed_extrapolate;
- v3_lerp( part->prev_co, part->obj.rb.co, substep, co_int );
- q_nlerp( part->prev_q, part->obj.rb.q, substep, q_int );
-
- q_m3x3( q_int, mtx );
- v3_copy( co_int, mtx[3] );
-
- m4x3_mul( mtx, part->inv_collider_mtx, av->sk.final_mtx[part->bone_id] );
- }
-
- for( u32 i=1; i<av->sk.bone_count; i++ ){
- struct skeleton_bone *sb = &av->sk.bones[i];
-
- if( sb->parent && !sb->collider ){
- v3f delta;
- v3_sub( av->sk.bones[i].co, av->sk.bones[sb->parent].co, delta );
-
- m4x3f posemtx;
- m3x3_identity( posemtx );
- v3_copy( delta, posemtx[3] );
-
- /* final matrix */
- m4x3_mul( av->sk.final_mtx[sb->parent], posemtx, av->sk.final_mtx[i] );
- }
- }
-
- skeleton_apply_inverses( &av->sk );
-}
-
-/*
- * Make the ragdoll copy the player model
- */
+ struct player_avatar *av );
VG_STATIC void copy_avatar_pose_to_ragdoll( struct player_avatar *av,
struct player_ragdoll *rd,
- v3f velocity )
-{
- for( int i=0; i<rd->part_count; i++ ){
- struct ragdoll_part *part = &rd->parts[i];
-
- v3f pos, offset;
- u32 bone = part->bone_id;
-
- m4x3_mulv( av->sk.final_mtx[bone], av->sk.bones[bone].co, pos );
- m3x3_mulv( av->sk.final_mtx[bone], part->collider_mtx[3], offset );
- v3_add( pos, offset, part->obj.rb.co );
-
- m3x3f r;
- m3x3_mul( av->sk.final_mtx[bone], part->collider_mtx, r );
- m3x3_q( r, part->obj.rb.q );
-
- v3_copy( velocity, part->obj.rb.v );
- v3_zero( part->obj.rb.w );
-
- v3_copy( part->obj.rb.co, part->prev_co );
- v4_copy( part->obj.rb.q, part->prev_q );
-
- rb_update_transform( &part->obj.rb );
- }
-}
-
-/*
- * Draw rigidbody colliders for ragdoll
- */
-VG_STATIC void player_debug_ragdoll(void)
-{
-}
-
-/*
- * Ragdoll physics step
- */
-VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd )
-{
- world_instance *world = get_active_world();
-
- int run_sim = 0;
- ragdoll_frame ++;
-
- if( ragdoll_frame >= k_ragdoll_div ){
- ragdoll_frame = 0;
- run_sim = 1;
- }
-
- rb_solver_reset();
-
- float contact_velocities[256];
-
- for( int i=0; i<rd->part_count; i ++ ){
- v4_copy( rd->parts[i].obj.rb.q, rd->parts[i].prev_q );
- v3_copy( rd->parts[i].obj.rb.co, rd->parts[i].prev_co );
-
- if( rb_global_has_space() ){
- rb_ct *buf = rb_global_buffer();
-
- int l;
-
- if( rd->parts[i].obj.type == k_rb_shape_capsule ){
- l = rb_capsule__scene( rd->parts[i].obj.rb.to_world,
- &rd->parts[i].obj.inf.capsule,
- NULL, &world->rb_geo.inf.scene, buf );
- }
- else if( rd->parts[i].obj.type == k_rb_shape_box ){
- l = rb_box__scene( rd->parts[i].obj.rb.to_world,
- rd->parts[i].obj.rb.bbx,
- NULL, &world->rb_geo.inf.scene, buf );
- }
- else continue;
-
- for( int j=0; j<l; j++ ){
- buf[j].rba = &rd->parts[i].obj.rb;
- buf[j].rbb = &world->rb_geo.rb;
- }
-
- rb_contact_count += l;
- }
- }
-
- /*
- * self-collision
- */
- for( int i=0; i<rd->part_count-1; i ++ ){
- for( int j=i+1; j<rd->part_count; j ++ ){
- if( rd->parts[j].parent != i ){
- if( !rb_global_has_space() )
- break;
-
- if( rd->parts[j].obj.type != k_rb_shape_capsule )
- continue;
-
- if( rd->parts[i].obj.type != k_rb_shape_capsule )
- continue;
-
- rb_ct *buf = rb_global_buffer();
-
- int l = rb_capsule__capsule( rd->parts[i].obj.rb.to_world,
- &rd->parts[i].obj.inf.capsule,
- rd->parts[j].obj.rb.to_world,
- &rd->parts[j].obj.inf.capsule,
- buf );
-
- for( int k=0; k<l; k++ ){
- buf[k].rba = &rd->parts[i].obj.rb;
- buf[k].rbb = &rd->parts[j].obj.rb;
- }
-
- rb_contact_count += l;
- }
- }
- }
-
- for( int j=0; j<rd->part_count; j++ ){
- struct ragdoll_part *pj = &rd->parts[j];
-
- if( run_sim ){
- v4f plane = {0.0f,1.0f,0.0f,0.0f};
- rb_effect_simple_bouyency( &pj->obj.rb, plane,
- k_ragdoll_floatyiness,
- k_ragdoll_floatydrag );
- }
- }
-
- /*
- * PRESOLVE
- */
- for( u32 i=0; i<rb_contact_count; i++ ){
- rb_ct *ct = &rb_contact_buffer[i];
-
- v3f rv, ra, rb;
- v3_sub( ct->co, ct->rba->co, ra );
- v3_sub( ct->co, ct->rbb->co, rb );
- rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
- float vn = v3_dot( rv, ct->n );
-
- contact_velocities[i] = vn;
- }
-
- rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
- rb_presolve_swingtwist_constraints( rd->cone_constraints,
- rd->cone_constraints_count );
-
- /*
- * DEBUG
- */
- if( k_ragdoll_debug_collider ){
- for( u32 i=0; i<rd->part_count; i ++ )
- rb_object_debug( &rd->parts[i].obj, rd->parts[i].colour );
- }
-
- if( k_ragdoll_debug_constraints ){
- rb_debug_position_constraints( rd->position_constraints,
- rd->position_constraints_count );
-
- rb_debug_swingtwist_constraints( rd->cone_constraints,
- rd->cone_constraints_count );
- }
-
- /*
- * SOLVE CONSTRAINTS
- */
- if( run_sim ){
- for( int i=0; i<16; i++ ){
- rb_solve_contacts( rb_contact_buffer, rb_contact_count );
- rb_solve_swingtwist_constraints( rd->cone_constraints,
- rd->cone_constraints_count );
- rb_solve_position_constraints( rd->position_constraints,
- rd->position_constraints_count );
- }
-
- for( int i=0; i<rd->part_count; i++ )
- rb_iter( &rd->parts[i].obj.rb );
-
- for( int i=0; i<rd->part_count; i++ )
- rb_update_transform( &rd->parts[i].obj.rb );
-
- rb_correct_swingtwist_constraints( rd->cone_constraints,
- rd->cone_constraints_count, 0.25f );
-
- rb_correct_position_constraints( rd->position_constraints,
- rd->position_constraints_count, 0.5f );
- }
-
- rb_ct *stress = NULL;
- float max_stress = 1.0f;
-
- for( u32 i=0; i<rb_contact_count; i++ ){
- rb_ct *ct = &rb_contact_buffer[i];
-
- v3f rv, ra, rb;
- v3_sub( ct->co, ct->rba->co, ra );
- v3_sub( ct->co, ct->rbb->co, rb );
- rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
- float vn = v3_dot( rv, ct->n );
-
- float s = fabsf(vn - contact_velocities[i]);
- if( s > max_stress ){
- stress = ct;
- max_stress = s;
- }
- }
-
- static u32 temp_filter = 0;
-
- if( temp_filter ){
- temp_filter --;
- return;
- }
-
- if( stress ){
- temp_filter = 20;
- audio_lock();
- audio_oneshot_3d( &audio_hits[rand()%5], stress->co, 20.0f, 1.0f );
- audio_unlock();
- }
-}
+ v3f velocity );
+VG_STATIC void player_debug_ragdoll(void);
+VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd );
#endif /* PLAYER_RAGDOLL_H */
--- /dev/null
+#ifndef PLAYER_RENDER_C
+#define PLAYER_RENDER_C
+
+#include "player.h"
+#include "player_render.h"
+#include "camera.h"
+#include "player_model.h"
+
+#include "shaders/model_character_view.h"
+#include "shaders/model_board_view.h"
+
+VG_STATIC void player_avatar_load( struct player_avatar *av, const char *path )
+{
+ mdl_open( &av->meta, path, vg_mem.rtmemory );
+ mdl_load_metadata_block( &av->meta, vg_mem.rtmemory );
+ mdl_load_animation_block( &av->meta, vg_mem.rtmemory );
+ mdl_close( &av->meta );
+
+ struct skeleton *sk = &av->sk;
+ skeleton_setup( sk, vg_mem.rtmemory, &av->meta );
+
+ av->id_hip = skeleton_bone_id( sk, "hips" );
+ av->id_ik_hand_l = skeleton_bone_id( sk, "hand.IK.L" );
+ av->id_ik_hand_r = skeleton_bone_id( sk, "hand.IK.R" );
+ av->id_ik_elbow_l = skeleton_bone_id( sk, "elbow.L" );
+ av->id_ik_elbow_r = skeleton_bone_id( sk, "elbow.R" );
+ av->id_head = skeleton_bone_id( sk, "head" );
+ av->id_ik_foot_l = skeleton_bone_id( sk, "foot.IK.L" );
+ av->id_ik_foot_r = skeleton_bone_id( sk, "foot.IK.R" );
+ av->id_board = skeleton_bone_id( sk, "board" );
+ av->id_wheel_l = skeleton_bone_id( sk, "wheel.L" );
+ av->id_wheel_r = skeleton_bone_id( sk, "wheel.R" );
+ av->id_ik_knee_l = skeleton_bone_id( sk, "knee.L" );
+ av->id_ik_knee_r = skeleton_bone_id( sk, "knee.R" );
+}
+
+/* TODO: Standard model load */
+
+VG_STATIC void player_model_load( struct player_model *mdl, const char *path )
+{
+ vg_linear_clear( vg_mem.scratch );
+
+ mdl_context ctx;
+ mdl_open( &ctx, path, vg_mem.scratch );
+ mdl_load_metadata_block( &ctx, vg_mem.scratch );
+ mdl_load_mesh_block( &ctx, vg_mem.scratch );
+
+ if( !mdl_arrcount( &ctx.textures ) )
+ vg_fatal_exit_loop( "No texture in player model" );
+
+ mdl_texture *tex0 = mdl_arritm( &ctx.textures, 0 );
+ void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
+ mdl_fread_pack_file( &ctx, &tex0->file, data );
+
+ vg_acquire_thread_sync();
+ {
+ mdl_unpack_glmesh( &ctx, &mdl->mesh );
+
+ /* upload first texture */
+ mdl->texture = vg_tex2d_new();
+
+ vg_tex2d_set_error();
+ vg_tex2d_qoi( data, tex0->file.pack_size,
+ mdl_pstr( &ctx, tex0->file.pstr_path ));
+ vg_tex2d_nearest();
+ vg_tex2d_clamp();
+ }
+ vg_release_thread_sync();
+
+ mdl_close( &ctx );
+}
+
+VG_STATIC void player_board_load( struct player_board *mdl, const char *path )
+{
+ vg_linear_clear( vg_mem.scratch );
+
+ mdl_context ctx;
+ mdl_open( &ctx, path, vg_mem.scratch );
+ mdl_load_metadata_block( &ctx, vg_mem.scratch );
+ mdl_load_mesh_block( &ctx, vg_mem.scratch );
+
+ mdl_array_ptr markers;
+ mdl_load_array( &ctx, &markers, "ent_marker", vg_mem.scratch );
+
+ if( !mdl_arrcount( &ctx.textures ) )
+ vg_fatal_exit_loop( "No texture in board model" );
+
+ mdl_texture *tex0 = mdl_arritm( &ctx.textures, 0 );
+ void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
+ mdl_fread_pack_file( &ctx, &tex0->file, data );
+
+ vg_acquire_thread_sync();
+ {
+ mdl_unpack_glmesh( &ctx, &mdl->mesh );
+
+ /* upload first texture */
+ mdl->texture = vg_tex2d_new();
+
+ vg_tex2d_set_error();
+ vg_tex2d_qoi( data, tex0->file.pack_size,
+ mdl_pstr( &ctx, tex0->file.pstr_path ));
+ vg_tex2d_nearest();
+ vg_tex2d_clamp();
+ }
+ vg_release_thread_sync();
+
+ mdl_close( &ctx );
+
+ for( int i=0; i<4; i++ )
+ mdl->wheels[i].indice_count = 0;
+ for( int i=0; i<2; i++ )
+ mdl->trucks[i].indice_count = 0;
+ mdl->board.indice_count = 0;
+
+ for( u32 i=0; i<mdl_arrcount(&ctx.meshs); i++ ){
+ mdl_mesh *mesh = mdl_arritm( &ctx.meshs, i );
+
+ vg_info( "[%u]=%u:%u\n", mesh->entity_id,
+ mdl_entity_id_type( mesh->entity_id ),
+ mdl_entity_id_id( mesh->entity_id ) );
+
+ if( mdl_entity_id_type( mesh->entity_id ) != k_ent_marker )
+ continue;
+
+ u32 index = mdl_entity_id_id( mesh->entity_id );
+ ent_marker *marker = mdl_arritm( &markers, index );
+
+ mdl_submesh *sm0 = mdl_arritm( &ctx.submeshs, mesh->submesh_start );
+
+ const char *alias = mdl_pstr( &ctx, marker->pstr_alias );
+ u32 lr = marker->transform.co[0] > 0.0f? 1: 0,
+ fb = marker->transform.co[2] > 0.0f? 0: 1;
+
+ if( !strcmp( alias, "wheel" ) ){
+ u32 id = fb<<1 | lr;
+ mdl->wheels[ id ] = *sm0;
+ v3_copy( marker->transform.co, mdl->wheel_positions[ id ] );
+ }
+ else if( !strcmp( alias, "board" ) ){
+ mdl->board = *sm0;
+ v3_copy( marker->transform.co, mdl->board_position );
+ }
+ else if( !strcmp( alias, "truck" ) ){
+ mdl->trucks[ fb ] = *sm0;
+ v3_copy( marker->transform.co, mdl->truck_positions[ fb ] );
+ }
+ }
+}
+
+VG_STATIC void player__pre_render( player_instance *player )
+{
+ if( _player_animate[ player->subsystem ] ){
+ player_animation res;
+ _player_animate[ player->subsystem ]( player, &res );
+
+ m4x3f transform;
+ q_m3x3( res.root_q, transform );
+ v3_copy( res.root_co, transform[3] );
+
+ struct skeleton *sk = &player->playeravatar->sk;
+
+ if( player->holdout_time > 0.0f ){
+ skeleton_lerp_pose( sk, res.pose, player->holdout_pose,
+ player->holdout_time, res.pose );
+ player->holdout_time -= vg.time_frame_delta * 2.0f;
+ }
+
+ skeleton_apply_pose( sk, res.pose, k_anim_apply_defer_ik );
+ skeleton_apply_ik_pass( sk );
+ skeleton_apply_pose( sk, res.pose, k_anim_apply_deffered_only );
+ skeleton_apply_inverses( sk );
+ skeleton_apply_transform( sk, transform );
+
+ skeleton_debug( sk );
+ }
+
+ if( _player_post_animate[ player->subsystem ] )
+ _player_post_animate[ player->subsystem ]( player );
+
+ struct player_avatar *av = player->playeravatar;
+
+ v3f vp0 = {0.0f,0.1f, player->playerboard->truck_positions[0][2]},
+ vp1 = {0.0f,0.1f, player->playerboard->truck_positions[1][2]};
+
+ struct ub_world_lighting *ubo = &get_active_world()->ub_lighting;
+ m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, ubo->g_board_0 );
+ m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp1, ubo->g_board_1 );
+
+ if( player->rewinding ){
+ if( player->rewind_time <= 0.0f ){
+ double taken = vg.time - player->rewind_start;
+ vg_success( "Rewind took (rt, pt, tl): %f, %f, %f\n",
+ taken, player->rewind_predicted_time,
+ player->rewind_total_length );
+
+ player->rewinding = 0;
+ player->rewind_length = 1;
+ player->rewind_total_length = 0.0f;
+ player->rewind_accum = 0.0f;
+ world_global.sky_target_rate = 1.0;
+ world_global.time = world_global.last_use;
+ }
+ else{
+ world_global.sky_target_rate = -100.0;
+
+ float budget = vg.time_delta,
+ overall_length = player->rewind_length;
+
+ for( int i=0; (i<10)&&(player->rewind_time>0.0f)&&(budget>0.0f); i++ ){
+ /* Interpolate frames */
+ int i0 = floorf( player->rewind_time ),
+ i1 = VG_MIN( i0+1, player->rewind_length-1 );
+
+ struct rewind_frame *fr = &player->rewind_buffer[i0],
+ *fr1 = &player->rewind_buffer[i1];
+
+ float dist = vg_maxf( v3_dist( fr->pos, fr1->pos ), 0.001f ),
+ subl = vg_fractf( player->rewind_time ) + 0.001f,
+
+ sramp = 3.0f-(1.0f/(0.4f+0.4f*player->rewind_time)),
+ speed = sramp*28.0f + 0.5f*player->rewind_time,
+ mod = speed * (budget / dist),
+
+ advl = vg_minf( mod, subl ),
+ advt = (advl / mod) * budget;
+
+ player->dist_accum += speed * advt;
+ player->rewind_time -= advl;
+ budget -= advt;
+ }
+
+ player->rewind_time = vg_maxf( 0.0f, player->rewind_time );
+
+ float current_time = vg.time - player->rewind_start,
+ remaining = player->rewind_predicted_time - current_time;
+
+ if( player->rewind_sound_wait ){
+ if( player->rewind_predicted_time >= 6.5f ){
+ if( remaining <= 6.5f ){
+ audio_lock();
+ audio_oneshot( &audio_rewind[3], 1.0f, 0.0f );
+ audio_unlock();
+ player->rewind_sound_wait = 0;
+ }
+ }
+ else if( player->rewind_predicted_time >= 2.5f ){
+ if( remaining <= 2.5f ){
+ audio_lock();
+ audio_oneshot( &audio_rewind[2], 1.0f, 0.0f );
+ audio_unlock();
+ player->rewind_sound_wait = 0;
+ }
+ }
+ else if( player->rewind_predicted_time >= 1.5f ){
+ if( remaining <= 1.5f ){
+ audio_lock();
+ audio_oneshot( &audio_rewind[1], 1.0f, 0.0f );
+ audio_unlock();
+ player->rewind_sound_wait = 0;
+ }
+ }
+ }
+
+ int i0 = floorf( player->rewind_time ),
+ i1 = VG_MIN( i0+1, player->rewind_length-1 );
+
+ struct rewind_frame *fr = &player->rewind_buffer[i0],
+ *fr1 = &player->rewind_buffer[i1];
+
+ float sub = vg_fractf(player->rewind_time);
+
+ v3_lerp( fr->pos, fr1->pos, sub, player->cam_override_pos );
+ player->cam_override_angles[0] =
+ vg_alerpf( fr->ang[0], fr1->ang[0], sub );
+ player->cam_override_angles[1] =
+ vg_lerpf ( fr->ang[1], fr1->ang[1], sub );
+
+ float blend = player->rewind_time * 0.25f;
+ player->cam_override_strength = vg_clampf( blend, 0.0f, 1.0f );
+ }
+ }
+ else player->cam_override_strength = 0.0f;
+
+ player__cam_iterate( player );
+}
+
+PLAYER_API void player__render( camera *cam, player_instance *player )
+{
+ shader_model_character_view_use();
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_2D, player->playermodel->texture );
+ shader_model_character_view_uTexMain( 0 );
+ shader_model_character_view_uCamera( cam->transform[3] );
+ shader_model_character_view_uPv( cam->mtx.pv );
+ shader_model_character_view_uTexSceneDepth( 1 );
+ render_fb_bind_texture( gpipeline.fb_main, 2, 1 );
+ v3f inverse;
+ render_fb_inverse_ratio( gpipeline.fb_main, inverse );
+ inverse[2] = main_camera.farz-main_camera.nearz;
+
+ shader_model_character_view_uInverseRatioDepth( inverse );
+ render_fb_inverse_ratio( NULL, inverse );
+ inverse[2] = cam->farz-cam->nearz;
+ shader_model_character_view_uInverseRatioMain( inverse );
+
+ world_instance *world = get_active_world();
+ world_link_lighting_ub( world, _shader_model_character_view.id );
+ world_bind_position_texture( world, _shader_model_character_view.id,
+ _uniform_model_character_view_g_world_depth, 2 );
+ world_bind_light_array( world, _shader_model_character_view.id,
+ _uniform_model_character_view_uLightsArray, 3 );
+ world_bind_light_index( world, _shader_model_character_view.id,
+ _uniform_model_character_view_uLightsIndex, 4 );
+
+ glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms,
+ player->playeravatar->sk.bone_count,
+ 0,
+ (float *)player->playeravatar->sk.final_mtx );
+
+ mesh_bind( &player->playermodel->mesh );
+ mesh_draw( &player->playermodel->mesh );
+
+ /* draw skateboard */
+ shader_model_board_view_use();
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_2D, player->playerboard->texture );
+ shader_model_board_view_uTexMain( 0 );
+ shader_model_board_view_uCamera( cam->transform[3] );
+ shader_model_board_view_uPv( cam->mtx.pv );
+ shader_model_board_view_uTexSceneDepth( 1 );
+
+ render_fb_inverse_ratio( gpipeline.fb_main, inverse );
+ inverse[2] = main_camera.farz-main_camera.nearz;
+
+ shader_model_board_view_uInverseRatioDepth( inverse );
+ render_fb_inverse_ratio( NULL, inverse );
+ inverse[2] = cam->farz-cam->nearz;
+ shader_model_board_view_uInverseRatioMain( inverse );
+
+ world_link_lighting_ub( world, _shader_model_board_view.id );
+ world_bind_position_texture( world, _shader_model_board_view.id,
+ _uniform_model_board_view_g_world_depth, 2 );
+ world_bind_light_array( world, _shader_model_board_view.id,
+ _uniform_model_board_view_uLightsArray, 3 );
+ world_bind_light_index( world, _shader_model_board_view.id,
+ _uniform_model_board_view_uLightsIndex, 4 );
+
+ m4x3f root;
+ m4x3_copy( player->playeravatar->sk.final_mtx[player->playeravatar->id_board]
+ , root );
+
+ struct player_board *board = player->playerboard;
+ mesh_bind( &board->mesh );
+
+ if( board->board.indice_count ){
+ m4x3f mlocal;
+ m3x3_identity( mlocal );
+ v3_copy( board->board_position, mlocal[3] );
+ m4x3_mul( root, mlocal, mlocal );
+
+ shader_model_board_view_uMdl( mlocal );
+ mdl_draw_submesh( &board->board );
+ }
+
+ for( int i=0; i<2; i++ ){
+ if( !board->trucks[i].indice_count )
+ continue;
+
+ m4x3f mlocal;
+ m3x3_identity( mlocal );
+ v3_copy( board->truck_positions[i], mlocal[3] );
+ m4x3_mul( root, mlocal, mlocal );
+
+ shader_model_board_view_uMdl( mlocal );
+ mdl_draw_submesh( &board->trucks[i] );
+ }
+
+ for( int i=0; i<4; i++ ){
+ if( !board->wheels[i].indice_count )
+ continue;
+
+ m4x3f mlocal;
+ m3x3_identity( mlocal );
+ v3_copy( board->wheel_positions[i], mlocal[3] );
+ m4x3_mul( root, mlocal, mlocal );
+
+ shader_model_board_view_uMdl( mlocal );
+ mdl_draw_submesh( &board->wheels[i] );
+ }
+}
+
+#endif /* PLAYER_RENDER_C */
--- /dev/null
+#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 */
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++ )
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;
}
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 );
--- /dev/null
+#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 */
*/
#define SR_NETWORKED
-//#define VG_DEVWINDOW
+#define VG_DEVWINDOW
#include "common.h"
#include "conf.h"
#include "steam.h"
#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"
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)
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 );
/* --------------------- */
/* load home world */
-#if 0
+#if 1
world_load( 0, "maps/mp_spawn.mdl" );
#else
world_load( 0, "maps/mp_mtzero.mdl" );
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;