#include "common.h"
#include "model.h"
#include "scene.h"
+#include "world.h"
#include "ik.h"
#include "rigidbody.h"
+#include "render.h"
#include "shaders/character.h"
vg_tex2d tex_pallet = { .path = "textures/ch_gradient.qoi" };
static void character_ragdoll_iter( struct character *ch )
{
+ /* TODO: Lots of the RB functions unimplemented here currently */
+
+ return;
rb_solver_reset();
for( int i=0; i<PART_COUNT; i++ )
{
- rb_build_manifold_terrain( &ch->ragdoll[i] );
-
- /* TODO: Cars, piece-to-piece collision */
-#if 0
- u32 colliders[16];
- int len = bh_select( &world.bhcubes, ch->ragdoll[i].bbx_world,
- colliders, 16 );
-
- for( int j=0; j<len; j++ )
- rb_build_manifold_rb_static( &ch->ragdoll[i],
- &world.temp_rbs[colliders[j]] );
-#endif
+ rb_collide( &ch->ragdoll[i], &world.rb_geo );
}
rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
static int debugview = 0;
static int sv_debugcam = 0;
static int lightedit = 0;
-static int sv_scene = 1;
+static int sv_scene = 0;
/* Components */
#include "road.h"
static void init_other(void)
{
+ player_init();
render_init();
gate_init();
world_init();
void vg_start(void)
{
- vg_convar_push( (struct vg_convar){
- .name = "scene",
- .data = &sv_scene,
- .data_type = k_convar_dtype_i32,
- .opt_i32 = { .min=0, .max=1, .clamp=1 },
- .persistent = 1
- });
-
vg_convar_push( (struct vg_convar){
.name = "fc",
.data = &freecam,
if( sv_scene == 0 )
{
- character_load( &player.mdl, "ch_default" );
+ character_load( &player.mdl, "ch_outlaw" );
character_init_ragdoll( &player.mdl );
world_load();
for( int i=0; i<4; i++ )
{
rigidbody *fn = &funnel[i];
- rb_contact_count += rb_sphere_vs_box( &ball, fn, rb_global_ct());
- rb_contact_count += rb_sphere_vs_box( &ball1, fn, rb_global_ct());
- rb_contact_count += rb_capsule_vs_box( &jeff1, fn, rb_global_ct() );
+ rb_collide( &ball, fn );
+ rb_collide( &ball1, fn );
+ rb_collide( &jeff1, fn );
for( int i=0; i<vg_list_size(jeffs); i++ )
- rb_contact_count += rb_capsule_vs_box( jeffs+i, fn, rb_global_ct() );
+ rb_collide( jeffs+i, fn );
}
for( int i=0; i<vg_list_size(jeffs)-1; i++ )
{
for( int j=i+1; j<vg_list_size(jeffs); j++ )
{
- rb_contact_count += rb_capsule_vs_capsule( jeffs+i, jeffs+j,
- rb_global_ct() );
+ rb_collide( jeffs+i, jeffs+j );
}
}
for( int i=0; i<vg_list_size(jeffs); i++ )
{
- rb_contact_count += rb_capsule_vs_box( jeffs+i, &ground, rb_global_ct() );
- rb_contact_count += rb_capsule_vs_sphere( jeffs+i, &ball, rb_global_ct() );
- rb_contact_count += rb_capsule_vs_sphere( jeffs+i, &ball1, rb_global_ct() );
- rb_contact_count += rb_capsule_vs_capsule( jeffs+i, &jeff1, rb_global_ct() );
+ rb_collide( jeffs+i, &ground );
+ rb_collide( jeffs+i, &ball );
+ rb_collide( jeffs+i, &ball1 );
+ rb_collide( jeffs+i, &jeff1 );
}
- rb_contact_count += rb_capsule_vs_box( &jeff1, &ground, rb_global_ct() );
- rb_contact_count += rb_capsule_vs_box( &jeff1, &blocky, rb_global_ct() );
- rb_contact_count += rb_capsule_vs_sphere( &jeff1, &ball, rb_global_ct() );
- rb_contact_count += rb_capsule_vs_sphere( &jeff1, &ball1, rb_global_ct() );
+ rb_collide( &jeff1, &ground );
+ rb_collide( &jeff1, &blocky );
+ rb_collide( &jeff1, &ball );
+ rb_collide( &jeff1, &ball1 );
- rb_contact_count += rb_sphere_vs_box( &ball, &ground, rb_global_ct() );
- rb_contact_count += rb_sphere_vs_box( &ball1, &ground, rb_global_ct() );
- rb_contact_count += rb_sphere_vs_sphere( &ball1, &ball, rb_global_ct() );
+ rb_collide( &ball, &ground );
+ rb_collide( &ball1, &ground );
+ rb_collide( &ball1, &ball );
rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
for( int i=0; i<8; i++ )
#include "audio.h"
#include "common.h"
+#include "world.h"
#include "character.h"
#include "bvh.h"
static struct gplayer
{
/* Physics */
- rigidbody rb;
+ rigidbody rb, collide_front, collide_back;
v3f a, v_last, m, bob, vl;
{
.on_board = 1,
- .rb = { .type = k_rb_shape_capsule }
+ .collide_front = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f },
+ .collide_back = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f }
};
/*
float best_velocity_mod = 0.0f,
best_velocity_delta = -9999.9f;
- float k_bias = 0.97f;
+ float k_bias = 0.96f;
v3f axis;
v3_cross( player.rb.up, player.rb.v, axis );
v2_lerp( player.board_xy, target, ktimestep*3.0f, player.board_xy );
}
+static void player_init(void)
+{
+ rb_init( &player.collide_front );
+ rb_init( &player.collide_back );
+}
+
static void player_physics(void)
{
/*
- * Player physics uses a customized routine seperate from the main
- * rigidbody implementation. It requires some non-standard impulse
- * responses being applied for example limiting the effect on certain axises
- * ( especially for angular velocity )
- *
- * The capsule collider is also at a different angle to the players roation.
+ * Update collision fronts
*/
+
+ rigidbody *rbf = &player.collide_front,
+ *rbb = &player.collide_back;
- m4x3f mboard;
- v3_copy( player.rb.to_world[0], mboard[0] );
- v3_copy( player.rb.to_world[2], mboard[1] );
- v3_copy( player.rb.to_world[1], mboard[2] );
- m4x3_mulv( player.rb.to_world, (v3f){ 0.0f, 0.3f, 0.0f }, mboard[3] );
+ m3x3_copy( player.rb.to_world, player.collide_front.to_world );
+ m3x3_copy( player.rb.to_world, player.collide_back.to_world );
+ m4x3_mulv( player.rb.to_world, (v3f){0.0f,0.0f,-k_board_length}, rbf->co );
+ v3_copy( rbf->co, rbf->to_world[3] );
+ m4x3_mulv( player.rb.to_world, (v3f){0.0f,0.0f, k_board_length}, rbb->co );
+ v3_copy( rbb->co, rbb->to_world[3] );
- debug_capsule( mboard, k_board_length*2.0f, k_board_radius, 0xff0000ff );
+ m4x3_invert_affine( rbf->to_world, rbf->to_local );
+ m4x3_invert_affine( rbb->to_world, rbb->to_local );
- 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 );
+ rb_update_bounds( rbf );
+ rb_update_bounds( rbb );
- 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;
+ rb_debug( rbf, 0xff00ffff );
+ rb_debug( rbb, 0xffffff00 );
- v3f surface_avg = {0.0f, 0.0f, 0.0f};
+ rb_ct manifold[24];
+ int len = 0;
+
+ len += rb_sphere_vs_scene( rbf, &world.rb_geo, manifold+len );
+ len += rb_sphere_vs_scene( rbb, &world.rb_geo, manifold+len );
+#if 0
for( int i=0; i<len; i++ )
{
u32 *ptri = &world.geo.indices[ geo[i]*3 ];
v3_copy( temp, player.rb.co );
}
- rb_presolve_contacts( manifold, manifold_count );
+#endif
+
+ rb_presolve_contacts( manifold, len );
+ v3f surface_avg = {0.0f, 0.0f, 0.0f};
- if( !manifold_count )
+ if( !len )
{
player_start_air();
}
else
{
+ for( int i=0; i<len; i++ )
+ v3_add( manifold[i].n, surface_avg, surface_avg );
+
v3_normalize( surface_avg );
if( v3_dot( player.rb.v, surface_avg ) > 0.5f )
for( int j=0; j<5; j++ )
{
- for( int i=0; i<manifold_count; i++ )
+ for( int i=0; i<len; i++ )
{
struct contact *ct = &manifold[i];
character_pose_reset( &player.mdl );
/* TODO */
- float fstand1 = 1.0f-(1.0f-fstand)*0.3f;
+ float fstand1 = 1.0f-(1.0f-fstand)*0.0f;
float amt_air = ffly*ffly,
amt_ground = 1.0f-amt_air,
character_final_pose( &player.mdl, (v3f){0.0f,0.0f,0.0f},
&pose_fly, amt_air );
-
/*
* Additive effects
-#ifndef RENDER_H
-#define RENDER_H
-
#include "common.h"
#include "model.h"
+static void render_water_texture( m4x3f camera );
+static void render_water_surface( m4x4f pv, m4x3f camera );
+static void render_world( m4x4f projection, m4x3f camera );
+static void shader_link_standard_ub( GLuint shader, int texture_id );
+static void render_world_depth( m4x4f projection, m4x3f camera );
+
+#ifndef RENDER_H
+#define RENDER_H
+
static struct pipeline
{
float fov;
}
};
-static void render_water_texture( m4x3f camera );
-static void render_water_surface( m4x4f pv, m4x3f camera );
-static void render_world( m4x4f projection, m4x3f camera );
-static void render_world_depth( m4x4f projection, m4x3f camera );
-
/*
* Matrix Projections
*/
#include "common.h"
#include "bvh.h"
+#include "scene.h"
static void rb_tangent_basis( v3f n, v3f tx, v3f ty );
static bh_system bh_system_rigidbodies;
#ifndef RIGIDBODY_H
#define RIGIDBODY_H
-#define RB_DEPR
+//#define RB_DEPR
#define k_rb_rate 60.0f
#define k_rb_delta (1.0f/k_rb_rate)
enum rb_shape
{
- k_rb_shape_box,
- k_rb_shape_sphere,
- k_rb_shape_capsule
+ k_rb_shape_box = 0,
+ k_rb_shape_sphere = 1,
+ k_rb_shape_capsule = 2,
+ k_rb_shape_scene = 3
}
type;
float height, radius;
}
capsule;
+
+ struct rb_scene
+ {
+ scene *pscene;
+ }
+ scene;
}
inf;
boxf bbx, bbx_world;
float inv_mass;
- v3f delta; /* where is the origin of this in relation to a parent body */
+ v3f delta; /* where is the origin of this in relation to a parent body
+ TODO: Move this somewhere other than rigidbody struct
+ it is only used by character.h's ragdoll
+ */
m4x3f to_world, to_local;
};
+#ifdef RB_DEPR
+/*
+ * Impulses on static objects get re-routed here
+ */
static rigidbody rb_static_null =
{
.co={0.0f,0.0f,0.0f},
.is_world = 1,
.inv_mass = 0.0f
};
+#endif
static void rb_debug( rigidbody *rb, u32 colour );
rb_contact_buffer[256];
static int rb_contact_count = 0;
+static void rb_update_bounds( rigidbody *rb )
+{
+ box_copy( rb->bbx, rb->bbx_world );
+ m4x3_transform_aabb( rb->to_world, rb->bbx_world );
+}
+
static void rb_update_transform( rigidbody *rb )
{
q_normalize( rb->q );
m4x3_invert_affine( rb->to_world, rb->to_local );
- box_copy( rb->bbx, rb->bbx_world );
- m4x3_transform_aabb( rb->to_world, rb->bbx_world );
-
m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f, 0.0f}, rb->right );
m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f, 0.0f}, rb->up );
m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,-1.0f}, rb->forward );
+
+ rb_update_bounds( rb );
}
static float sphere_volume( float radius )
rb->bbx[0][1] = -h;
rb->bbx[1][1] = h;
}
+ else if( rb->type == k_rb_shape_scene )
+ {
+ rb->is_world = 1;
+ box_copy( rb->inf.scene.pscene->bbx, rb->bbx );
+ }
if( rb->is_world )
{
}
static void rb_solver_reset(void);
+#ifdef RB_DEPR
static void rb_build_manifold_terrain( rigidbody *rb );
static void rb_build_manifold_terrain_sphere( rigidbody *rb );
+#endif
static void rb_solve_contacts( rb_ct *buf, int len );
static void rb_presolve_contacts( rb_ct *buffer, int len );
return 0;
}
+/* TODO: these guys */
+
+static int rb_capsule_vs_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+{
+ u32 geo[128];
+ v3f tri[3];
+ int len = bh_select( &rbb->inf.scene.pscene->bhtris,
+ rba->bbx_world, geo, 128 );
+
+ return 0;
+}
+
+static int rb_sphere_vs_triangle( rigidbody *rba, rigidbody *rbb,
+ v3f tri[3], rb_ct *buf )
+{
+ v3f delta, co;
+
+ closest_on_triangle( rba->co, tri, co );
+ v3_sub( rba->co, co, delta );
+
+ vg_line( rba->co, co, 0xffff0000 );
+ vg_line_pt3( rba->co, 0.1f, 0xff00ffff );
+
+ float d2 = v3_length2( delta ),
+ r = rba->inf.sphere.radius;
+
+ if( d2 < r*r )
+ {
+ rb_ct *ct = buf;
+
+ v3f ab, ac, tn;
+ v3_sub( tri[2], tri[0], ab );
+ v3_sub( tri[1], tri[0], ac );
+ v3_cross( ac, ab, tn );
+ v3_copy( tn, ct->n );
+ v3_normalize( ct->n );
+
+ float d = sqrtf(d2);
+
+ v3_copy( co, ct->co );
+ ct->p = r-d;
+ ct->rba = rba;
+ ct->rbb = rbb;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rb_sphere_vs_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+{
+ scene *sc = rbb->inf.scene.pscene;
+
+ u32 geo[128];
+ v3f tri[3];
+ int len = bh_select( &sc->bhtris, rba->bbx_world, geo, 128 );
+
+ int count = 0;
+
+ for( int i=0; i<len; i++ )
+ {
+ u32 *ptri = &sc->indices[ geo[i]*3 ];
+
+ for( int j=0; j<3; j++ )
+ v3_copy( sc->verts[ptri[j]].co, tri[j] );
+
+ vg_line(tri[0],tri[1],0xff00ff00 );
+ vg_line(tri[1],tri[2],0xff00ff00 );
+ vg_line(tri[2],tri[0],0xff00ff00 );
+
+ count += rb_sphere_vs_triangle( rba, rbb, tri, buf+count );
+
+ if( count == 12 )
+ {
+ vg_warn( "Exceeding sphere_vs_scene capacity. Geometry too dense!\n" );
+ return count;
+ }
+ }
+
+ return count;
+}
+
static int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
{
vg_error( "Collision type is unimplemented between types %d and %d\n",
= {
/* box */ /* Sphere */ /* Capsule */
/*box */ { RB_MATRIX_ERROR, rb_box_vs_sphere, rb_box_vs_capsule, RB_MATRIX_ERROR },
-/*sphere */ { rb_sphere_vs_box, rb_sphere_vs_sphere, rb_sphere_vs_capsule, RB_MATRIX_ERROR },
+/*sphere */ { rb_sphere_vs_box, rb_sphere_vs_sphere, rb_sphere_vs_capsule, rb_sphere_vs_scene },
/*capsule*/ { rb_capsule_vs_box,rb_capsule_vs_sphere,rb_capsule_vs_capsule,RB_MATRIX_ERROR },
/*mesh */ { RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR }
};
+static int rb_collide( rigidbody *rba, rigidbody *rbb )
+{
+ int (*collider_jump)(rigidbody *rba, rigidbody *rbb, rb_ct *buf )
+ = rb_jump_table[rba->type][rbb->type];
+
+ /*
+ * 12 is the maximum manifold size we can generate, so we are forced to abort
+ * potentially checking any more.
+ */
+ if( rb_contact_count + 12 > vg_list_size(rb_contact_buffer) )
+ {
+ vg_warn( "Too many contacts made in global collider buffer (%d of %d\n)",
+ rb_contact_count, vg_list_size(rb_contact_buffer) );
+ return 0;
+ }
+
+ /*
+ * TODO: Replace this with a more dedicated broad phase pass
+ */
+ if( box_overlap( rba->bbx_world, rbb->bbx_world ) )
+ {
+ int count = collider_jump( rba, rbb, rb_contact_buffer+rb_contact_count);
+ rb_contact_count += count;
+ return count;
+ }
+ else
+ return 0;
+}
/*
* Generic functions
*/
+#ifdef RB_DEPR
/*
* This function does not accept triangle as a dynamic object, it is assumed
* to always be static.
return 0;
}
-
-RB_DEPR
static int sphere_vs_triangle( v3f c, float r, v3f tri[3],
v3f co, v3f norm, float *p )
{
}
#include "world.h"
+#endif
static void rb_solver_reset(void)
{
return rb_contact_buffer + rb_contact_count;
}
+#ifdef RB_DEPR
static struct contact *rb_start_contact(void)
{
if( rb_contact_count == vg_list_size(rb_contact_buffer) )
}
-RB_DEPR
static void rb_build_manifold_terrain( rigidbody *rb )
{
v3f *box = rb->bbx;
}
}
}
+#endif
/*
* Initializing things like tangent vectors
}
-RB_DEPR
static void rb_constraint_angle( rigidbody *rba, v3f va,
rigidbody *rbb, v3f vb,
float max, float spring )
debug_capsule( rb->to_world, r, h, colour );
}
+ else if( rb->type == k_rb_shape_scene )
+ {
+ vg_line_boxf( rb->bbx, colour );
+ }
}
+#ifdef RB_DEPR
/*
* out penetration distance, normal
*/
.cast_ray = NULL
};
+#endif
+
#endif /* RIGIDBODY_H */
/* Rendering & geometry */
scene geo, foliage;
+ rigidbody rb_geo;
mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb;
mdl_node *nholden = mdl_node_from_name( mcars, "holden" );
world.car_holden = *mdl_node_submesh( mcars, nholden, 0 );
free(mcars);
+
+ /*
+ * Setup scene collider
+ */
+ v3_zero( world.rb_geo.co );
+ q_identity( world.rb_geo.q );
+
+ world.rb_geo.type = k_rb_shape_scene;
+ world.rb_geo.inf.scene.pscene = &world.geo;
+ world.rb_geo.is_world = 1;
+ rb_init( &world.rb_geo );
}
static void world_update(void)
{
+#if 0
rb_solver_reset();
rb_build_manifold_terrain_sphere( &world.mr_ball );
rb_iter( &world.mr_ball );
rb_update_transform( &world.mr_ball );
rb_debug( &world.mr_ball, 0 );
+#endif
for( int i=0; i<vg_list_size(world.van_man); i++ )
{