From: hgn Date: Thu, 30 Jun 2022 02:03:58 +0000 (+0100) Subject: bvh interface and high perf gate X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=1656d58a7bd17df4a1edcc9677ade4dbafc82229;p=carveJwlIkooP6JGAAIwe30JlM.git bvh interface and high perf gate --- diff --git a/bvh.h b/bvh.h new file mode 100644 index 0000000..c841939 --- /dev/null +++ b/bvh.h @@ -0,0 +1,284 @@ +#ifndef BVH_H +#define BVH_H +#include "common.h" + +/* + * Usage: + * + * create a bh_system with functions filled out for expand, centroid, and swap. + * optionally include item_debug and cast_ray functions if needed, otherwise, + * set them to null + * + * create a bh_tree struct with: + * user: a pointer back the base of the data you are ordering + * system: the system we created above which will deal with the data + * + * call bh_create( bh_tree *bh, u32 item_count, u32 item_size ) + */ + +typedef struct bh_node bh_node; +typedef struct bh_tree bh_tree; +typedef struct bh_system bh_system; + +struct bh_node +{ + boxf bbx; + + /* if il is 0, this is a leaf */ + u32 il, count; + union{ u32 ir, start; }; +}; + +struct bh_tree +{ + bh_node *nodes; + u32 node_count; + + bh_system *system; + void *user; +}; + +struct bh_system +{ + void (*expand_bound)( void *user, boxf bound, u32 item_index ); + float (*item_centroid)( void *user, u32 item_index, int axis ); + void (*item_swap)( void *user, u32 ia, u32 ib ); + u32 item_size; + + /* + * Optional: + * item_debug - draw this item quickly usually with lines + * cast_ray - shoot a ray against the object, if this is not set, + * raycasts will simply return the hit on the bvh node + */ + + void (*item_debug)( void *user, u32 item_index ); + int (*cast_ray)( void *user, v3f co, v3f dir, ray_hit *hit ); +}; + +static void bh_update_bounds( bh_tree *bh, u32 inode ) +{ + bh_node *node = &bh->nodes[ inode ]; + + box_init_inf( node->bbx ); + for( u32 i=0; icount; i++ ) + { + u32 idx = node->start+i; + bh->system->expand_bound( bh->user, node->bbx, idx ); + } +} + +static void bh_subdivide( bh_tree *bh, u32 inode ) +{ + bh_node *node = &bh->nodes[ inode ]; + + v3f extent; + v3_sub( node->bbx[1], node->bbx[0], extent ); + + int axis = 0; + if( extent[1] > extent[0] ) axis = 1; + if( extent[2] > extent[axis] ) axis = 2; + + float split = node->bbx[0][axis] + extent[axis]*0.5f; + + float avg = 0.0; + for( u32 t=0; tcount; t++ ) + { + u32 idx = node->start+t; + avg += bh->system->item_centroid( bh->user, idx, axis ); + } + avg /= (float)node->count; + + split = avg; + + i32 i = node->start, + j = i + node->count-1; + + while( i <= j ) + { + if( bh->system->item_centroid( bh->user, i, axis ) < split ) + i ++; + else + { + bh->system->item_swap( bh->user, i, j ); + j --; + } + } + + u32 left_count = i - node->start; + if( left_count == 0 || left_count == node->count ) return; + + u32 il = bh->node_count ++, + ir = bh->node_count ++; + + bh_node *lnode = &bh->nodes[il], + *rnode = &bh->nodes[ir]; + + lnode->start = node->start; + lnode->count = left_count; + rnode->start = i; + rnode->count = node->count - left_count; + + node->il = il; + node->ir = ir; + node->count = 0; + + /* TODO: Implement max depth, or stack */ + bh_update_bounds( bh, il ); + bh_update_bounds( bh, ir ); + bh_subdivide( bh, il ); + bh_subdivide( bh, ir ); +} + +static void bh_create( bh_tree *bh, bh_system *sys, u32 item_count ) +{ + bh->system = sys; + bh->nodes = malloc( sys->item_size * (item_count*2-1) ); + + bh_node *root = &bh->nodes[0]; + bh->node_count = 1; + + root->il = 0; + root->ir = 0; + root->count = item_count; + root->start = 0; + + bh_update_bounds( bh, 0 ); + bh_subdivide( bh, 0 ); + + bh->nodes = realloc( bh->nodes, sys->item_size * bh->node_count ); + vg_success( "BVH done, size: %u/%u\n", bh->node_count, (item_count*2-1) ); +} + +static void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour ) +{ + bh_node *node = &bh->nodes[ inode ]; + + if( (pos[0] >= node->bbx[0][0] && pos[0] <= node->bbx[1][0]) && + (pos[2] >= node->bbx[0][2] && pos[2] <= node->bbx[1][2]) ) + { + if( !node->count ) + { + vg_line_boxf( node->bbx, colour ); + + bh_debug_node( bh, node->il, pos, colour ); + bh_debug_node( bh, node->ir, pos, colour ); + } + else + { + vg_line_boxf( node->bbx, 0xff00ff00 ); + + if( bh->system->item_debug ) + { + for( u32 i=0; icount; i++ ) + { + u32 idx = node->start+i; + bh->system->item_debug( bh->user, idx ); + } + } + } + } +} + +static int bh_ray( bh_tree *bh, u32 inode, v3f co, v3f dir, ray_hit *hit ) +{ + int count = 0; + u32 stack[100]; + u32 depth = 2; + + stack[0] = 0; + stack[1] = bh->nodes[0].il; + stack[2] = bh->nodes[0].ir; + + while(depth) + { + bh_node *inode = &bh->nodes[ stack[depth] ]; + if( ray_aabb( inode->bbx, co, dir, hit->dist ) ) + { + if( inode->count ) + { + for( u32 i=0; icount; i++ ) + { + u32 idx = inode->start+i; + + if( bh->system->cast_ray ) + count += bh->system->cast_ray( bh->user, co, dir, hit ); + else + count ++; + } + + depth --; + } + else + { + if( depth+1 >= vg_list_size(stack) ) + { + vg_error( "Maximum stack reached!\n" ); + return count; + } + + stack[depth] = inode->il; + stack[depth+1] = inode->ir; + depth ++; + } + } + else + { + depth --; + } + } + + return count; +} + +static int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len ) +{ + int count = 0; + u32 stack[100]; + u32 depth = 2; + + stack[0] = 0; + stack[1] = bh->nodes[0].il; + stack[2] = bh->nodes[0].ir; + + while(depth) + { + bh_node *inode = &bh->nodes[ stack[depth] ]; + if( box_overlap( inode->bbx, box ) ) + { + if( inode->count ) + { + if( count + inode->count >= len ) + { + vg_error( "Maximum buffer reached!\n" ); + return count; + } + + for( u32 i=0; icount; i++ ) + buffer[ count ++ ] = inode->start+i; + + depth --; + } + else + { + if( depth+1 >= vg_list_size(stack) ) + { + vg_error( "Maximum stack reached!\n" ); + return count; + } + + stack[depth] = inode->il; + stack[depth+1] = inode->ir; + depth ++; + } + } + else + { + depth --; + } + } + + return count; +} + +#endif /* BVH_H */ diff --git a/character.h b/character.h index bc2ccb5..047b714 100644 --- a/character.h +++ b/character.h @@ -368,6 +368,22 @@ static character_pose pose_stand = .cam = {-0.3477f, 1.5884f, -0.0019f} }; +static character_pose pose_stand_reverse = +{ + .b0 = {0.1624f, 1.0688f, -0.0632f}, + .b1 = {0.0499f, 1.5564f, -0.0013f}, + .p = {0.5423f, 1.2810f, -0.2368f}, + .fr = {0.0535f, 0.1312f, -0.3647f}, + .fl = {0.0354f, 0.1464f, 0.2917f}, + .pl = {-0.4325f, 0.6889f, 0.4591f}, + .pr = {-0.4794f, 0.7598f, -0.0842f}, + .hl = {0.0498f, 1.0058f, 0.2317f}, + .hr = {0.0188f, 0.9786f, -0.2725f}, + .apl = {0.2898f, 1.3453f, 0.0695f}, + .apr = {0.4715f, 1.2876f, -0.4982f}, + .cam = {-0.3477f, 1.5884f, -0.0730f} +}; + static character_pose pose_fly = { .b0 = {0.2995f, 0.6819f, -0.1369f}, @@ -831,7 +847,18 @@ static void character_debug_ragdoll( struct character *ch ) static void character_ragdoll_iter( struct character *ch ) { for( int i=0; iragdoll[i] ); + { + rb_manifold_reset( &ch->ragdoll[i] ); + rb_build_manifold_terrain( &ch->ragdoll[i] ); + + u32 colliders[16]; + int len = bh_select( &world.bhcubes, ch->ragdoll[i].bbx_world, + colliders, 16 ); + + for( int j=0; jragdoll[i], + &world.temp_rbs[colliders[j]] ); + } v3f rv; diff --git a/common.h b/common.h index 51eb1fa..1e1ebed 100644 --- a/common.h +++ b/common.h @@ -13,4 +13,13 @@ enum classtype k_classtype_gate = 1 }; +/* TODO: he needs a home somewhere */ +typedef struct ray_hit ray_hit; +struct ray_hit +{ + float dist; + u32 *tri; + v3f pos, normal; +}; + #endif /* COMMON_H */ diff --git a/gate.h b/gate.h index 9350d2b..6e9b95f 100644 --- a/gate.h +++ b/gate.h @@ -6,6 +6,8 @@ #include "model.h" #include "render.h" #include "shaders/gate.h" +#include "shaders/gatelq.h" +#include "water.h" typedef struct teleport_gate teleport_gate; @@ -13,8 +15,15 @@ static struct { GLuint fb, rgb, rb; glmesh mdl; + + int high_qual; /* If in high performance mode, we don't use RT's, and + instead use stencil buffers. + There is therefore no heat warp effect. */ } -grender; +grender = +{ + .high_qual = 0 +}; struct teleport_gate { @@ -42,6 +51,7 @@ static void gate_transform_update( teleport_gate *gate ) static void gate_register(void) { shader_gate_register(); + shader_gatelq_register(); } static void gate_init(void) @@ -70,6 +80,9 @@ static void render_gate( teleport_gate *gate, m4x3f camera ) if( v3_dot(v0, gatedir) >= 0.0f ) return; + if( v3_dist( viewpos, gate->co[0] ) > 100.0f ) + return; + v3f a,b,c,d; float sx = gate->dims[0], @@ -91,10 +104,10 @@ static void render_gate( teleport_gate *gate, m4x3f camera ) vg_line_pt3( cam_new[3], 0.3f, 0xff00ff00 ); - glBindFramebuffer( GL_FRAMEBUFFER, grender.fb ); - glClearColor( 0.11f, 0.35f, 0.37f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); - + m4x3f gate_xform; + m4x3_copy( gate->to_world, gate_xform ); + m4x3_scalev( gate_xform, (v3f){ gate->dims[0], gate->dims[1], 1.0f } ); + m4x3f inverse; m4x3_invert_affine( cam_new, inverse ); @@ -107,47 +120,87 @@ static void render_gate( teleport_gate *gate, m4x3f camera ) m4x4f projection; pipeline_projection( projection, 0.1f, 900.0f ); - m4x3_mulp( inverse, surface, surface ); surface[3] = -fabsf(surface[3]); plane_clip_projection( projection, surface ); m4x4_mul( projection, view, projection ); - - render_world( projection, cam_new ); - render_water_texture( cam_new ); - glBindFramebuffer( GL_FRAMEBUFFER, grender.fb ); - render_water_surface( projection ); - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - - shader_gate_use(); - - m4x3f full; - m4x3_copy( gate->to_world, full ); - m4x3_scalev( full, (v3f){ gate->dims[0], gate->dims[1], 1.0f } ); - - shader_gate_uPv( vg_pv ); - shader_gate_uMdl( full ); - - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, grender.rgb ); - shader_gate_uCam( viewpos ); - shader_gate_uTexMain( 0 ); - shader_gate_uTexWater( 1 ); - shader_gate_uTime( vg_time*0.25f ); - shader_gate_uInvRes( (v2f){ - 1.0f / (float)vg_window_x, - 1.0f / (float)vg_window_y }); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - mesh_bind( &grender.mdl ); - mesh_draw( &grender.mdl ); + if( grender.high_qual ) + { + glBindFramebuffer( GL_FRAMEBUFFER, grender.fb ); + glClearColor( 0.11f, 0.35f, 0.37f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + } + else + { + shader_gatelq_use(); + shader_gatelq_uPv( vg_pv ); + shader_gatelq_uMdl( gate_xform ); + shader_gatelq_uCam( viewpos ); + shader_gatelq_uTime( vg_time*0.25f ); + shader_gatelq_uInvRes( (v2f){ + 1.0f / (float)vg_window_x, + 1.0f / (float)vg_window_y }); + + glEnable( GL_STENCIL_TEST ); + glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); + glStencilFunc( GL_ALWAYS, 1, 0xFF ); + glStencilMask( 0xFF ); + + mesh_bind( &grender.mdl ); + mesh_draw( &grender.mdl ); + + glClear( GL_DEPTH_BUFFER_BIT ); + glStencilFunc( GL_EQUAL, 1, 0xFF ); + glStencilMask( 0x00 ); + } - glDisable(GL_BLEND); + render_world( projection, cam_new ); + + if( grender.high_qual ) + { + /* + * TODO: Need to find a way to draw a stencil buffer into the water + * rendering + */ + + render_water_texture( cam_new ); + glBindFramebuffer( GL_FRAMEBUFFER, grender.fb ); + render_water_surface( projection ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + + shader_gate_use(); + + shader_gate_uPv( vg_pv ); + shader_gate_uMdl( gate_xform ); + + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, grender.rgb ); + shader_gate_uCam( viewpos ); + shader_gate_uTexMain( 0 ); + shader_gate_uTexWater( 1 ); + shader_gate_uTime( vg_time*0.25f ); + shader_gate_uInvRes( (v2f){ + 1.0f / (float)vg_window_x, + 1.0f / (float)vg_window_y }); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + mesh_bind( &grender.mdl ); + mesh_draw( &grender.mdl ); + + glDisable(GL_BLEND); + } + else + { + glStencilMask( 0xFF ); + glStencilFunc( GL_ALWAYS, 1, 0xFF ); + glDisable( GL_STENCIL_TEST ); + } } static int gate_intersect( teleport_gate *gate, v3f pos, v3f last ) diff --git a/main.c b/main.c index aaf58dc..6b38fc5 100644 --- a/main.c +++ b/main.c @@ -164,7 +164,7 @@ void vg_render(void) glDisable( GL_DEPTH_TEST ); glClearColor( 0.11f, 0.35f, 0.37f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); float speed = freecam? 0.0f: v3_length( player.v ); v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f }; diff --git a/player.h b/player.h index 790d71c..984d4e3 100644 --- a/player.h +++ b/player.h @@ -152,6 +152,8 @@ static void player_start_air(void) float best_velocity_mod = 0.0f, best_velocity_delta = -9999.9f; + 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 ); @@ -166,7 +168,7 @@ static void player_start_air(void) v3f pco, pco1, pv; v3_copy( player.co, pco ); - v3_copy( player.v, pv ); + v3_muls( player.v, k_bias, pv ); /* * Try different 'rotations' of the velocity to find the best possible @@ -181,7 +183,7 @@ static void player_start_air(void) q_m3x3( vr_q, vr ); m3x3_mulv( vr, pv, pv ); - v3_muladds( pco, pv, ktimestep, pco ); + v3_muladds( pco, pv, pstep, pco ); for( int i=0; i<50; i++ ) { @@ -413,9 +415,6 @@ static void draw_cross(v3f pos,u32 colour, float scale) static void player_physics_air(void) { m3x3_mulv( player.vr, player.v, player.v ); - for( int i=0; i 0.0001f ) + float orient = + (points[i][2]-points[p][2])*(points[q][0]-points[i][0]) - + (points[i][0]-points[p][0])*(points[q][2]-points[i][2]); + + if( orient > 0.0001f ) { q = i; } @@ -1959,7 +1964,6 @@ static void player_do_collision( rigidbody *rb ) 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] ); @@ -1974,6 +1978,31 @@ static void player_do_collision( rigidbody *rb ) 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 0.2f && ya < kheight ) - { - v3_copy( verts[ia], hull[hull_len] ); - hull[hull_len ++][1] = 0.2f; + m4x3_mulv( player.to_world, p0, p0 ); + vg_line_pt3( p0, 0.1f, 0xffffff00 ); + } } } @@ -2031,6 +2055,8 @@ static void player_do_collision( rigidbody *rb ) v3f p0, p1, p2, p3; v3_copy( hull[hull_indices[i]], p0 ); v3_copy( hull[hull_indices[(i+1)%len]], p1 ); + p0[1] = 0.2f; + p1[1] = 0.2f; v3_add( p0, (v3f){0,kheight-0.2f,0}, p2 ); v3_add( p1, (v3f){0,kheight-0.2f,0}, p3 ); @@ -2044,82 +2070,102 @@ static void player_do_collision( rigidbody *rb ) vg_line( p0, p2, 0xff00ffa0 ); } - int collide = 1; - float min_dist = 99999.9f; - v2f normal; - for( int i=0; i 14.0f ) + { + player.is_dead = 1; + character_ragdoll_copypose( &player.mdl, player.v ); + return; + } - float vn = vg_maxf( -v2_dot( vel, normal ), 0.0f ); - vn += -0.2f * (1.0f/k_rb_delta) * vg_minf( 0.0f, -min_dist+0.04f ); + 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 ); + } - v2_muls( normal, vn*0.03f, impulse ); - v3f impulse_world = { impulse[0], 0.0f, impulse[1] }; + v2_muls( normal, vn*0.03f, impulse ); + v3f impulse_world = { impulse[0], 0.0f, impulse[1] }; - m3x3_mulv( player.to_world, impulse_world, impulse_world ); - v3_add( impulse_world, player.v, player.v ); - - 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 ); + m3x3_mulv( player.to_world, impulse_world, impulse_world ); + v3_add( impulse_world, player.v, player.v ); + } } } static void player_update(void) { + for( int i=0; i0.0f) reset_player(0,NULL); @@ -2138,8 +2184,17 @@ static void player_update(void) { if( player.on_board ) { - for( int i=0; ico, rb->to_world[3] ); 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 ); } static void rb_init( rigidbody *rb ) @@ -108,7 +113,12 @@ static void rb_tangent_basis( v3f n, v3f tx, v3f ty ) #include "world.h" -static void rb_build_manifold( rigidbody *rb ) +static void rb_manifold_reset( rigidbody *rb ) +{ + rb->manifold_count = 0; +} + +static void rb_build_manifold_terrain( rigidbody *rb ) { v3f *box = rb->bbx; v3f pts[8]; @@ -134,7 +144,7 @@ static void rb_build_manifold( rigidbody *rb ) m4x3_mulv( rb->to_world, p110, p110 ); m4x3_mulv( rb->to_world, p111, p111 ); - rb->manifold_count = 0; + int count = 0; for( int i=0; i<8; i++ ) { @@ -171,7 +181,8 @@ static void rb_build_manifold( rigidbody *rb ) ct->tangent_impulse[1] = 0.0f; rb->manifold_count ++; - if( rb->manifold_count == 4 ) + count ++; + if( count == 4 ) break; } } @@ -242,8 +253,7 @@ struct rb_angle_limit float impulse, bias; }; -static int rb_angle_limit_force( - rigidbody *rba, v3f va, +static int rb_angle_limit_force( rigidbody *rba, v3f va, rigidbody *rbb, v3f vb, float max ) { @@ -481,4 +491,101 @@ static int rb_point_in_body( rigidbody *rb, v3f pos, float *pen, v3f normal ) return 0; } +static void rb_build_manifold_rb_static( rigidbody *ra, rigidbody *rb_static ) +{ + v3f verts[8]; + + v3f a, b; + v3_copy( ra->bbx[0], a ); + v3_copy( ra->bbx[1], b ); + + m4x3_mulv( ra->to_world, (v3f){ a[0], a[1], a[2] }, verts[0] ); + m4x3_mulv( ra->to_world, (v3f){ a[0], b[1], a[2] }, verts[1] ); + m4x3_mulv( ra->to_world, (v3f){ b[0], b[1], a[2] }, verts[2] ); + m4x3_mulv( ra->to_world, (v3f){ b[0], a[1], a[2] }, verts[3] ); + m4x3_mulv( ra->to_world, (v3f){ a[0], a[1], b[2] }, verts[4] ); + m4x3_mulv( ra->to_world, (v3f){ a[0], b[1], b[2] }, verts[5] ); + 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] ); + + int count = 0; + + for( int i=0; i<8; i++ ) + { + if( ra->manifold_count == vg_list_size(ra->manifold) ) + return; + + struct contact *ct = &ra->manifold[ ra->manifold_count ]; + + float p; + v3f normal; + + if( rb_point_in_body( rb_static, verts[i], &p, normal )) + { + v3_copy( normal, ct->n ); + v3_muladds( verts[i], ct->n, p*0.5f, ct->co ); + v3_sub( ct->co, ra->co, ct->delta ); + + vg_line_pt3( ct->co, 0.0125f, 0xffff00ff ); + + ct->bias = -0.2f * (1.0f/k_rb_delta) * vg_minf( 0.0f, -p+0.04f ); + rb_tangent_basis( ct->n, ct->t[0], ct->t[1] ); + + ct->norm_impulse = 0.0f; + ct->tangent_impulse[0] = 0.0f; + ct->tangent_impulse[1] = 0.0f; + + ra->manifold_count ++; + count ++; + if( count == 4 ) + return; + } + } +} + +/* + * BVH implementation, this is ONLY for static rigidbodies, its to slow for + * realtime use. + */ + +static void rb_bh_expand_bound( void *user, boxf bound, u32 item_index ) +{ + rigidbody *rb = &((rigidbody *)user)[ item_index ]; + box_concat( bound, rb->bbx_world ); +} + +static float rb_bh_centroid( void *user, u32 item_index, int axis ) +{ + rigidbody *rb = &((rigidbody *)user)[ item_index ]; + return (rb->bbx_world[axis][0] + rb->bbx_world[1][axis]) * 0.5f; +} + +static void rb_bh_swap( void *user, u32 ia, u32 ib ) +{ + rigidbody temp, *rba, *rbb; + rba = &((rigidbody *)user)[ ia ]; + rbb = &((rigidbody *)user)[ ib ]; + + temp = *rba; + *rba = *rbb; + *rbb = temp; +} + +static void rb_bh_debug( void *user, u32 item_index ) +{ + rigidbody *rb = &((rigidbody *)user)[ item_index ]; + rb_debug( rb, 0xff00ffff ); +} + +static bh_system bh_system_rigidbodies = +{ + .expand_bound = rb_bh_expand_bound, + .item_centroid = rb_bh_centroid, + .item_swap = rb_bh_swap, + .item_debug = rb_bh_debug, + .cast_ray = NULL, + + .item_size = sizeof(rigidbody) +}; + #endif /* RIGIDBODY_H */ diff --git a/scene.h b/scene.h index d6cfb0a..c5c94f5 100644 --- a/scene.h +++ b/scene.h @@ -1,7 +1,7 @@ #ifndef SCENE_H #define SCENE_H -#include "vg/vg.h" +#include "common.h" #include "model.h" typedef struct scene scene; @@ -369,6 +369,15 @@ static void sample_scene_normal( scene *pscene, v3f pos, v3f normal ) normal[2] = 0.0f; } + +/* + * + * + * TODO: THIS SHIT IS DEPRECATED FOR THE NEW SHIT IN BVH.H + * + * + */ + struct bvh_node { boxf bbx; @@ -409,18 +418,14 @@ static void bvh_subdiv( scene *s, u32 inode ) float split = node->bbx[0][axis] + extent[axis]*0.5f; - /* To beat: 121,687 / 136,579 - * 136,375 - */ - float avg = 0.0; for( u32 t=0; tcount; t++ ) { u32 *ti = &s->indices[(node->start+t)*3]; float a = s->verts[ti[0]].co[axis], - b = s->verts[ti[1]].co[axis], - c = s->verts[ti[2]].co[axis]; - avg += (a+b+c)/3.0; + b = s->verts[ti[1]].co[axis], + c = s->verts[ti[2]].co[axis]; + avg += (a+b+c) * (1.0f/3.0f); } avg /= (float)node->count; @@ -437,7 +442,7 @@ static void bvh_subdiv( scene *s, u32 inode ) b = s->verts[ti[1]].co[axis], c = s->verts[ti[2]].co[axis]; - if( ((a+b+c) / 3.0f) < split ) + if( (a+b+c) * (1.0f/3.0f) < split ) i ++; else { @@ -545,34 +550,6 @@ static void bvh_debug( scene *s, v3f pos ) bvh_debug_node( s, 0, pos, 0x4000ffa8 ); } -typedef struct ray_hit ray_hit; -struct ray_hit -{ - float dist; - u32 *tri; - v3f pos, normal; -}; - -int ray_aabb( boxf box, v3f co, v3f dir, float dist ) -{ - v3f v0, v1; - float tmin, tmax; - - v3_sub( box[0], co, v0 ); - v3_sub( box[1], co, v1 ); - v3_div( v0, dir, v0 ); - v3_div( v1, dir, v1 ); - - tmin = vg_minf( v0[0], v1[0] ); - tmax = vg_maxf( v0[0], v1[0] ); - tmin = vg_maxf( tmin, vg_minf( v0[1], v1[1] )); - tmax = vg_minf( tmax, vg_maxf( v0[1], v1[1] )); - tmin = vg_maxf( tmin, vg_minf( v0[2], v1[2] )); - tmax = vg_minf( tmax, vg_maxf( v0[2], v1[2] )); - - return tmax >= tmin && tmin < dist && tmax > 0; -} - static int bvh_ray_tri( scene *sc, u32 *tri, v3f co, v3f dir, ray_hit *hit ) { v3f positions[3]; @@ -595,6 +572,7 @@ static int bvh_ray_tri( scene *sc, u32 *tri, v3f co, v3f dir, ray_hit *hit ) static int bvh_ray( scene *s, u32 inode, v3f co, v3f dir, ray_hit *hit ) { +#if 0 bvh_node *node = &s->bvh.nodes[ inode ]; if( !ray_aabb( node->bbx, co, dir, hit->dist )) @@ -616,6 +594,51 @@ static int bvh_ray( scene *s, u32 inode, v3f co, v3f dir, ray_hit *hit ) count += bvh_ray( s, node->ir, co, dir, hit ); } + return count; +#endif + + int count = 0; + u32 stack[100]; + u32 depth = 2; + + stack[0] = 0; + stack[1] = s->bvh.nodes[0].il; + stack[2] = s->bvh.nodes[0].ir; + + while(depth) + { + bvh_node *inode = &s->bvh.nodes[ stack[depth] ]; + if( ray_aabb( inode->bbx, co, dir, hit->dist ) ) + { + if( inode->count ) + { + for( u32 i=0; icount; i++ ) + { + u32 *indices = &s->indices[ (inode->start+i)*3 ]; + count += bvh_ray_tri( s, indices, co, dir, hit ); + } + + depth --; + } + else + { + if( depth+1 >= vg_list_size(stack) ) + { + vg_error( "Maximum stack reached!\n" ); + return count; + } + + stack[depth] = inode->il; + stack[depth+1] = inode->ir; + depth ++; + } + } + else + { + depth --; + } + } + return count; } diff --git a/shaders/gate_lq.fs b/shaders/gate_lq.fs new file mode 100644 index 0000000..c455126 --- /dev/null +++ b/shaders/gate_lq.fs @@ -0,0 +1,23 @@ +out vec4 FragColor; + +uniform float uTime; +uniform vec3 uCam; +uniform vec2 uInvRes; + +in vec3 aNorm; +in vec2 aUv; +in vec3 aCo; + +void main() +{ + vec2 ssuv = gl_FragCoord.xy; + float opacity = 1.0-smoothstep(0.4,1.0,aUv.y); + + vec3 vDither = vec3( dot( vec2( 171.0, 231.0 ), ssuv) ); + float dither = fract( vDither.g / 71.0 ) - 0.5; + + if( opacity+dither<0.5 ) + discard; + + FragColor = vec4( 0.0, 1.0, 0.0, 1.0 ); +} diff --git a/shaders/gatelq.h b/shaders/gatelq.h new file mode 100644 index 0000000..0bedde2 --- /dev/null +++ b/shaders/gatelq.h @@ -0,0 +1,96 @@ +#ifndef SHADER_gatelq_H +#define SHADER_gatelq_H +static void shader_gatelq_link(void); +static void shader_gatelq_register(void); +static struct vg_shader _shader_gatelq = { + .name = "gatelq", + .link = shader_gatelq_link, + .vs = +{ +.orig_file = "../shaders/gate.vs", +.static_src = +"layout (location=0) in vec3 a_co;\n" +"layout (location=1) in vec3 a_norm;\n" +"layout (location=2) in vec4 a_colour;\n" +"layout (location=3) in vec2 a_uv;\n" +"\n" +"#line 2 0 \n" +"uniform mat4 uPv;\n" +"uniform mat4x3 uMdl;\n" +"\n" +"out vec3 aNorm;\n" +"out vec2 aUv;\n" +"out vec3 aCo;\n" +"\n" +"void main()\n" +"{\n" +" vec3 world_pos = uMdl * vec4( a_co, 1.0 );\n" +" gl_Position = uPv * vec4(world_pos,1.0);\n" +"\n" +" aNorm = a_norm;\n" +" aCo = world_pos;\n" +" aUv = a_uv;\n" +"}\n" +""}, + .fs = +{ +.orig_file = "../shaders/gate_lq.fs", +.static_src = +"out vec4 FragColor;\n" +"\n" +"uniform float uTime;\n" +"uniform vec3 uCam;\n" +"uniform vec2 uInvRes;\n" +"\n" +"in vec3 aNorm;\n" +"in vec2 aUv;\n" +"in vec3 aCo;\n" +"\n" +"void main()\n" +"{\n" +" vec2 ssuv = gl_FragCoord.xy;\n" +" float opacity = 1.0-smoothstep(0.4,1.0,aUv.y);\n" +" \n" +" vec3 vDither = vec3( dot( vec2( 171.0, 231.0 ), ssuv) );\n" +" float dither = fract( vDither.g / 71.0 ) - 0.5;\n" +"\n" +" if( opacity+dither<0.5 )\n" +" discard;\n" +"\n" +" FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );\n" +"}\n" +""}, +}; + +static GLuint _uniform_gatelq_uPv; +static GLuint _uniform_gatelq_uMdl; +static GLuint _uniform_gatelq_uTime; +static GLuint _uniform_gatelq_uCam; +static GLuint _uniform_gatelq_uInvRes; +static void shader_gatelq_uPv(m4x4f m){ + glUniformMatrix4fv( _uniform_gatelq_uPv, 1, GL_FALSE, (float *)m ); +} +static void shader_gatelq_uMdl(m4x3f m){ + glUniformMatrix4x3fv( _uniform_gatelq_uMdl, 1, GL_FALSE, (float *)m ); +} +static void shader_gatelq_uTime(float f){ + glUniform1f( _uniform_gatelq_uTime, f ); +} +static void shader_gatelq_uCam(v3f v){ + glUniform3fv( _uniform_gatelq_uCam, 1, v ); +} +static void shader_gatelq_uInvRes(v2f v){ + glUniform2fv( _uniform_gatelq_uInvRes, 1, v ); +} +static void shader_gatelq_register(void){ + vg_shader_register( &_shader_gatelq ); +} +static void shader_gatelq_use(void){ glUseProgram(_shader_gatelq.id); } +static void shader_gatelq_link(void){ + _uniform_gatelq_uPv = glGetUniformLocation( _shader_gatelq.id, "uPv" ); + _uniform_gatelq_uMdl = glGetUniformLocation( _shader_gatelq.id, "uMdl" ); + _uniform_gatelq_uTime = glGetUniformLocation( _shader_gatelq.id, "uTime" ); + _uniform_gatelq_uCam = glGetUniformLocation( _shader_gatelq.id, "uCam" ); + _uniform_gatelq_uInvRes = glGetUniformLocation( _shader_gatelq.id, "uInvRes" ); +} +#endif /* SHADER_gatelq_H */ diff --git a/vg.conf b/vg.conf index e383b59..99fc92e 100644 --- a/vg.conf +++ b/vg.conf @@ -7,5 +7,6 @@ shader standard standard.vs standard.fs shader unlit standard.vs unlit.fs shader character character.vs character.fs shader gate gate.vs gate.fs +shader gatelq gate.vs gate_lq.fs shader water water.vs water.fs shader sky standard.vs sky.fs diff --git a/world.h b/world.h index cfa3d6b..7272b80 100644 --- a/world.h +++ b/world.h @@ -10,6 +10,7 @@ #include "water.h" #include "rigidbody.h" #include "gate.h" +#include "bvh.h" #include "shaders/standard.h" @@ -27,12 +28,16 @@ static struct gworld teleport_gate gates[16]; u32 gate_count; - + rigidbody temp_rbs[32]; u32 rb_count; + + bh_tree bhcubes; } world; + + static void render_world( m4x4f projection, m4x3f camera ) { render_sky( camera ); @@ -66,6 +71,7 @@ static int ray_hit_is_ramp( ray_hit *hit ) return hit->tri[0] < world.sm_road.vertex_count; } +static bh_system bh_system_rigidbodies; static void world_load(void) { /* Setup scene */ @@ -157,15 +163,6 @@ static void world_load(void) * * then compute bvh */ -#if 0 - scene_add_foliage( &world.foliage, mworld, boxtest, world.box.to_world ); -#endif - - -#if 0 - submodel *boxtest = submodel_get( mworld, "cubey" ); - -#endif for( int i=0; ilayer_count; i++ ) { @@ -189,7 +186,6 @@ static void world_load(void) rb_update_transform( rb ); } - free( mworld ); v3f volume; @@ -241,6 +237,9 @@ static void world_load(void) free( mfoliage ); scene_upload( &world.foliage ); + + world.bhcubes.user = world.temp_rbs; + bh_create( &world.bhcubes, &bh_system_rigidbodies, world.rb_count ); } #endif /* WORLD_H */