From: hgn Date: Sun, 17 Jul 2022 04:46:44 +0000 (+0100) Subject: a lot X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=6d66c67945f84476d6ac75a0497007cc30bcf58c;hp=d8b8c566831e15ef061a66409e1219f44a82097a;p=carveJwlIkooP6JGAAIwe30JlM.git a lot --- diff --git a/blender_export.py b/blender_export.py index 16d1f38..05f687a 100644 --- a/blender_export.py +++ b/blender_export.py @@ -1,4 +1,5 @@ import bpy, math, gpu +import cProfile from ctypes import * from mathutils import * from gpu_extras.batch import batch_for_shader @@ -75,7 +76,8 @@ class mdl_header(Structure): class classtype_gate(Structure): _pack_ = 1 - _fields_ = [("target",c_uint32)] + _fields_ = [("target",c_uint32), + ("target1",c_uint32)] class classtype_block(Structure): _pack_ = 1 @@ -89,6 +91,11 @@ class classtype_water(Structure): _pack_ = 1 _fields_ = [("temp",c_uint32)] +class classtype_car_path(Structure): + _pack_ = 1 + _fields_ = [("target",c_uint32), + ("target1",c_uint32)] + # Exporter # ============================================================================== @@ -227,10 +234,11 @@ def write_model(name): block = classtype_block() block.bbx[0][0] = source.v0[0] block.bbx[0][1] = source.v0[2] - block.bbx[0][2] = -source.v0[1] + block.bbx[0][2] = -source.v1[1] + block.bbx[1][0] = source.v1[0] block.bbx[1][1] = source.v1[2] - block.bbx[1][2] = -source.v1[1] + block.bbx[1][2] = -source.v0[1] entdata_buffer += [block] elif classtype == 'k_classtype_spawn': @@ -238,6 +246,20 @@ def write_model(name): elif classtype == 'k_classtype_water': node.classtype = 4 + elif classtype == 'k_classtype_car_path': + node.classtype = 5 + entdata_length += sizeof( classtype_car_path ) + + pn = classtype_car_path() + pn.target = 0 + pn.target1 = 0 + + if obj.cv_data.target != None: + pn.target = obj.cv_data.target.cv_data.uid + if obj.cv_data.target1 != None: + pn.target1 = obj.cv_data.target1.cv_data.uid + + entdata_buffer += [pn] # Process meshes # @@ -296,11 +318,21 @@ def write_model(name): if data.vertex_colors: colour = data.vertex_colors.active.data[li].color - key = (round(co[0],4),round(co[1],4),round(co[2],4),\ - round(norm[0],4),round(norm[1],4),round(norm[2],4),\ - round(uv[0],4),round(uv[1],4),\ - round(colour[0],4),round(colour[1],4),\ - round(colour[2],4),round(colour[3],4)) + TOLERENCE = 4 + m = float(10**TOLERENCE) + + key = (int(co[0]*m+0.5),\ + int(co[1]*m+0.5),\ + int(co[2]*m+0.5),\ + int(norm[0]*m+0.5),\ + int(norm[1]*m+0.5),\ + int(norm[2]*m+0.5),\ + int(uv[0]*m+0.5),\ + int(uv[1]*m+0.5),\ + int(colour[0]*m+0.5),\ + int(colour[1]*m+0.5),\ + int(colour[2]*m+0.5),\ + int(colour[3]*m+0.5)) if key in boffa: indice_buffer += [boffa[key]] @@ -407,11 +439,34 @@ def cv_draw(): gpu.state.line_width_set(2.0) gpu.state.face_culling_set('BACK') gpu.state.depth_test_set('NONE') - gpu.state.blend_set('ADDITIVE') + gpu.state.blend_set('NONE') verts = [] colours = [] + def drawbezier(p0,h0,p1,h1,c0,c1): + nonlocal verts, colours + + verts += [p0] + verts += [h0] + colours += [(0.5,0.5,0.5,1.0),(0.5,0.5,0.5,1)] + verts += [p1] + verts += [h1] + colours += [(1.0,1.0,1,1),(1,1,1,1)] + + last = p0 + for i in range(10): + t = (i+1)/10 + a0 = 1-t + + tt = t*t + ttt = tt*t + p=ttt*p1+(3*tt-3*ttt)*h1+(3*ttt-6*tt+3*t)*h0+(3*tt-ttt-3*t+1)*p0 + verts += [(last[0],last[1],last[2])] + verts += [(p[0],p[1],p[2])] + colours += [c0*a0+c1*(1-a0),c0*a0+c1*(1-a0)] + last = p + for obj in bpy.context.collection.objects: if obj.cv_data.classtype == 'k_classtype_gate': if obj.cv_data.target != None: @@ -444,6 +499,45 @@ def cv_draw(): verts += [(v1[0],v1[1],v1[2])] colours += [(1,1,0,1),(1,1,0,1)] + elif obj.cv_data.classtype == 'k_classtype_spawn': + vs = [None]*4 + vs[0] = obj.matrix_world @ Vector((0,0,0)) + vs[1] = obj.matrix_world @ Vector((0,2,0)) + vs[2] = obj.matrix_world @ Vector((0.5,1,0)) + vs[3] = obj.matrix_world @ Vector((-0.5,1,0)) + indices = [(0,1),(1,2),(1,3)] + for l in indices: + v0 = vs[l[0]] + v1 = vs[l[1]] + verts += [(v0[0],v0[1],v0[2])] + verts += [(v1[0],v1[1],v1[2])] + colours += [(0,1,1,1),(0,1,1,1)] + + elif obj.cv_data.classtype == 'k_classtype_car_path': + p0 = obj.location + h0 = obj.matrix_world @ Vector((1,0,0)) + + v0 = obj.matrix_world.to_quaternion() @ Vector((1,0,0)) + c0 = Vector((v0.x*0.5+0.5, v0.y*0.5+0.5, 0.0, 1.0)) + + if obj.cv_data.target != None: + p1 = obj.cv_data.target.location + h1 = obj.cv_data.target.matrix_world @ Vector((-1,0,0)) + + v1 = obj.cv_data.target.matrix_world.to_quaternion()@Vector((1,0,0)) + c1 = Vector((v1.x*0.5+0.5, v1.y*0.5+0.5, 0.0, 1.0)) + + drawbezier( p0, h0, p1, h1, c0, c1 ) + + if obj.cv_data.target1 != None: + p1 = obj.cv_data.target1.location + h1 = obj.cv_data.target1.matrix_world @ Vector((-1,0,0)) + + v1 = obj.cv_data.target1.matrix_world.to_quaternion()@Vector((1,0,0)) + c1 = Vector((v1.x*0.5+0.5, v1.y*0.5+0.5, 0.0, 1.0)) + + drawbezier( p0, h0, p1, h1, c0, c1 ) + lines = batch_for_shader(\ cv_view_shader, 'LINES', \ { "pos":verts, "color":colours }) @@ -468,6 +562,8 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup): target: bpy.props.PointerProperty( type=bpy.types.Object, name="target", \ poll=cv_poll_target ) + target1: bpy.props.PointerProperty( type=bpy.types.Object, name="target1", \ + poll=cv_poll_target ) classtype: bpy.props.EnumProperty( name="Format", @@ -476,7 +572,8 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup): ('k_classtype_gate', "k_classtype_gate", "", 1), ('k_classtype_block', "k_classtype_block", "", 2), ('k_classtype_spawn', "k_classtype_spawn", "", 3), - ('k_classtype_water', "k_classtype_water", "", 4) + ('k_classtype_water', "k_classtype_water", "", 4), + ('k_classtype_car_path', "k_classtype_car_path", "", 5) ]) class CV_OBJ_PANEL(bpy.types.Panel): @@ -493,6 +590,9 @@ class CV_OBJ_PANEL(bpy.types.Panel): if active_object.cv_data.classtype == 'k_classtype_gate': _.layout.prop( active_object.cv_data, "target" ) + elif active_object.cv_data.classtype == 'k_classtype_car_path': + _.layout.prop( active_object.cv_data, "target" ) + _.layout.prop( active_object.cv_data, "target1" ) elif active_object.cv_data.classtype == 'k_classtype_block': mesh = active_object.data @@ -513,13 +613,19 @@ class CV_INTERFACE(bpy.types.Panel): layout = _.layout layout.operator( "carve.compile_all" ) +def test_compile(): + for col in bpy.data.collections["export"].children: + write_model( col.name ) + class CV_COMPILE(bpy.types.Operator): bl_idname="carve.compile_all" bl_label="Compile All" def execute(_,context): - for col in bpy.data.collections["export"].children: - write_model( col.name ) + test_compile() + #cProfile.runctx("test_compile()",globals(),locals(),sort=1) + #for col in bpy.data.collections["export"].children: + # write_model( col.name ) return {'FINISHED'} diff --git a/character.h b/character.h index 5ce456f..39ee472 100644 --- a/character.h +++ b/character.h @@ -441,11 +441,14 @@ void character_final_pose( struct character *ch, v3f cog, tilt = vg_clampf(cog[2], -1.0f, 1.0f) * 0.3f; v4f rz; m4x3f tr; - q_axis_angle( rz, (v3f){0.0f,0.0f,1.0f}, -cog[0]*0.6f ); + q_axis_angle( rz, (v3f){0.0f,0.0f,1.0f}, -cog[0]*0.3f ); q_m3x3( rz, tr ); - v3_copy( (v3f){0.0f,dip,tilt}, tr[3] ); + m3x3_identity( tr ); + //v3_copy( (v3f){0.0f,dip,tilt}, tr[3] ); + v3_copy( cog, tr[3] ); - m4x3_mulv( tr, pose->b0, npose.b0 ); + v3_muladd( pose->b0, tr[3], (v3f){0.85f,1.0f,1.0f}, npose.b0 ); + //m4x3_mulv( tr, pose->b0, npose.b0 ); m4x3_mulv( tr, pose->b1, npose.b1 ); m4x3_mulv( tr, pose->p, npose.p ); m4x3_mulv( tr, pose->pl, npose.pl ); diff --git a/common.h b/common.h index 2125154..2ee2d7c 100644 --- a/common.h +++ b/common.h @@ -15,7 +15,8 @@ enum classtype k_classtype_gate = 1, k_classtype_block = 2, k_classtype_spawn = 3, - k_classtype_water = 4 + k_classtype_water = 4, + k_classtype_car_path = 5 }; /* TODO: he needs a home somewhere */ diff --git a/main.c b/main.c index 84de410..ca2b997 100644 --- a/main.c +++ b/main.c @@ -90,7 +90,7 @@ static int playermodel( int argc, char const *argv[] ) void vg_start(void) { vg_convar_push( (struct vg_convar){ - .name = "freecam", + .name = "fc", .data = &freecam, .data_type = k_convar_dtype_i32, .opt_i32 = { .min=0, .max=1, .clamp=1 }, @@ -163,6 +163,8 @@ void vg_free(void) void vg_update(void) { player_update(); + world_update(); + //traffic_visualize( world.traffic, world.traffic_count ); } static void vg_framebuffer_resize( int w, int h ) diff --git a/model.h b/model.h index 4ed39d4..a65f11f 100644 --- a/model.h +++ b/model.h @@ -50,8 +50,9 @@ struct mdl_node v3f co; v4f q; v3f s; - - u32 submesh_start, + + union{ u32 submesh_start, sub_uid; }; + u32 submesh_count, classtype, offset, @@ -94,6 +95,11 @@ struct classtype_water u32 temp; }; +struct classtype_car_path +{ + u32 target, target1; +}; + #pragma pack(pop) /* @@ -361,9 +367,9 @@ static mdl_material *mdl_material_from_id( mdl_header *mdl, u32 id ) static void mdl_node_transform( mdl_node *pnode, m4x3f transform ) { q_m3x3( pnode->q, transform ); - transform[0][0] *= pnode->s[0]; - transform[1][1] *= pnode->s[1]; - transform[2][2] *= pnode->s[2]; + v3_muls( transform[0], pnode->s[0], transform[0] ); + v3_muls( transform[1], pnode->s[1], transform[1] ); + v3_muls( transform[2], pnode->s[2], transform[2] ); v3_copy( pnode->co, transform[3] ); } diff --git a/models/mp_dev.mdl b/models/mp_dev.mdl index bea2f18..84d6cc3 100644 Binary files a/models/mp_dev.mdl and b/models/mp_dev.mdl differ diff --git a/models/rs_cars.mdl b/models/rs_cars.mdl new file mode 100644 index 0000000..3b643c1 Binary files /dev/null and b/models/rs_cars.mdl differ diff --git a/models/rs_foliage.mdl b/models/rs_foliage.mdl index 43d9033..b65581b 100644 Binary files a/models/rs_foliage.mdl and b/models/rs_foliage.mdl differ diff --git a/player.h b/player.h index bd7304d..0e38d85 100644 --- a/player.h +++ b/player.h @@ -6,18 +6,43 @@ #include "character.h" #include "bvh.h" +/* + * Constants + */ + +static float + k_walkspeed = 2.0f, + k_board_radius = 0.25f, + k_board_length = 0.65f, + k_board_allowance = 0.04f, + k_friction_lat = 8.68f, + k_friction_resistance = 0.02f, + k_max_push_speed = 16.0f, + k_push_accel = 5.0f, + k_push_cycle_rate = 8.0f, + k_steer_ground = 2.5f, + k_steer_air = 3.6f, + k_steer_air_lerp = 0.3f, + k_downforce = 5.0f; + static int freecam = 0; -static float k_walkspeed = 2.0f; static int walk_grid_iterations = 1; static struct gplayer { /* Physics */ - v3f co, v, a, v_last, m, bob, vl; + v3f co, v, w, a, v_last, m, bob, vl; + + /* Utility */ + v3f up, right, forward; + v4f rot; float vswitch, slip, slip_last, reverse; + int rf, rb; + v3f ctf, ctb; + float iY; /* Yaw inertia */ int in_air, is_dead, on_board; @@ -50,10 +75,9 @@ player = .on_board = 1 }; -static float *player_cam_pos(void) -{ - return player.camera_pos; -} +/* + * Player API + */ static void player_transform_update(void) { @@ -62,67 +86,16 @@ static void player_transform_update(void) v3_copy( player.co, player.to_world[3] ); m4x3_invert_affine( player.to_world, player.to_local ); -} - -static int reset_player( int argc, char const *argv[] ) -{ - struct respawn_point *rp = NULL, *r; - - if( argc > 1 ) - { - for( int i=0; iname, argv[0] ) ) - { - rp = r; - break; - } - } - - if( !rp ) - vg_warn( "No spawn named '%s'\n", argv[0] ); - } - - if( !rp ) - { - float min_dist = INFINITY; - for( int i=0; ico, player.co ); - - if( d < min_dist ) - { - min_dist = d; - rp = r; - } - } - } - - if( !rp ) - { - vg_error( "No spawn found\n" ); - return 0; - } - - v4_copy( r->q, player.rot ); - v3_copy( r->co, player.co ); - - player.vswitch = 1.0f; - player.slip_last = 0.0f; - player.is_dead = 0; - player.in_air = 1; - m3x3_identity( player.vr ); - player.mdl.shoes[0] = 1; - player.mdl.shoes[1] = 1; - - player_transform_update(); - m3x3_mulv( player.to_world, (v3f){ 0.0f, 0.0f, -0.2f }, player.v ); - return 1; + m3x3_mulv( player.to_world, (v3f){1.0f,0.0f, 0.0f}, player.right ); + m3x3_mulv( player.to_world, (v3f){0.0f,1.0f, 0.0f}, player.up ); + m3x3_mulv( player.to_world, (v3f){0.0f,0.0f,-1.0f}, player.forward ); } +/* + * Free camera movement + */ + static void player_mouseview(void) { if( gui_want_mouse() ) @@ -176,6 +149,10 @@ static void player_freecam(void) v3_add( move_vel, player.camera_pos, player.camera_pos ); } +/* + * Player Physics Implementation + */ + static void apply_gravity( v3f vel, float const timestep ) { v3f gravity = { 0.0f, -9.6f, 0.0f }; @@ -186,9 +163,15 @@ static void apply_gravity( v3f vel, float const timestep ) * TODO: The angle bias should become greater when launching from a steeper * angle and skewed towords more 'downwards' angles when launching from * shallower trajectories + * + * it should also be tweaked by the controller left stick being pushed + * up or down */ static void player_start_air(void) { + if( player.in_air ) + return; + player.in_air = 1; float pstep = ktimestep*10.0f; @@ -198,9 +181,8 @@ static void player_start_air(void) float k_bias = 0.97f; - v3f axis, vup; - m3x3_mulv( player.to_world, (v3f){0.0f,1.0f,0.0f}, vup ); - v3_cross( vup, player.v, axis ); + v3f axis; + v3_cross( player.up, player.v, axis ); v3_normalize( axis ); player.land_log_count = 0; @@ -279,120 +261,32 @@ static void player_start_air(void) } } } - - //v3_rotate( player.v, best_velocity_mod, axis, player.v ); - - return; - v3_muls( player.v, best_velocity_mod, player.v ); } -static int sample_if_resistant( v3f pos ) -{ - v3f ground; - v3_copy( pos, ground ); - ground[1] += 4.0f; - - ray_hit hit; - hit.dist = INFINITY; - - if( ray_world( ground, (v3f){0.0f,-1.0f,0.0f}, &hit )) - { - v3f angle; - v3_copy( player.v, angle ); - v3_normalize( angle ); - float resistance = v3_dot( hit.normal, angle ); - - if( resistance < 0.25f ) - { - v3_copy( hit.pos, pos ); - return 1; - } - } - - return 0; -} - -static float stable_force( float current, float diff ) +static void draw_cross(v3f pos,u32 colour, float scale) { - float new = current + diff; - - if( new * current < 0.0f ) - return 0.0f; - - return new; + v3f p0, p1; + v3_add( (v3f){ scale,0.0f,0.0f}, pos, p0 ); + v3_add( (v3f){-scale,0.0f,0.0f}, pos, p1 ); + vg_line( p0, p1, colour ); + v3_add( (v3f){0.0f, scale,0.0f}, pos, p0 ); + v3_add( (v3f){0.0f,-scale,0.0f}, pos, p1 ); + vg_line( p0, p1, colour ); + v3_add( (v3f){0.0f,0.0f, scale}, pos, p0 ); + v3_add( (v3f){0.0f,0.0f,-scale}, pos, p1 ); + vg_line( p0, p1, colour ); } -static void player_physics_ground(void) +static void player_physics_control(void) { - /* - * Getting surface collision points, - * the contact manifold is a triangle for simplicity. + /* + * Computing localized friction forces for controlling the character + * Friction across X is significantly more than Z */ - v3f contact_front, contact_back, contact_norm, vup, vside, - axis; - - float klength = 0.65f; - m4x3_mulv( player.to_world, (v3f){ 0.15f,0.0f,-klength}, contact_norm ); - m4x3_mulv( player.to_world, (v3f){-0.15f,0.0f,-klength}, contact_front ); - m4x3_mulv( player.to_world, (v3f){ 0.00f,0.0f, klength}, contact_back ); - m3x3_mulv( player.to_world, (v3f){ 0.0f, 1.0f, 0.0f}, vup ); - m3x3_mulv( player.to_world, (v3f){ 1.0f, 0.0f, 0.0f}, vside ); - - v3f cn0, cn1, cn2; - - int contact_count = - sample_if_resistant( contact_front ) + - sample_if_resistant( contact_back ) + - sample_if_resistant( contact_norm ); - - if( contact_count < 3 ) - { - player_start_air(); - return; - } - - v3f norm; - v3f v0, v1; - v3_sub( contact_norm, contact_front, v0 ); - v3_sub( contact_back, contact_front, v1 ); - v3_cross( v1, v0, norm ); - v3_normalize( norm ); - - vg_line( contact_norm, contact_front, 0xff00ff00 ); - vg_line( contact_back, contact_front, 0xff0000ff ); - - /* Surface alignment */ - float angle = v3_dot( vup, norm ); - v3_cross( vup, norm, axis ); - - if( angle < 0.999f ) - { - v4f correction; - q_axis_angle( correction, axis, acosf(angle) ); - q_mul( correction, player.rot, player.rot ); - } - - float resistance = v3_dot( norm, player.v ); - if( resistance >= 0.0f ) - { - player_start_air(); - return; - } - else - { - v3_muladds( player.v, norm, -resistance, player.v ); - } - - /* This is where velocity integration used to be */ - - float slip = 0.0f; - - player.co[1] = (contact_front[1]+contact_back[1])*0.5f; v3f vel; m3x3_mulv( player.to_local, player.v, vel ); - - /* Calculate local forces */ + float slip = 0.0f; if( fabsf(vel[2]) > 0.01f ) slip = fabsf(-vel[0] / vel[2]) * vg_signf(vel[0]); @@ -408,9 +302,7 @@ static void player_physics_ground(void) for( int i=0; i<5; i++ ) { vel[2] = stable_force( vel[2], vg_signf( vel[2] ) * fwd_resistance ); - - /* This used to be -7.0, then -10.0 */ - vel[0] = stable_force( vel[0], vg_signf( vel[0] ) * -8.5f *substep ); + vel[0] = stable_force( vel[0], vg_signf( vel[0] ) * -8.78f *substep ); } static double start_push = 0.0; @@ -419,74 +311,32 @@ static void player_physics_ground(void) if( !vg_get_button("break") && vg_get_button( "push" ) ) { - float const k_maxpush = 16.0f, - k_pushaccel = 5.0f; - - float cycle_time = vg_time-start_push, - amt = k_pushaccel * (sinf( cycle_time * 8.0f )*0.5f+0.5f)*ktimestep, + float cycle_time = (vg_time-start_push)*k_push_cycle_rate, + amt = k_push_accel * (sinf(cycle_time)*0.5f+0.5f)*ktimestep, current = v3_length( vel ), - new_vel = vg_minf( current + amt, k_maxpush ); - new_vel -= vg_minf(current, k_maxpush); + new_vel = vg_minf( current + amt, k_max_push_speed ); + new_vel -= vg_minf(current, k_max_push_speed); vel[2] -= new_vel * player.reverse; } m3x3_mulv( player.to_world, vel, player.v ); - - if( vg_get_button( "yawl" ) ) - player.iY += 3.6f * ktimestep; - if( vg_get_button( "yawr" ) ) - player.iY -= 3.6f * ktimestep; float steer = vg_get_axis( "horizontal" ); - player.iY -= vg_signf(steer)*powf(steer,2.0f) * 2.5f * ktimestep; + player.iY -= vg_signf(steer)*powf(steer,2.0f) * k_steer_ground * ktimestep; - /* Too much lean and it starts to look like a snowboard here */ v2_lerp( player.board_xy, (v2f){ slip*0.25f, 0.0f }, ktimestep*5.0f, player.board_xy); } -static void draw_cross(v3f pos,u32 colour, float scale) -{ - v3f p0, p1; - v3_add( (v3f){ scale,0.0f,0.0f}, pos, p0 ); - v3_add( (v3f){-scale,0.0f,0.0f}, pos, p1 ); - vg_line( p0, p1, colour ); - v3_add( (v3f){0.0f, scale,0.0f}, pos, p0 ); - v3_add( (v3f){0.0f,-scale,0.0f}, pos, p1 ); - vg_line( p0, p1, colour ); - v3_add( (v3f){0.0f,0.0f, scale}, pos, p0 ); - v3_add( (v3f){0.0f,0.0f,-scale}, pos, p1 ); - vg_line( p0, p1, colour ); -} - -static void player_physics_air(void) +static void player_physics_control_air(void) { m3x3_mulv( player.vr, player.v, player.v ); - draw_cross( player.land_target, 0xff0000ff, 1 ); + draw_cross( player.land_target, 0xff0000ff, 0.25f ); - v3f ground_pos; - v3_copy( player.co, ground_pos ); - ground_pos[1] += 4.0f; - ray_hit hit; - hit.dist = INFINITY; - if( ray_world( ground_pos, (v3f){0.0f,-1.0f,0.0f}, &hit )) - { - if( hit.pos[1] > player.co[1] ) - { - player.in_air = 0; - - if( !ray_hit_is_ramp( &hit ) ) - { - player.is_dead = 1; - character_ragdoll_copypose( &player.mdl, player.v ); - } - return; - } - } - - /* Prediction + /* + * Prediction */ float pstep = ktimestep*10.0f; @@ -536,19 +386,19 @@ static void player_physics_air(void) q_mul( correction, player.rot, player.rot ); } - draw_cross( contact.pos, 0xffff0000, 1 ); + draw_cross( contact.pos, 0xffff0000, 0.25f ); break; } time_to_impact += pstep; } - player.iY -= vg_get_axis( "horizontal" ) * 3.6f * ktimestep; + player.iY -= vg_get_axis( "horizontal" ) * k_steer_air * ktimestep; { - float iX = vg_get_axis( "vertical" ) * - player.reverse * 3.6f * limiter * ktimestep; + player.reverse * k_steer_air * limiter * ktimestep; + static float siX = 0.0f; - siX = vg_lerpf( siX, iX, 0.3f ); + siX = vg_lerpf( siX, iX, k_steer_air_lerp ); v4f rotate; v3f vside; @@ -565,16 +415,160 @@ static void player_physics_air(void) v2_lerp( player.board_xy, target, ktimestep*3.0f, player.board_xy ); } +static void player_physics(void) +{ + m4x3f mboard; + v3_copy( player.to_world[0], mboard[0] ); + v3_copy( player.to_world[2], mboard[1] ); + v3_copy( player.to_world[1], mboard[2] ); + m4x3_mulv( player.to_world, (v3f){ 0.0f, 0.3f, 0.0f }, mboard[3] ); + + debug_capsule( mboard, k_board_length*2.0f, k_board_radius, 0xff0000ff ); + + boxf region = {{ -k_board_radius, -k_board_length, -k_board_radius }, + { k_board_radius, k_board_length, k_board_radius }}; + m4x3_transform_aabb( mboard, region ); + + u32 geo[256]; + v3f tri[3]; + int len = bh_select( &world.geo.bhtris, region, geo, 256 ); + + v3f poles[2]; + m4x3_mulv(mboard, (v3f){0.0f,-k_board_length+k_board_radius,0.0f}, poles[0]); + m4x3_mulv(mboard, (v3f){0.0f, k_board_length-k_board_radius,0.0f}, poles[1]); + + struct contact manifold[12]; + int manifold_count = 0; + + v3f surface_avg = {0.0f, 0.0f, 0.0f}; + + for( int i=0; i= vg_list_size(manifold)) + { + vg_error("Manifold overflow!\n"); + break; + } + + v3f p1; + v3_muladds( poles[j], norm, p, p1 ); + vg_line( poles[j], p1, 0xffffffff ); + + struct contact *ct = &manifold[manifold_count ++]; + v3_sub( co, player.co, ct->delta ); + v3_copy( co, ct->co ); + v3_copy( norm, ct->n ); + ct->bias = -0.2f*k_rb_rate*vg_minf(0.0f,-p+k_board_allowance); + ct->norm_impulse = 0.0f; + + v3_add( norm, surface_avg, surface_avg ); + } + } + } + + if( !manifold_count ) + { + player_start_air(); + } + else + { + v3_normalize( surface_avg ); + + if( v3_dot( player.v, surface_avg ) > 0.5f ) + { + player_start_air(); + } + else + player.in_air = 0; + } + + for( int j=0; j<10; j++ ) + { + for( int i=0; idelta, dv ); + v3_add( player.v, dv, dv ); + + float vn = -v3_dot( dv, ct->n ); + vn += ct->bias; + + float temp = ct->norm_impulse; + ct->norm_impulse = vg_maxf( temp + vn, 0.0f ); + vn = ct->norm_impulse - temp; + + v3f impulse; + + v3_muls( ct->n, vn, impulse ); + v3_add( impulse, player.v, player.v ); + + v3_cross( ct->delta, impulse, impulse ); + + /* + * W Impulses are limited to the Y and X axises, we don't really want + * roll angular velocities being included. + * + * Can also tweak the resistance of each axis here by scaling the wx,wy + * components. + */ + + float wy = v3_dot( player.up, impulse ), + wx = v3_dot( player.right, impulse ); + + v3_muladds( player.w, player.up, wy, player.w ); + v3_muladds( player.w, player.right, wx, player.w ); + } + } + + if( !player.in_air ) + { + v3f axis; + float angle = v3_dot( player.up, surface_avg ); + v3_cross( player.up, surface_avg, axis ); + + float cz = v3_dot( player.forward, axis ); + v3_muls( player.forward, cz, axis ); + + if( angle < 0.999f ) + { + v4f correction; + q_axis_angle( correction, axis, acosf(angle)*0.3f ); + q_mul( correction, player.rot, player.rot ); + } + + v3_muladds( player.v, player.up, -k_downforce*ktimestep, player.v ); + player_physics_control(); + } + else + { + player_physics_control_air(); + } +} + static void player_do_motion(void) { float horizontal = vg_get_axis("horizontal"), vertical = vg_get_axis("vertical"); - if( player.in_air ) - player_physics_air(); - - if( !player.in_air ) - player_physics_ground(); + player_physics(); /* Integrate velocity */ v3f prevco; @@ -583,22 +577,34 @@ static void player_do_motion(void) apply_gravity( player.v, ktimestep ); v3_muladds( player.co, player.v, ktimestep, player.co ); - /* Integrate inertia */ - v4f rotate; v3f vup = {0.0f,1.0f,0.0f}; - m3x3_mulv( player.to_world, vup, vup ); + /* Real angular velocity integration */ + v3_lerp( player.w, (v3f){0.0f,0.0f,0.0f}, 0.125f, player.w ); + if( v3_length2( player.w ) > 0.0f ) + { + v4f rotation; + v3f axis; + v3_copy( player.w, axis ); + + float mag = v3_length( axis ); + v3_divs( axis, mag, axis ); + q_axis_angle( rotation, axis, mag*k_rb_delta ); + q_mul( rotation, player.rot, player.rot ); + } - static float siY = 0.0f; + /* Faux angular velocity */ + v4f rotate; + static float siY = 0.0f; float lerpq = player.in_air? 0.04f: 0.3f; siY = vg_lerpf( siY, player.iY, lerpq ); - q_axis_angle( rotate, vup, siY ); + q_axis_angle( rotate, player.up, siY ); q_mul( rotate, player.rot, player.rot ); + player.iY = 0.0f; - player.iY = 0.0f; /* temp */ - - /* GATE COLLISION */ - + /* + * Gate intersection, by tracing a line over the gate planes + */ for( int i=0; i 0.0f? 1.0f: 0.0f, 0.04f ); - fdirx = vg_lerpf(fdirx, player.slip < 0.0f? 1.0f: 0.0f, 0.04f ); + fdirx = vg_lerpf(fdirx, player.slip < 0.0f? 1.0f: 0.0f, 0.01f ); ffly = vg_lerpf(ffly, player.in_air? 1.0f: 0.0f, 0.04f ); character_pose_reset( &player.mdl ); /* TODO */ - fstand = 1.0f; + float fstand1 = 1.0f-(1.0f-fstand)*0.3f; float amt_air = ffly*ffly, amt_ground = 1.0f-amt_air, amt_std = (1.0f-fslide) * amt_ground, - amt_stand = amt_std * fstand, - amt_aero = amt_std * (1.0f-fstand), + amt_stand = amt_std * fstand1, + amt_aero = amt_std * (1.0f-fstand1), amt_slide = amt_ground * fslide; character_final_pose( &player.mdl, offset, &pose_stand, amt_stand*fdirz ); @@ -1667,23 +1679,6 @@ static void player_animate(void) character_final_pose( &player.mdl, (v3f){0.0f,0.0f,0.0f}, &pose_fly, amt_air ); -#if 0 - static float fupper = 0.0f; - fupper = vg_lerpf( fupper, -vg_get_axis("horizontal")*0.2f, 0.1f ); - character_yaw_upper( &player.mdl, fupper ); -#endif - - /* Camera position */ - v3_lerp( player.smooth_localcam, player.mdl.cam_pos, 0.08f, - player.smooth_localcam ); - v3_muladds( player.smooth_localcam, offset, 0.7f, player.camera_pos ); - player.camera_pos[1] = vg_clampf( player.camera_pos[1], 0.3f, kheight ); - - m4x3_mulv( player.to_world, player.camera_pos, player.camera_pos ); - - player.air_blend = vg_lerpf( player.air_blend, player.in_air, 0.04f ); - v3_muladds( player.camera_pos, player.v, -0.05f*player.air_blend, - player.camera_pos ); /* * Additive effects @@ -1695,11 +1690,6 @@ static void player_animate(void) v3f localv; m3x3_mulv( player.to_local, player.v, localv ); -#if 0 - v3_muladds( arm_l->end, localv, -0.01f, arm_l->end ); - v3_muladds( arm_r->end, localv, -0.01f, arm_r->end ); -#endif - /* New board transformation */ v4f board_rotation; v3f board_location; @@ -1773,8 +1763,8 @@ static void player_animate(void) } } - v3_lerp( player.handl, player.handl_target, 0.1f, player.handl ); - v3_lerp( player.handr, player.handr_target, 0.1f, player.handr ); + v3_lerp( player.handl, player.handl_target, 1.0f, player.handl ); + v3_lerp( player.handr, player.handr_target, 1.0f, player.handr ); v3_copy( player.handl, player.mdl.ik_arm_l.end ); v3_copy( player.handr, player.mdl.ik_arm_r.end ); @@ -1788,277 +1778,81 @@ static void player_animate(void) player.mdl.rhead = rhead; } -static int giftwrapXZ( v3f *points, int *output, int len ) +static void player_camera_update(void) { - int l, p, q, count; - - if( len < 3 ) - return 0; - - l = 0; - for( int i=1; i= len ) - { - vg_error ("MANIFOLD ERR (%d)\n", count ); - return 0; - } - output[ count ++ ] = p; - - q = (p+1)%len; - - for( int i=0; i 0.0001f ) - { - q = i; - } - } - p = q; - } - while( p != l ); - - return count; + /* Update camera matrices */ + m4x3_identity( player.camera ); + m4x3_rotate_y( player.camera, -player.angles[0] ); + m4x3_rotate_x( player.camera, -player.angles[1] ); + v3_copy( player.camera_pos, player.camera[3] ); + m4x3_invert_affine( player.camera, player.camera_inverse ); } - -static void player_do_collision( rigidbody *rb ) -{ - /* - * If point is inside box - * find normal (theres 8 simple pyramid regions for this, x>y/dim .. etc) - * find distance (same sorta thing) - * - * apply normal impulse to rotation - * correct position based on new penetration amount if needed - * apply normal impulse to velocity - */ - - v3f pfront, pback; - m4x3_mulv( player.to_world, (v3f){ 0.0f,0.0f,-1.0f }, pfront ); - m4x3_mulv( player.to_world, (v3f){ 0.0f,0.0f, 1.0f }, pback ); - - float const kheight = 2.0f; - - v3f verts[8]; - - v3f a, b; - v3_copy( rb->bbx[0], a ); - v3_copy( rb->bbx[1], b ); - - m4x3f compound; - m4x3_mul( player.to_local, rb->to_world, compound ); - - m4x3_mulv( compound, (v3f){ a[0], a[1], a[2] }, verts[0] ); - m4x3_mulv( compound, (v3f){ a[0], b[1], a[2] }, verts[1] ); - m4x3_mulv( compound, (v3f){ b[0], b[1], a[2] }, verts[2] ); - m4x3_mulv( compound, (v3f){ b[0], a[1], a[2] }, verts[3] ); - m4x3_mulv( compound, (v3f){ a[0], a[1], b[2] }, verts[4] ); - m4x3_mulv( compound, (v3f){ a[0], b[1], b[2] }, verts[5] ); - m4x3_mulv( compound, (v3f){ b[0], b[1], b[2] }, verts[6] ); - m4x3_mulv( compound, (v3f){ b[0], a[1], b[2] }, verts[7] ); - - int const indices[12][2] = { - {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4}, - {0,4},{1,5},{2,6},{3,7} - }; - - v3f hull[12*2 + 8]; - int hull_indices[12*2 + 8]; - int hull_len = 0; - - for( int i=0; i<8; i++ ) - { - int ia = indices[i][0]; - float ya = verts[ia][1]; - - if( ya > 0.2f && ya < kheight ) - { - int add_point = 1; - for( int j=0; j 14.0f ) - { - player.is_dead = 1; - character_ragdoll_copypose( &player.mdl, player.v ); - return; - } + float yaw = atan2f( player.vl[0], -player.vl[2] ), + pitch = atan2f( -player.vl[1], + sqrtf( + player.vl[0]*player.vl[0] + player.vl[2]*player.vl[2] + )) * 0.7f; - if( vn > 0.0f ) - { - v2_muls( normal, min_dist, impulse ); - float rotation = v2_cross( point, impulse )*0.08f; - v4f rot; - v3f up = {0.0f,1.0f,0.0f}; - m3x3_mulv( player.to_world, up, up ); - q_axis_angle( rot, up, -rotation ); - q_mul( rot, player.rot, player.rot ); - } + player.angles[0] = yaw; + player.angles[1] = pitch + 0.30f; - v2_muls( normal, vn*0.03f, impulse ); - v3f impulse_world = { impulse[0], 0.0f, impulse[1] }; + /* Camera shake */ + static v2f shake_damp = {0.0f,0.0f}; + v2f shake = { vg_randf()-0.5f, vg_randf()-0.5f }; + v2_muls( shake, v3_length(player.v)*0.3f *(1.0f+fabsf(player.slip)), shake); + v2_lerp( shake_damp, shake, 0.01f, shake_damp ); + shake_damp[0] *= 0.2f; - m3x3_mulv( player.to_world, impulse_world, impulse_world ); - v3_add( impulse_world, player.v, player.v ); - } - } + v2_muladds( player.angles, shake_damp, 0.1f, player.angles ); } +/* + * Audio + */ static void player_audio(void) { float speed = vg_minf(v3_length( player.v )*0.1f,1.0f), @@ -2104,10 +1898,84 @@ static void player_audio(void) } } +/* + * Public Endpoints + */ +static float *player_cam_pos(void) +{ + return player.camera_pos; +} + +static int reset_player( int argc, char const *argv[] ) +{ + struct respawn_point *rp = NULL, *r; + + if( argc == 1 ) + { + for( int i=0; iname, argv[0] ) ) + { + rp = r; + break; + } + } + + if( !rp ) + vg_warn( "No spawn named '%s'\n", argv[0] ); + } + + if( !rp ) + { + float min_dist = INFINITY; + + vg_info( "%f %f %f\n", player.co[0], player.co[1], player.co[2] ); + for( int i=0; ico, player.co ); + + vg_info( "Dist %s : %f\n", r->name, d ); + if( d < min_dist ) + { + min_dist = d; + rp = r; + } + } + } + + if( !rp ) + { + vg_error( "No spawn found\n" ); + if( !world.spawn_count ) + return 0; + + rp = &world.spawns[0]; + } + + v4_copy( rp->q, player.rot ); + v3_copy( rp->co, player.co ); + + player.vswitch = 1.0f; + player.slip_last = 0.0f; + player.is_dead = 0; + player.in_air = 1; + m3x3_identity( player.vr ); + + player.mdl.shoes[0] = 1; + player.mdl.shoes[1] = 1; + + player_transform_update(); + m3x3_mulv( player.to_world, (v3f){ 0.0f, 0.0f, -1.2f }, player.v ); + return 1; +} + static void player_update(void) { for( int i=0; i0.0f) reset_player(0,NULL); @@ -2117,91 +1985,35 @@ static void player_update(void) player.on_board ^= 0x1; } - if( freecam ) + if( player.is_dead ) { - player_freecam(); + character_ragdoll_iter( &player.mdl ); + character_debug_ragdoll( &player.mdl ); + + if( !freecam ) + player_animate_death_cam(); } else { - if( player.is_dead ) + if( player.on_board ) { - /* - * Follow camera - */ - character_ragdoll_iter( &player.mdl ); - character_debug_ragdoll( &player.mdl ); - - v3f delta; - v3f head_pos; - v3_copy( player.mdl.ragdoll[k_chpart_head].co, head_pos ); - - v3_sub( head_pos, player.camera_pos, delta ); - v3_normalize( delta ); - - v3f follow_pos; - v3_muladds( head_pos, delta, -2.5f, follow_pos ); - v3_lerp( player.camera_pos, follow_pos, 0.1f, player.camera_pos ); - - /* - * Make sure the camera stays above the ground - */ - v3f min_height = {0.0f,1.0f,0.0f}; + player_do_motion(); + player_animate(); - v3f sample; - v3_add( player.camera_pos, min_height, sample ); - ray_hit hit; - hit.dist = min_height[1]*2.0f; - - if( ray_world( sample, (v3f){0.0f,-1.0f,0.0f}, &hit )) - v3_add( hit.pos, min_height, player.camera_pos ); - - player.camera_pos[1] = - vg_maxf( wrender.height + 2.0f, player.camera_pos[1] ); - - player.angles[0] = atan2f( delta[0], -delta[2] ); - player.angles[1] = -asinf( delta[1] ); + if( !freecam ) + player_animate_camera(); } else { - if( player.on_board ) - { - bh_debug_node(&world.bhcubes, 0, - player.camera_pos, 0xff80ff00 ); - - u32 colliders[16]; - boxf wbox = {{ -2.0f, -2.0f, -2.0f }, - { 2.0f, 2.0f, 2.0f }}; - m4x3_transform_aabb( player.to_world, wbox ); - int len = bh_select( &world.bhcubes, wbox, colliders, 32 ); - - for( int i=0; ico, rb->v, k_rb_delta, rb->co ); - v3_lerp( rb->I, (v3f){0.0f,0.0f,0.0f}, 0.0025f, rb->I ); /* inegrate inertia */ @@ -405,44 +415,7 @@ static void rb_constraint_position( rigidbody *ra, v3f lca, static void rb_debug( rigidbody *rb, u32 colour ) { v3f *box = rb->bbx; - v3f p000, p001, p010, p011, p100, p101, p110, p111; - - p000[0]=box[0][0];p000[1]=box[0][1];p000[2]=box[0][2]; - p001[0]=box[0][0];p001[1]=box[0][1];p001[2]=box[1][2]; - p010[0]=box[0][0];p010[1]=box[1][1];p010[2]=box[0][2]; - p011[0]=box[0][0];p011[1]=box[1][1];p011[2]=box[1][2]; - - p100[0]=box[1][0];p100[1]=box[0][1];p100[2]=box[0][2]; - p101[0]=box[1][0];p101[1]=box[0][1];p101[2]=box[1][2]; - p110[0]=box[1][0];p110[1]=box[1][1];p110[2]=box[0][2]; - p111[0]=box[1][0];p111[1]=box[1][1];p111[2]=box[1][2]; - - m4x3_mulv( rb->to_world, p000, p000 ); - m4x3_mulv( rb->to_world, p001, p001 ); - m4x3_mulv( rb->to_world, p010, p010 ); - m4x3_mulv( rb->to_world, p011, p011 ); - m4x3_mulv( rb->to_world, p100, p100 ); - m4x3_mulv( rb->to_world, p101, p101 ); - m4x3_mulv( rb->to_world, p110, p110 ); - m4x3_mulv( rb->to_world, p111, p111 ); - - vg_line( p000, p001, colour ); - vg_line( p001, p011, colour ); - vg_line( p011, p010, colour ); - vg_line( p010, p000, colour ); - - vg_line( p100, p101, colour ); - vg_line( p101, p111, colour ); - vg_line( p111, p110, colour ); - vg_line( p110, p100, colour ); - - vg_line( p100, p000, colour ); - vg_line( p101, p001, colour ); - vg_line( p110, p010, colour ); - vg_line( p111, p011, colour ); - - vg_line( p000, p110, colour ); - vg_line( p100, p010, colour ); + vg_line_boxf_transformed( rb->to_world, rb->bbx, colour ); } /* @@ -511,6 +484,8 @@ static void rb_build_manifold_rb_static( rigidbody *ra, rigidbody *rb_static ) m4x3_mulv( ra->to_world, (v3f){ b[0], b[1], b[2] }, verts[6] ); m4x3_mulv( ra->to_world, (v3f){ b[0], a[1], b[2] }, verts[7] ); + vg_line_boxf_transformed( rb_static->to_world, rb_static->bbx, 0xff0000ff ); + int count = 0; for( int i=0; i<8; i++ ) @@ -546,6 +521,267 @@ static void rb_build_manifold_rb_static( rigidbody *ra, rigidbody *rb_static ) } } +/* + * Capsule phyics + */ + +static float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2, + float *s, float *t, v3f c1, v3f c2) +{ + v3f d1,d2,r; + v3_sub( q1, p1, d1 ); + v3_sub( q2, p2, d2 ); + v3_sub( p1, p2, r ); + + float a = v3_length2( d1 ), + e = v3_length2( d2 ), + f = v3_dot( d2, r ); + + const float kEpsilon = 0.0001f; + + if( a <= kEpsilon && e <= kEpsilon ) + { + *s = 0.0f; + *t = 0.0f; + v3_copy( p1, c1 ); + v3_copy( p2, c2 ); + + v3f v0; + v3_sub( c1, c2, v0 ); + + return v3_length2( v0 ); + } + + if( a<= kEpsilon ) + { + *s = 0.0f; + *t = vg_clampf( f / e, 0.0f, 1.0f ); + } + else + { + float c = v3_dot( d1, r ); + if( e <= kEpsilon ) + { + *t = 0.0f; + *s = vg_clampf( -c / a, 0.0f, 1.0f ); + } + else + { + float b = v3_dot(d1,d2), + d = a*e-b*b; + + if( d != 0.0f ) + { + *s = vg_clampf((b*f - c*e)/d, 0.0f, 1.0f); + } + else + { + *s = 0.0f; + } + + *t = (b*(*s)+f) / e; + + if( *t < 0.0f ) + { + *t = 0.0f; + *s = vg_clampf( -c / a, 0.0f, 1.0f ); + } + else if( *t > 1.0f ) + { + *t = 1.0f; + *s = vg_clampf((b-c)/a,0.0f,1.0f); + } + } + } + + v3_muladds( p1, d1, *s, c1 ); + v3_muladds( p2, d2, *t, c2 ); + + v3f v0; + v3_sub( c1, c2, v0 ); + return v3_length2( v0 ); +} + +static void closest_point_segment( v3f a, v3f b, v3f point, v3f dest ) +{ + v3f v0, v1; + v3_sub( b, a, v0 ); + v3_sub( point, a, v1 ); + + float t = v3_dot( v1, v0 ) / v3_length2(v0); + v3_muladds( a, v0, vg_clampf(t,0.0f,1.0f), dest ); +} + +/* Real-Time Collision Detection */ +static void closest_on_triangle( v3f p, v3f tri[3], v3f dest ) +{ + v3f ab, ac, ap; + float d1, d2; + + /* Region outside A */ + v3_sub( tri[1], tri[0], ab ); + v3_sub( tri[2], tri[0], ac ); + v3_sub( p, tri[0], ap ); + + d1 = v3_dot(ab,ap); + d2 = v3_dot(ac,ap); + if( d1 <= 0.0f && d2 <= 0.0f ) + { + v3_copy( tri[0], dest ); + v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); + return; + } + + /* Region outside B */ + v3f bp; + float d3, d4; + + v3_sub( p, tri[1], bp ); + d3 = v3_dot( ab, bp ); + d4 = v3_dot( ac, bp ); + + if( d3 >= 0.0f && d4 <= d3 ) + { + v3_copy( tri[1], dest ); + v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); + return; + } + + /* Edge region of AB */ + float vc = d1*d4 - d3*d2; + if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f ) + { + float v = d1 / (d1-d3); + v3_muladds( tri[0], ab, v, dest ); + v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); + return; + } + + /* Region outside C */ + v3f cp; + float d5, d6; + v3_sub( p, tri[2], cp ); + d5 = v3_dot(ab, cp); + d6 = v3_dot(ac, cp); + + if( d6 >= 0.0f && d5 <= d6 ) + { + v3_copy( tri[2], dest ); + v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); + return; + } + + /* Region of AC */ + float vb = d5*d2 - d1*d6; + if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f ) + { + float w = d2 / (d2-d6); + v3_muladds( tri[0], ac, w, dest ); + v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); + return; + } + + /* Region of BC */ + float va = d3*d6 - d5*d4; + if( va <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f ) + { + float w = (d4-d3) / ((d4-d3) + (d5-d6)); + v3f bc; + v3_sub( tri[2], tri[1], bc ); + v3_muladds( tri[1], bc, w, dest ); + v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); + return; + } + + /* P inside region, Q via barycentric coordinates uvw */ + float d = 1.0f/(va+vb+vc), + v = vb*d, + w = vc*d; + + v3_muladds( tri[0], ab, v, dest ); + v3_muladds( dest, ac, w, dest ); +} + +static int sphere_vs_triangle( v3f c, float r, v3f tri[3], + v3f co, v3f norm, float *p ) +{ + v3f delta; + closest_on_triangle( c, tri, co ); + + v3_sub( c, co, delta ); + + + float d = v3_length2( delta ); + if( d < r*r ) + { + v3f ab, ac, tn; + v3_sub( tri[1], tri[0], ab ); + v3_sub( tri[2], tri[0], ac ); + v3_cross( ac, ab, tn ); + + if( v3_dot( delta, tn ) > 0.0f ) + v3_muls( delta, -1.0f, delta ); + + vg_line_pt3( co, 0.05f, 0xff00ff00 ); + + d = sqrtf(d); + v3_muls( delta, 1.0f/d, norm ); + + *p = r-d; + return 1; + } + + return 0; +} + +static void debug_capsule( m4x3f m, float height, float radius, u32 colour ) +{ + v3f last = { 0.0f, 0.0f, radius }; + m4x3f lower, upper; + m3x3_copy( m, lower ); + m3x3_copy( m, upper ); + m4x3_mulv( m, (v3f){0.0f,-height*0.5f+radius,0.0f}, lower[3] ); + m4x3_mulv( m, (v3f){0.0f, height*0.5f-radius,0.0f}, upper[3] ); + + for( int i=0; i<16; i++ ) + { + float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f, + s = sinf(t), + c = cosf(t); + + v3f p = { s*radius, 0.0f, c*radius }; + + v3f p0, p1; + m4x3_mulv( lower, p, p0 ); + m4x3_mulv( lower, last, p1 ); + vg_line( p0, p1, colour ); + + m4x3_mulv( upper, p, p0 ); + m4x3_mulv( upper, last, p1 ); + vg_line( p0, p1, colour ); + + v3_copy( p, last ); + } + + for( int i=0; i<4; i++ ) + { + float t = ((float)(i) * (1.0f/4.0f)) * VG_PIf * 2.0f, + s = sinf(t), + c = cosf(t); + + v3f p = { s*radius, 0.0f, c*radius }; + + v3f p0, p1; + m4x3_mulv( lower, p, p0 ); + m4x3_mulv( upper, p, p1 ); + vg_line( p0, p1, colour ); + + m4x3_mulv( lower, (v3f){0.0f,-radius,0.0f}, p0 ); + m4x3_mulv( upper, (v3f){0.0f, radius,0.0f}, p1 ); + vg_line( p0, p1, colour ); + } +} + /* * BVH implementation, this is ONLY for static rigidbodies, its to slow for * realtime use. diff --git a/shaders/character.fs b/shaders/character.fs index cf62679..2b13d76 100644 --- a/shaders/character.fs +++ b/shaders/character.fs @@ -8,6 +8,7 @@ in vec4 aColour; in vec2 aUv; in vec3 aNorm; in vec3 aCo; +in vec3 aWorldCo; in float aOpacity; #include "common_world.glsl" @@ -17,7 +18,7 @@ void main() vec3 vfrag = texture( uTexMain, aUv ).rgb; // Lighting - vec3 halfview = uCamera - aCo; + vec3 halfview = uCamera - aWorldCo; float fdist = length( halfview ); halfview /= fdist; diff --git a/shaders/character.h b/shaders/character.h index 83fdff3..e592a94 100644 --- a/shaders/character.h +++ b/shaders/character.h @@ -24,6 +24,7 @@ static struct vg_shader _shader_character = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "out float aOpacity;\n" "\n" "void main()\n" @@ -35,7 +36,8 @@ static struct vg_shader _shader_character = { " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" -" aCo = world_pos;\n" +" aWorldCo = world_pos;\n" +" aCo = a_co;\n" " aOpacity = max(clip_pos.w*3.0,0.1);// 1.0-(gl_Position.y+0.5)*uOpacity;\n" "}\n" ""}, @@ -53,6 +55,7 @@ static struct vg_shader _shader_character = { "in vec2 aUv;\n" "in vec3 aNorm;\n" "in vec3 aCo;\n" +"in vec3 aWorldCo;\n" "in float aOpacity;\n" "\n" "#line 1 1 \n" @@ -108,7 +111,7 @@ static struct vg_shader _shader_character = { "\n" "float shadow_sample( vec3 vdir )\n" "{\n" -" vec3 sample_pos = aCo + vdir;\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" @@ -153,14 +156,14 @@ static struct vg_shader _shader_character = { " return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n" "}\n" "\n" -"#line 14 0 \n" +"#line 15 0 \n" "\n" "void main()\n" "{\n" " vec3 vfrag = texture( uTexMain, aUv ).rgb;\n" "\n" " // Lighting\n" -" vec3 halfview = uCamera - aCo;\n" +" vec3 halfview = uCamera - aWorldCo;\n" " float fdist = length( halfview );\n" " halfview /= fdist;\n" "\n" diff --git a/shaders/character.vs b/shaders/character.vs index 997ecc5..6d90ce6 100644 --- a/shaders/character.vs +++ b/shaders/character.vs @@ -8,6 +8,7 @@ out vec4 aColour; out vec2 aUv; out vec3 aNorm; out vec3 aCo; +out vec3 aWorldCo; out float aOpacity; void main() @@ -19,6 +20,7 @@ void main() aColour = a_colour; aUv = a_uv; aNorm = mat3(uMdl) * a_norm; - aCo = world_pos; + aWorldCo = world_pos; + aCo = a_co; aOpacity = max(clip_pos.w*3.0,0.1);// 1.0-(gl_Position.y+0.5)*uOpacity; } diff --git a/shaders/common_world.glsl b/shaders/common_world.glsl index 4d9b0d3..5e1a891 100644 --- a/shaders/common_world.glsl +++ b/shaders/common_world.glsl @@ -50,7 +50,7 @@ float world_depth_sample( vec3 pos ) float shadow_sample( vec3 vdir ) { - vec3 sample_pos = aCo + vdir; + vec3 sample_pos = aWorldCo + vdir; float height_sample = world_depth_sample( sample_pos ); float fdelta = height_sample - sample_pos.y; diff --git a/shaders/gpos.fs b/shaders/gpos.fs index b21f7a7..77dac50 100644 --- a/shaders/gpos.fs +++ b/shaders/gpos.fs @@ -6,6 +6,7 @@ in vec4 aColour; in vec2 aUv; in vec3 aNorm; in vec3 aCo; +in vec3 aWorldCo; #include "common_world.glsl" diff --git a/shaders/gpos.h b/shaders/gpos.h index 4e44e35..d140abb 100644 --- a/shaders/gpos.h +++ b/shaders/gpos.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_gpos = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = @@ -45,6 +48,7 @@ static struct vg_shader _shader_gpos = { "in vec2 aUv;\n" "in vec3 aNorm;\n" "in vec3 aCo;\n" +"in vec3 aWorldCo;\n" "\n" "#line 1 1 \n" "layout (std140) uniform ub_world_lighting\n" @@ -99,7 +103,7 @@ static struct vg_shader _shader_gpos = { "\n" "float shadow_sample( vec3 vdir )\n" "{\n" -" vec3 sample_pos = aCo + vdir;\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" @@ -144,7 +148,7 @@ static struct vg_shader _shader_gpos = { " return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n" "}\n" "\n" -"#line 11 0 \n" +"#line 12 0 \n" "\n" "// Water blending\n" "// ==============\n" diff --git a/shaders/planeinf.h b/shaders/planeinf.h index d2a227a..abd7a0c 100644 --- a/shaders/planeinf.h +++ b/shaders/planeinf.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_planeinf = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = diff --git a/shaders/sky.h b/shaders/sky.h index 3ef9613..09329f5 100644 --- a/shaders/sky.h +++ b/shaders/sky.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_sky = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = diff --git a/shaders/standard.h b/shaders/standard.h index 59aa1d9..1b41b9a 100644 --- a/shaders/standard.h +++ b/shaders/standard.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_standard = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = diff --git a/shaders/standard.vs b/shaders/standard.vs index db7f980..ac062ae 100644 --- a/shaders/standard.vs +++ b/shaders/standard.vs @@ -7,12 +7,15 @@ out vec4 aColour; out vec2 aUv; out vec3 aNorm; out vec3 aCo; +out vec3 aWorldCo; void main() { - gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 ); + vec3 world_pos = uMdl * vec4(a_co,1.0); + gl_Position = uPv * vec4( world_pos, 1.0 ); aColour = a_colour; aUv = a_uv; aNorm = mat3(uMdl) * a_norm; aCo = a_co; + aWorldCo = world_pos; } diff --git a/shaders/terrain.fs b/shaders/terrain.fs index 456d08e..de8958d 100644 --- a/shaders/terrain.fs +++ b/shaders/terrain.fs @@ -8,6 +8,7 @@ in vec4 aColour; in vec2 aUv; in vec3 aNorm; in vec3 aCo; +in vec3 aWorldCo; #include "common_world.glsl" diff --git a/shaders/terrain.h b/shaders/terrain.h index 436ca1f..1c87e35 100644 --- a/shaders/terrain.h +++ b/shaders/terrain.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_terrain = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = @@ -47,6 +50,7 @@ static struct vg_shader _shader_terrain = { "in vec2 aUv;\n" "in vec3 aNorm;\n" "in vec3 aCo;\n" +"in vec3 aWorldCo;\n" "\n" "#line 1 1 \n" "layout (std140) uniform ub_world_lighting\n" @@ -101,7 +105,7 @@ static struct vg_shader _shader_terrain = { "\n" "float shadow_sample( vec3 vdir )\n" "{\n" -" vec3 sample_pos = aCo + vdir;\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" @@ -146,7 +150,7 @@ static struct vg_shader _shader_terrain = { " return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n" "}\n" "\n" -"#line 13 0 \n" +"#line 14 0 \n" "\n" "void main()\n" "{\n" diff --git a/shaders/unlit.h b/shaders/unlit.h index afba67c..8fbf00b 100644 --- a/shaders/unlit.h +++ b/shaders/unlit.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_unlit = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = diff --git a/shaders/vblend.fs b/shaders/vblend.fs index 0849e69..023721e 100644 --- a/shaders/vblend.fs +++ b/shaders/vblend.fs @@ -9,6 +9,7 @@ in vec4 aColour; in vec2 aUv; in vec3 aNorm; in vec3 aCo; +in vec3 aWorldCo; #include "common_world.glsl" @@ -43,7 +44,7 @@ void main() } // Lighting - vec3 halfview = uCamera - aCo; + vec3 halfview = uCamera - aWorldCo; float fdist = length( halfview ); halfview /= fdist; diff --git a/shaders/vblend.h b/shaders/vblend.h index 45782ad..3f5bfdc 100644 --- a/shaders/vblend.h +++ b/shaders/vblend.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_vblend = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = @@ -48,6 +51,7 @@ static struct vg_shader _shader_vblend = { "in vec2 aUv;\n" "in vec3 aNorm;\n" "in vec3 aCo;\n" +"in vec3 aWorldCo;\n" "\n" "#line 1 1 \n" "layout (std140) uniform ub_world_lighting\n" @@ -102,7 +106,7 @@ static struct vg_shader _shader_vblend = { "\n" "float shadow_sample( vec3 vdir )\n" "{\n" -" vec3 sample_pos = aCo + vdir;\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" @@ -147,7 +151,7 @@ static struct vg_shader _shader_vblend = { " return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n" "}\n" "\n" -"#line 14 0 \n" +"#line 15 0 \n" "\n" "void main()\n" "{\n" @@ -180,7 +184,7 @@ static struct vg_shader _shader_vblend = { " }\n" "\n" " // Lighting\n" -" vec3 halfview = uCamera - aCo;\n" +" vec3 halfview = uCamera - aWorldCo;\n" " float fdist = length( halfview );\n" " halfview /= fdist;\n" "\n" diff --git a/shaders/water.fs b/shaders/water.fs index 0be4389..9f9e8be 100644 --- a/shaders/water.fs +++ b/shaders/water.fs @@ -13,6 +13,7 @@ in vec4 aColour; in vec2 aUv; in vec3 aNorm; in vec3 aCo; +in vec3 aWorldCo; #include "common_world.glsl" diff --git a/shaders/water.h b/shaders/water.h index 2cdc271..8a1d4df 100644 --- a/shaders/water.h +++ b/shaders/water.h @@ -23,14 +23,17 @@ static struct vg_shader _shader_water = { "out vec2 aUv;\n" "out vec3 aNorm;\n" "out vec3 aCo;\n" +"out vec3 aWorldCo;\n" "\n" "void main()\n" "{\n" -" gl_Position = uPv * vec4( uMdl * vec4(a_co,1.0), 1.0 );\n" +" vec3 world_pos = uMdl * vec4(a_co,1.0);\n" +" gl_Position = uPv * vec4( world_pos, 1.0 );\n" " aColour = a_colour;\n" " aUv = a_uv;\n" " aNorm = mat3(uMdl) * a_norm;\n" " aCo = a_co;\n" +" aWorldCo = world_pos;\n" "}\n" ""}, .fs = @@ -52,6 +55,7 @@ static struct vg_shader _shader_water = { "in vec2 aUv;\n" "in vec3 aNorm;\n" "in vec3 aCo;\n" +"in vec3 aWorldCo;\n" "\n" "#line 1 1 \n" "layout (std140) uniform ub_world_lighting\n" @@ -106,7 +110,7 @@ static struct vg_shader _shader_water = { "\n" "float shadow_sample( vec3 vdir )\n" "{\n" -" vec3 sample_pos = aCo + vdir;\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" @@ -151,7 +155,7 @@ static struct vg_shader _shader_water = { " return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n" "}\n" "\n" -"#line 18 0 \n" +"#line 19 0 \n" "\n" "vec4 water_surf( vec3 halfview, vec3 vnorm, float depthvalue, \n" " vec4 beneath, vec4 above )\n" diff --git a/traffic.h b/traffic.h new file mode 100644 index 0000000..8850306 --- /dev/null +++ b/traffic.h @@ -0,0 +1,232 @@ +#ifndef TRAFFIC_H +#define TRAFFIC_H + +#include "common.h" +#include "model.h" +#include "rigidbody.h" + +typedef struct traffic_node traffic_node; +typedef struct traffic_driver traffic_driver; + +struct traffic_node +{ + v3f co, h; + + union + { + struct{ traffic_node *next, *next1; }; + struct{ mdl_node *mn_next, *mn_next1; }; + }; +}; + +struct traffic_driver +{ + m4x3f transform; + + traffic_node *current; + int option; + float t, speed; +}; + +static void eval_bezier_time( v3f p0, v3f p1, v3f h0, v3f h1, float t, v3f p ) +{ + float tt = t*t, + ttt = tt*t; + + v3_muls( p1, ttt, p ); + v3_muladds( p, h1, 3.0f*tt -3.0f*ttt, p ); + v3_muladds( p, h0, 3.0f*ttt -6.0f*tt +3.0f*t, p ); + v3_muladds( p, p0, 3.0f*tt -ttt -3.0f*t +1.0f, p ); +} + +static float eval_bezier_length( v3f p0, v3f p1, v3f h0, v3f h1, int res ) +{ + float length = 0.0f, m = 1.0f/(float)res; + v3f l, p; + v3_copy( p0, l ); + + for( int i=0; imn_next ) + tn->next = &system[ tn->mn_next->sub_uid ]; + if( tn->mn_next1 ) + tn->next1 = &system[ tn->mn_next1->sub_uid ]; + } +} + +static void traffic_visualize_link( traffic_node *ta, traffic_node *tb ) +{ + v3f p0, p1, h0, h1, p, l; + + if( !tb ) return; + + v3_copy( ta->co, p0 ); + v3_muladds( ta->co, ta->h, 1.0f, h0 ); + v3_copy( tb->co, p1 ); + v3_muladds( tb->co, tb->h, -1.0f, h1 ); + v3_copy( p0, l ); + + vg_line_pt3( h0, 0.2f, 0xff00ff00 ); + vg_line_pt3( h1, 0.2f, 0xffff00ff ); + vg_line( p0, h0, 0xff000000 ); + vg_line( p1, h1, 0xff000000 ); + + for( int i=0; i<5; i++ ) + { + float t = (float)(i+1)/5.0f; + eval_bezier_time( p0, p1, h0, h1, t, p ); + + vg_line( p, l, 0xffffffff ); + v3_copy( p, l ); + } +} + +static void sample_wheel_floor( v3f pos ) +{ + v3f ground; + v3_copy( pos, ground ); + ground[1] += 4.0f; + + ray_hit hit; + hit.dist = 8.0f; + + if( ray_world( ground, (v3f){0.0f,-1.0f,0.0f}, &hit )) + { + v3_copy( hit.pos, pos ); + } +} + +static void traffic_drive( traffic_driver *driver ) +{ + traffic_node *next, *current = driver->current; + + if( !current ) return; + next = driver->option==0? current->next: current->next1; + + if( driver->t > 1.0f ) + { + driver->t = driver->t - floorf( driver->t ); + driver->current = driver->option==0? current->next: current->next1; + driver->option = 0; + + current = driver->current; + if( !current ) + return; + + if( current->next && current->next1 ) + if( vg_randf() > 0.5f ) + driver->option = 1; + } + + traffic_visualize_link( current, next ); + + /* + * Calculate the speed of the curve at the current point. On the reference + * curve the rate should come out to be exactly 1 ktimestep traveled. + * Dividing this distance by ktimestep gives us the modifier to use. + */ + v3f p0,p1,h0,h1,pc,pn; + + v3_copy( current->co, p0 ); + v3_muladds( current->co, current->h, 1.0f, h0 ); + v3_copy( next->co, p1 ); + v3_muladds( next->co, next->h, -1.0f, h1 ); + + eval_bezier_time( p0,p1,h0,h1, driver->t, pc ); + eval_bezier_time( p0,p1,h0,h1, driver->t + ktimestep, pn ); + + float mod = ktimestep / v3_dist( pc, pn ); + v3f dir,side,up; + v3_sub( pn, pc, dir ); + v3_normalize(dir); + + /* + * Stick the car on the ground by casting rays where the wheels are + */ + side[0] = -dir[2]; + side[1] = 0.0f; + side[2] = dir[0]; + v3_normalize(side); + + v3f fl, fr, bc; + v3_muladds( pc, dir, 2.0f, fr ); + v3_muladds( pc, dir, 2.0f, fl ); + v3_muladds( pc, dir, -2.0f, bc ); + v3_muladds( fr, side, 1.0f, fr ); + v3_muladds( fl, side, -1.0f, fl ); + + sample_wheel_floor( fl ); + sample_wheel_floor( fr ); + sample_wheel_floor( bc ); + + vg_line( fl, fr, 0xff00ffff ); + vg_line( fr, bc, 0xff00ffff ); + vg_line( bc, fl, 0xff00ffff ); + + v3f norm; + v3f v0, v1; + v3_sub( fr, fl, v0 ); + v3_sub( bc, fl, v1 ); + v3_cross( v1, v0, norm ); + v3_normalize( norm ); + + /* + * Jesus take the wheel + */ + float steer_penalty = 1.0f-v3_dot( dir, driver->transform[0] ); + steer_penalty /= ktimestep; + steer_penalty *= 30.0f; + + float target_speed = vg_maxf( 16.0f * (1.0f-steer_penalty), 0.1f ), + accel = target_speed - driver->speed; + driver->speed = stable_force( driver->speed, accel*ktimestep*2.0f ); + driver->t += driver->speed*mod*ktimestep; + + /* + * Update transform + */ + v3_cross( dir, norm, side ); + v3_copy( dir, driver->transform[0] ); + v3_copy( norm, driver->transform[1] ); + v3_copy( side, driver->transform[2] ); + + v3_add( fl, fr, pc ); + v3_add( bc, pc, pc ); + v3_muls( pc, 1.0f/3.0f, pc ); + v3_copy( pc, driver->transform[3] ); +} + +static void traffic_visualize( traffic_node *system, int count ) +{ + for( int i=0; inext ); + traffic_visualize_link( tn, tn->next1 ); + } +} + +static void traffic_visualize_car( traffic_driver *driver ) +{ + vg_line_boxf_transformed( driver->transform, + (boxf){{-1.0f,0.0f,-0.5f}, + { 1.0f,0.0f, 0.5f}}, 0xff00ff00 ); +} + +#endif /* TRAFFIC_H */ diff --git a/world.h b/world.h index d8b3616..add08b7 100644 --- a/world.h +++ b/world.h @@ -14,6 +14,7 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); #include "bvh.h" #include "lighting.h" #include "model.h" +#include "traffic.h" #include "shaders/terrain.h" #include "shaders/sky.h" @@ -37,6 +38,12 @@ static struct gworld teleport_gate gates[64]; u32 gate_count; + + /* Paths */ + traffic_node traffic[128]; + u32 traffic_count; + + traffic_driver van_man[6]; /* Physics */ rigidbody temp_rbs[128]; @@ -45,10 +52,13 @@ static struct gworld /* Rendering & geometry */ scene geo, foliage, props; - mdl_submesh sm_surface; + mdl_submesh sm_surface, sm_other; glmesh skybox, skydome; mdl_submesh dome_upper, dome_lower; + + glmesh cars; + mdl_submesh car_holden; } world; @@ -166,6 +176,7 @@ static void world_load(void) world.spawn_count = 0; world.gate_count = 0; world.rb_count = 0; + world.traffic_count = 0; scene_init( &world.geo ); scene_init( &world.props ); @@ -194,6 +205,9 @@ static void world_load(void) if( mat_surf ) add_all_if_material( &world.geo, mworld, mat_surf ); + if( mat_vertex_blend ) + add_all_if_material( &world.geo, mworld, mat_vertex_blend ); + scene_copy_slice( &world.geo, &world.sm_surface ); @@ -222,17 +236,21 @@ static void world_load(void) else if( pnode->classtype == k_classtype_gate ) { struct classtype_gate *entgate = mdl_get_entdata( mworld, pnode ); - mdl_node *pother = mdl_node_from_id( mworld, entgate->target ); - - teleport_gate *gate = &world.gates[ world.gate_count ++ ]; - - v3_copy( pnode->co, gate->co[0] ); - v3_copy( pother->co, gate->co[1] ); - v4_copy( pnode->q, gate->q[0] ); - v4_copy( pother->q, gate->q[1] ); - v2_copy( pnode->s, gate->dims ); - gate_transform_update( gate ); + if( entgate->target ) + { + mdl_node *pother = mdl_node_from_id( mworld, entgate->target ); + + teleport_gate *gate = &world.gates[ world.gate_count ++ ]; + + v3_copy( pnode->co, gate->co[0] ); + v3_copy( pother->co, gate->co[1] ); + v4_copy( pnode->q, gate->q[0] ); + v4_copy( pother->q, gate->q[1] ); + v2_copy( pnode->s, gate->dims ); + + gate_transform_update( gate ); + } } else if( pnode->classtype == k_classtype_block ) { @@ -276,7 +294,28 @@ static void world_load(void) water_set_surface( &surf, pnode->co[1] ); } } + else if( pnode->classtype == k_classtype_car_path ) + { + struct classtype_car_path *p = mdl_get_entdata( mworld, pnode ); + traffic_node *tn = &world.traffic[ world.traffic_count ]; + tn->mn_next = NULL; + tn->mn_next1 = NULL; + + if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target ); + if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 ); + + m4x3f transform; + mdl_node_transform( pnode, transform ); + m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h ); + v3_copy( transform[3], tn->co ); + + pnode->sub_uid = world.traffic_count ++; + } } + + traffic_finalize( world.traffic, world.traffic_count ); + for( int i=0; ig_water_fog = 0.04f; render_update_lighting_ub(); + } static void world_init(void) @@ -356,6 +396,21 @@ static void world_init(void) world.dome_lower = *mdl_node_submesh( msky, nlower, 0 ); world.dome_upper = *mdl_node_submesh( msky, nupper, 0 ); free(msky); + + mdl_header *mcars = mdl_load( "models/rs_cars.mdl" ); + mdl_unpack_glmesh( mcars, &world.cars ); + mdl_node *nholden = mdl_node_from_name( mcars, "holden" ); + world.car_holden = *mdl_node_submesh( mcars, nholden, 0 ); + free(mcars); +} + +static void world_update(void) +{ + for( int i=0; i