diff options
| -rw-r--r-- | assets/maps/test.hmap | 41 | ||||
| -rw-r--r-- | assets/maps/test2.hmap | 100 | ||||
| -rw-r--r-- | assets/maps/test3.hmap | 70 | ||||
| -rw-r--r-- | src/game/physics/movement.cpp | 22 | ||||
| -rw-r--r-- | src/game/world/bsp.cpp | 106 | ||||
| -rw-r--r-- | src/game/world/bsp.h | 35 | ||||
| -rw-r--r-- | src/game/world/trace.cpp | 151 | ||||
| -rw-r--r-- | src/util/aabb.h | 20 | ||||
| -rw-r--r-- | src/util/vector.h | 10 |
9 files changed, 511 insertions, 44 deletions
diff --git a/assets/maps/test.hmap b/assets/maps/test.hmap index df52de5..3d7db93 100644 --- a/assets/maps/test.hmap +++ b/assets/maps/test.hmap @@ -1,9 +1,9 @@ DEF map { I32 wallcount = 7; - I32 polycount = 2; + I32 polycount = 3; I32 propcount = 5; I32 spritecount = 1; - VEC3 startpos = { 84, 109, -39.75 }; + VEC3 startpos = { 124, 42, -39.75 }; F32 startang = 0; DEF props { DEF 0 { @@ -38,7 +38,7 @@ DEF map { } DEF 2 { VEC3 start = { 200, 200, -40 }; - VEC3 end = { 0, 200, 120 }; + VEC3 end = { 83, 200, 120 }; I32 propid = 2; } DEF 3 { @@ -96,22 +96,49 @@ DEF map { I32 type = 0; DEF vertices { DEF 0 { - VEC3 pos = { 188, 187, -7.5 }; + VEC3 pos = { 192, 124, -7.5 }; VEC2 uv = { 1, 0 }; CLR clr = { 1, 1, 1, 1 }; } DEF 1 { - VEC3 pos = { 6, 187, -7.5 }; + VEC3 pos = { 10, 124, -7.5 }; VEC2 uv = { 0, 0 }; CLR clr = { 1, 1, 1, 1 }; } DEF 2 { - VEC3 pos = { 6.79887, 133.711, -40 }; + VEC3 pos = { 10, 70, -40 }; VEC2 uv = { 0, 1 }; CLR clr = { 1, 1, 1, 1 }; } DEF 3 { - VEC3 pos = { 188.102, 133.711, -40 }; + VEC3 pos = { 192, 70, -40 }; + VEC2 uv = { 1, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + } + } + DEF 2 { + I32 vertcount = 4; + I32 propid = 0; + I32 type = 0; + DEF vertices { + DEF 0 { + VEC3 pos = { 192, 169, -40 }; + VEC2 uv = { 1, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 1 { + VEC3 pos = { 10, 169, -40 }; + VEC2 uv = { 0, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 2 { + VEC3 pos = { 10, 124, -7.5 }; + VEC2 uv = { 0, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 3 { + VEC3 pos = { 192, 124, -7.5 }; VEC2 uv = { 1, 1 }; CLR clr = { 1, 1, 1, 1 }; } diff --git a/assets/maps/test2.hmap b/assets/maps/test2.hmap index 69992df..de62787 100644 --- a/assets/maps/test2.hmap +++ b/assets/maps/test2.hmap @@ -1,23 +1,113 @@ DEF map { - I32 wallcount = 1; - I32 polycount = 0; - I32 propcount = 1; + I32 wallcount = 2; + I32 polycount = 3; + I32 propcount = 2; I32 spritecount = 0; - VEC3 startpos = { 10, 10, 0 }; + VEC3 startpos = { 146, 104, 15 }; F32 startang = -0.372549; DEF props { DEF 0 { CLR clr = { 1, 1, 1, 1 }; + STR tex[256] = "uvtest2.png"; + } + DEF 1 { + CLR clr = { 1, 1, 1, 1 }; } } DEF walls { DEF 0 { VEC3 start = { 0, 0, -40 }; - VEC3 end = { 10, 0, 80 }; + VEC3 end = { 545.75, 0, 80 }; + I32 propid = 1; + } + DEF 1 { + VEC3 start = { 219, 408, -40 }; + VEC3 end = { 219, 175, 80 }; I32 propid = 0; } } DEF polygons { + DEF 0 { + I32 vertcount = 4; + I32 propid = 0; + I32 type = 0; + DEF vertices { + DEF 0 { + VEC3 pos = { 545, 467, -40 }; + VEC2 uv = { 1, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 1 { + VEC3 pos = { 0, 467, -40 }; + VEC2 uv = { 0, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 2 { + VEC3 pos = { 0, 1, -40 }; + VEC2 uv = { 0, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 3 { + VEC3 pos = { 545, 1, -40 }; + VEC2 uv = { 1, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + } + } + DEF 1 { + I32 vertcount = 4; + I32 propid = 0; + I32 type = 0; + DEF vertices { + DEF 0 { + VEC3 pos = { 477, 291, 0 }; + VEC2 uv = { 1, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 1 { + VEC3 pos = { 219, 291, 0 }; + VEC2 uv = { 0, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 2 { + VEC3 pos = { 219, 175, -40 }; + VEC2 uv = { 0, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 3 { + VEC3 pos = { 477, 175, -40.25 }; + VEC2 uv = { 1, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + } + } + DEF 2 { + I32 vertcount = 4; + I32 propid = 0; + I32 type = 0; + DEF vertices { + DEF 0 { + VEC3 pos = { 477, 408, -80 }; + VEC2 uv = { 1, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 1 { + VEC3 pos = { 219, 408, -80 }; + VEC2 uv = { 0, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 2 { + VEC3 pos = { 219, 291, 0 }; + VEC2 uv = { 0, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 3 { + VEC3 pos = { 477, 291, 0 }; + VEC2 uv = { 1, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + } + } } DEF sprites { } diff --git a/assets/maps/test3.hmap b/assets/maps/test3.hmap new file mode 100644 index 0000000..e424ead --- /dev/null +++ b/assets/maps/test3.hmap @@ -0,0 +1,70 @@ +DEF map { + I32 wallcount = 4; + I32 polycount = 1; + I32 propcount = 2; + I32 spritecount = 0; + VEC3 startpos = { 246, 199, 0 }; + F32 startang = -0.372549; + DEF props { + DEF 0 { + CLR clr = { 1, 0, 1, 1 }; + } + DEF 1 { + CLR clr = { 1, 1, 1, 1 }; + STR tex[256] = "uvtest2.png"; + } + } + DEF walls { + DEF 0 { + VEC3 start = { 0, 0, -40 }; + VEC3 end = { 512, 0, 80 }; + I32 propid = 0; + } + DEF 1 { + VEC3 start = { 116, 165, -40 }; + VEC3 end = { 116, 293, 80 }; + I32 propid = 0; + } + DEF 2 { + VEC3 start = { 250, 183, -40 }; + VEC3 end = { 160, 96, 80 }; + I32 propid = 0; + } + DEF 3 { + VEC3 start = { 160, 96, -40 }; + VEC3 end = { 80, 96, 80 }; + I32 propid = 0; + } + } + DEF polygons { + DEF 0 { + I32 vertcount = 4; + I32 propid = 1; + I32 type = 0; + DEF vertices { + DEF 0 { + VEC3 pos = { 512, 512, -40 }; + VEC2 uv = { 1, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 1 { + VEC3 pos = { 0, 512, -40 }; + VEC2 uv = { 0, 0 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 2 { + VEC3 pos = { -3.6704, -0.685966, -40 }; + VEC2 uv = { 0, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + DEF 3 { + VEC3 pos = { 512, 0, -40 }; + VEC2 uv = { 1, 1 }; + CLR clr = { 1, 1, 1, 1 }; + } + } + } + } + DEF sprites { + } +} diff --git a/src/game/physics/movement.cpp b/src/game/physics/movement.cpp index 1e2e973..fce9d73 100644 --- a/src/game/physics/movement.cpp +++ b/src/game/physics/movement.cpp @@ -257,7 +257,7 @@ F32 gmove_try_move( BSP_TRACE* t, VEC3* pos, VEC3* vel ) { F32 dot = vec_dot( *vel, t->normal ); *pos += wishmove * t->frac; // nudge player away from wall - *pos += t->normal * BSP_TRACE_EPSILON * 4.f; + *pos += t->normal * BSP_TRACE_EPSILON; // avoid clipping planes twice // in a rare edge case its possible to get stuck in the plane again after pushing away from it @@ -291,7 +291,7 @@ void gmove_check_stuck( VEC3* in_pos ) { gmove->unstuck_vel = { 0, 0, 1.f }; bsp_trace( &t, gmove->bsp, gmove->aabb, pos, pos ); - if( !t.hit ) { + if( !t.hit || !t.startsolid ) { if( vec_len( gmove->velocity ) > 1.f ) { gmove->unstuck_pos = pos; gmove->unstuck_vel = gmove->velocity; @@ -299,6 +299,18 @@ void gmove_check_stuck( VEC3* in_pos ) { return; } + for( U32 i = 0; i < 3; ++i ) { + VEC3 dir = vec3_axis[i]; + VEC3 nudge = pos + dir; + bsp_trace( &t, gmove->bsp, gmove->aabb, pos, nudge ); + if( !t.hit || !t.startsolid ) + return; // not actually stuck, just somewhat inside a solid + + nudge = pos + dir * -1.f; + if( !t.hit || !t.startsolid ) + return; + } + VEC3 p1 = pos; defer( { if( !t.hit ) { @@ -435,14 +447,11 @@ void gmove_step_move( VEC3 dest, BSP_TRACE* tr ) { VEC3 up = pos, down = pos; VEC3 upvel = vel, downvel = vel; - F32 groundn = 0.f; if( gmove->ground ) { VEC3 ground = pos; ground.z += 2.f; bsp_trace( tr, gmove->bsp, gmove->aabb, pos, ground ); - if( tr->hit ) - groundn = tr->normal.z; } // try moving forward first @@ -504,9 +513,6 @@ void gmove_step_move( VEC3 dest, BSP_TRACE* tr ) { gmove->pos += delta; if( tr->normal.z < 0.99f ) gmove->pos += tr->normal * BSP_TRACE_EPSILON * 2.f; - // hack : moving to a steeper slope, move up a bit to avoid getting stuck in the edge - if( gmove->ground && tr->normal.z < groundn ) - gmove->pos.z += BSP_TRACE_EPSILON; gmove->velocity = upvel; gmove->velocity.z = downvel.z; } diff --git a/src/game/world/bsp.cpp b/src/game/world/bsp.cpp index e163d6e..7f72e52 100644 --- a/src/game/world/bsp.cpp +++ b/src/game/world/bsp.cpp @@ -1,6 +1,7 @@ #include "bsp.h" #include "../../util/math.h" #include "map.h" +#include "trace.h" #include <climits> const F32 BSP_PORTAL_PLANE_SIZE = 64000.f; @@ -134,7 +135,6 @@ LIST<BSP_PLANE> bsp_map_get_planes( WORLD_MAP* map ) { return ret; } - LIST<BSP_FACE> bsp_map_faces_from_walls( WORLD_MAP* map ) { LIST<BSP_FACE> ret{}; @@ -168,7 +168,6 @@ LIST<BSP_FACE> bsp_map_faces_from_walls( WORLD_MAP* map ) { f.verts.push( vertices[1] ); f.verts.push( vertices[0] ); f.verts.push( vertices[3] ); - ret.push( f ); }; @@ -417,6 +416,107 @@ I32 bsp_build_nodes( return nidx; } +U8 bsp_edge_is_shared( BSP* bsp, VEC3 edge1a, VEC3 edge1b, VEC3 center, VEC3 ecross, U32 facei ) { + for( U32 i = 0; i < bsp->faces.size; ++i ) { + if( facei == i ) + continue; + + BSP_FACE* other = &bsp->faces[i]; + if( other->verts.size < 3 ) + continue; + + VEC3 otherc{}; + for( U32 vi = 0; vi < other->verts.size; ++vi ) + otherc += other->verts[vi].pos; + otherc /= other->verts.size; + + for( U32 vi = 0; vi < other->verts.size; ++vi ) { + VEC3 edge2a = other->verts[vi].pos; + VEC3 edge2b = other->verts[(vi + 1) % other->verts.size].pos; + + F32 t = BSP_EDGE_TOLERANCE; + U8 match = ( vec_dist( edge1a, edge2a ) < t && vec_dist( edge1b, edge2b ) < t ) || + ( vec_dist( edge1a, edge2b ) < t && vec_dist( edge1b, edge2a ) < t ); + + if( !match ) + continue; + + if( vec_dot( ecross, otherc - edge2a ) < BSP_NORM_EPSILON ) + return 1; + } + } + + return 0; +} + +void bsp_gen_leaf_edges( BSP* bsp, I32 leaf_idx ) { + BSP_LEAF* leaf = &bsp->leaves.data[leaf_idx]; + LIST<BSP_EDGE>* edges = &leaf->edges; + + for( U32 facei = 0; facei < leaf->count; ++facei ) { + U32 faceidx = leaf->first + facei; + BSP_FACE* face = &bsp->faces.data[faceidx]; + + if( face->verts.size < 3 ) + continue; + + VEC3 facen = bsp_face_get_normal( face ); + VEC3 center{}; + for( U32 i = 0; i < face->verts.size; ++i ) + center = center + face->verts.data[i].pos; + center /= face->verts.size; + + for( U32 i = 0; i < face->verts.size; ++i ) { + VEC3 a = face->verts[i].pos; + VEC3 b = face->verts[(i+1) % face->verts.size].pos; + VEC3 edge = b - a; + F32 elen = vec_len( edge ); + if( elen < 0.0001f ) + continue; + edge *= (1.f / elen); + + for( U32 axis = 0; axis < 3; ++axis ) { + VEC3 cross = vec_cross( edge, vec3_axis[axis] ); + F32 clen = vec_len( cross ); + if( clen < 0.001f ) + continue; + cross *= (1.f / clen); + if( vec_dot( cross, center - a ) > 0.f ) + cross *= -1.f; + + if( fabsf( vec_dot( cross, facen ) ) > 0.995f ) + continue; + + if( !bsp_edge_is_shared( bsp, a, b, center, cross, faceidx ) ) + continue; + + F32 d = vec_dot( cross, a ); + BSP_PLANE plane = { cross, d }; + U8 dupe = 0; + for( U32 i = 0; i < edges->size; ++i ) { + if( edges->data[i].plane == plane ) { dupe = 1; break; } + } + + if( dupe ) + continue; + + BSP_EDGE e; + e.plane = plane; + e.face = faceidx; + e.v1 = a; + e.v2 = b; + edges->push( e ); + } + } + } +} + +void bsp_gen_leaf_edges( BSP* bsp ) { + LIST<BSP_EDGE> edges; + for( U32 i = 0; i < bsp->leaves.size; ++i ) + bsp_gen_leaf_edges( bsp, i ); +} + inline void bsp_plane_basis( const VEC3& norm, VEC3* u, VEC3* v ) { VEC3 a = fabsf( norm.x ) > 0.9f ? VEC3{ 0, 1, 0 } : VEC3{ 1, 0, 0 }; *u = vec_normalize( vec_cross( a, norm ) ); @@ -725,8 +825,10 @@ BSP* bsp_build_map( WORLD_MAP* m ) { bsp->root = bsp_build_nodes( bsp, planes, faces, 0 ); for( U32 i = 0; i < bsp->faces.size; ++i ) { + bsp_face_calc_extents( &bsp->faces.data[i] ); bsp->faces.data[i].id = i; } + bsp_gen_leaf_edges( bsp ); bsp_gen_render_vertices( bsp ); bsp_build_portals( bsp ); diff --git a/src/game/world/bsp.h b/src/game/world/bsp.h index 457bcb9..8892108 100644 --- a/src/game/world/bsp.h +++ b/src/game/world/bsp.h @@ -30,6 +30,8 @@ struct BSP_FACE { I32 id; LIST<MAP_VERTEX> verts{}; LIST<VERTEX3D> render_verts{}; + VEC3 mins; + VEC3 maxs; }; struct BSP_NODE { @@ -38,10 +40,19 @@ struct BSP_NODE { I32 back; }; +struct BSP_EDGE { + BSP_PLANE plane; + U32 face; + + VEC3 v1, v2; +}; + struct BSP_LEAF { U32 first; U32 count; I32 cluster; + + LIST<BSP_EDGE> edges; }; struct BSP_WINDING { @@ -106,3 +117,27 @@ inline SURF_PROPS* bsp_face_get_props( WORLD_MAP* w, BSP_FACE* s ) { map_props_get_special( w, s->propid ) : &w->props[s->propid]; } + +inline VEC3 bsp_face_get_normal( BSP_FACE* f ){ + VEC3 v0 = f->verts.data[0].pos; + VEC3 v1 = f->verts.data[1].pos; + VEC3 v2 = f->verts.data[2].pos; + return vec_normalize( vec_cross( v1 - v0, v2 - v0 ) ); +} + +inline void bsp_face_calc_extents( BSP_FACE* f ) { + VEC3 mins{ +INFINITY, +INFINITY, +INFINITY }, maxs{ -INFINITY, -INFINITY, -INFINITY }; + for( U32 i = 0; i < f->verts.size; ++i ) { + VEC3 v = f->verts.data[i].pos; + mins.x = min( mins.x, v.x ); + mins.y = min( mins.y, v.y ); + mins.z = min( mins.z, v.z ); + + maxs.x = max( maxs.x, v.x ); + maxs.y = max( maxs.y, v.y ); + maxs.z = max( maxs.z, v.z ); + } + + f->mins = mins; + f->maxs = maxs; +} diff --git a/src/game/world/trace.cpp b/src/game/world/trace.cpp index 3548fa8..1d32afe 100644 --- a/src/game/world/trace.cpp +++ b/src/game/world/trace.cpp @@ -1,6 +1,7 @@ #include "trace.h" #include "../../util/math.h" #include "bsp.h" +#include "map.h" // i have no idea how this works tbh i pasted this // todo : backface culling (return 0 if d < BSP_TRACE_EPSILON) @@ -172,12 +173,7 @@ U8 bsp_trace( BSP_TRACE* trace, BSP* bsp ) { return bsp_trace_segment( trace, bsp, bsp->root, start, end ); } -inline VEC3 bsp_face_get_normal( const BSP_FACE* f ){ - const VEC3 v0 = f->verts.data[0].pos; - const VEC3 v1 = f->verts.data[1].pos; - const VEC3 v2 = f->verts.data[2].pos; - return vec_normalize( vec_cross( v1 - v0, v2 - v0 ) ); -} + inline U8 point_in_inflated_poly( const VEC3& point, @@ -194,9 +190,10 @@ inline U8 point_in_inflated_poly( for( U32 i = 0; i < c; ++i ) { VEC3 a = face->verts.data[i].pos; VEC3 b = face->verts.data[(i+1)%c].pos; - VEC3 in = vec_cross( norm, b - a ); + VEC3 e = b - a; + VEC3 in = vec_cross( norm, e ); F32 len = vec_len( in ); - if( len <= 0.00001f ) continue; + if( len <= 0.0001f ) continue; in *= (1.0f/ len); if( vec_dot( center - a, in ) < 0.0f ) in = in * -1.0f; @@ -205,6 +202,13 @@ inline U8 point_in_inflated_poly( F32 expand = aabb_support_radius( hull, in ); if( dist < -( expand - BSP_EDGE_TOLERANCE ) ) return 0; + + // check if plane is aligned to any hull edge in x/y plane + if( fabsf( norm.x ) >= BSP_TRACE_EPSILON && fabsf( norm.y ) >= BSP_TRACE_EPSILON ) { + // for non-axis-aligned faces the point of contact is infinitely thin + if( dist < BSP_EDGE_TOLERANCE ) + return 0; + } } return 1; } @@ -222,20 +226,30 @@ U8 bsp_trace_sweep_aabb_to_face( if( face->verts.size < 3 ) return 0; - VEC3 norm = bsp_face_get_normal( face ); - F32 d = vec_dot( norm, face->verts[0].pos ); - F32 radius = aabb_support_radius( hull, norm ); + VEC3 hullv = hull.max - hull.min; + AABB fhull = { face->mins - hullv, face->maxs + hullv }; + AABB fhullh = { face->mins - hullv * 0.5f, face->maxs + hullv * 0.5f }; + VEC3 norm = bsp_face_get_normal( face ); + F32 d = vec_dot( norm, face->verts[0].pos ); + F32 radius = aabb_support_radius( hull, norm ); - VEC3 dir = end - start; + VEC3 dir = trace->in_end - trace->in_start; F32 s0 = vec_dot( norm, trace->in_start ) - d; - F32 ndir = vec_dot( norm, trace->in_end - trace->in_start ); + F32 ndir = vec_dot( norm, dir ); + + F32 tdot = vec_dot( dir, norm ); + if( tdot >= 0 ) // dont collide with rear side + return 0; if( fabsf( s0 ) <= radius + BSP_TRACE_EPSILON ) { - if( point_in_inflated_poly( start, face, hull, norm ) ) { + if( aabb_contains_point( fhullh, start ) && point_in_inflated_poly( start, face, hull, norm ) ) { trace->hit = 1; trace->frac = 0.f; trace->startsolid = 1; trace->point = start; + trace->point.x = m_clamp( trace->point.x, fhullh.min.x, fhullh.max.x ); + trace->point.y = m_clamp( trace->point.y, fhullh.min.y, fhullh.max.y ); + trace->point.z = m_clamp( trace->point.z, fhullh.min.z, fhullh.max.z ); trace->normal = norm; trace->propid = face->propid; trace->faceid = face_idx; @@ -243,22 +257,25 @@ U8 bsp_trace_sweep_aabb_to_face( } } - if( ndir > BSP_TRACE_EPSILON ) - return 0; - F32 t_enter = (-radius - s0) / ndir; F32 t_exit = ( radius - s0) / ndir; if( t_enter > t_exit ) { F32 tmp=t_enter; t_enter=t_exit; t_exit=tmp; } - if( t_exit < 0.f - BSP_TRACE_EPSILON || t_enter > 1.f + BSP_TRACE_EPSILON ) return 0; F32 t = m_clamp( t_enter, 0.f, 1.f ); - VEC3 step = start + dir * t; + VEC3 step = trace->in_start + dir * t; + + if( !aabb_contains_point( fhull, step ) ) + return 0; if( !point_in_inflated_poly( step, face, hull, norm ) ) return 0; + step.x = m_clamp( step.x, fhullh.min.x, fhullh.max.x ); + step.y = m_clamp( step.y, fhullh.min.y, fhullh.max.y ); + step.z = m_clamp( step.z, fhullh.min.z, fhullh.max.z ); + trace->hit = 1; trace->frac = t; trace->point = step; @@ -268,6 +285,84 @@ U8 bsp_trace_sweep_aabb_to_face( return 1; } +U8 bsp_trace_sweep_aabb_to_leaf_edges( + BSP* bsp, + BSP_TRACE* trace, + const AABB& hull, + const VEC3& start, + const VEC3& end, + I32 leaf_idx, + F32* in_best +) { + BSP_LEAF* leaf = &bsp->leaves.data[leaf_idx]; + U8 hit = 0; + F32 best = *in_best; + + BSP_TRACE besthit = *trace; + for( U32 i = 0; i < leaf->edges.size; ++i ) { + BSP_EDGE* e = &leaf->edges[i]; + BSP_FACE* f = &bsp->faces.data[e->face]; + + if( f->propid == MAPPROP_SKYBOX ) + continue; + + VEC3 n = e->plane.normal; + F32 d = e->plane.dist; + F32 r = aabb_support_radius( hull, n ); + + F32 s0 = vec_dot( n, start ) - d; + F32 ndir = vec_dot( n, end - start ); + + if( ndir >= 0.f ) continue; + if( s0 < -(r + BSP_TRACE_EPSILON) ) continue; + + F32 t_enter = ( r - s0) / ndir; + F32 t_exit = (-r - s0) / ndir; + if( t_enter > t_exit ) { F32 tmp = t_enter; t_enter = t_exit; t_exit = tmp; } + + if( t_exit < -BSP_TRACE_EPSILON || t_enter > 1.f + BSP_TRACE_EPSILON ) + continue; + + F32 t = m_clamp( t_enter, 0.f, 1.f ); + VEC3 step = start + (end - start) * t; + + VEC3 edir = e->v2 - e->v1; + F32 elen = vec_len( edir ); + if( elen < 0.001f ) + continue; + edir *= (1.f / elen); + + F32 along = vec_dot( step - e->v1, edir ); + VEC3 proj = e->v1 + edir * m_clamp( along, 0.f, elen ); + F32 dist = vec_dist( proj, step ); + + F32 expand = aabb_support_radius( hull, n ); + if( dist > BSP_TRACE_EPSILON ) { + if( dist > expand - BSP_EDGE_TOLERANCE ) + continue; + } + + if( t < best ) { + best = t; + *in_best = best; + besthit.frac = t; + besthit.point = step; + besthit.normal = n; + besthit.propid = f->propid; + besthit.faceid = e->face; + besthit.leafid = leaf_idx; + hit = 1; + } + } + + if( hit ) { + *trace = besthit; + trace->hit = 1; + } + + return hit; +} + U8 bsp_trace_sweep_aabb_to_leaf( BSP* bsp, BSP_TRACE* trace, @@ -281,6 +376,7 @@ U8 bsp_trace_sweep_aabb_to_leaf( F32 best = FLT_MAX; BSP_TRACE besthit = *trace; + BSP_TRACE edgehit = *trace; for( U32 i = 0; i < leaf->count; ++i ) { U32 face_idx = leaf->first + i; @@ -301,11 +397,22 @@ U8 bsp_trace_sweep_aabb_to_leaf( } } - if( hit ) { - *trace = besthit; + U8 ehit = bsp_trace_sweep_aabb_to_leaf_edges( bsp, &edgehit, hull, start, end, leaf_idx, &best ); + + if( hit || ehit ) { + if( ehit && !hit ) + *trace = edgehit; + else if( !ehit && hit ) + *trace = besthit; + else if( edgehit.frac < besthit.frac ) + *trace = edgehit; + else + *trace = besthit; trace->hit = 1; + return 1; } - return hit; + + return 0; } U8 bsp_trace_sweep_aabb( diff --git a/src/util/aabb.h b/src/util/aabb.h index 96e40bf..9dc4b20 100644 --- a/src/util/aabb.h +++ b/src/util/aabb.h @@ -13,3 +13,23 @@ inline F32 aabb_support_radius( const AABB& aabb, const VEC3& dir ) { VEC3 half = aabb_half( aabb ); return fabsf(dir.x) * half.x + fabsf(dir.y) * half.y + fabsf(dir.z) * half.z; } + +inline U8 aabb_intersects( const AABB& aabb, const AABB& other ) { + if (aabb.min.x > other.max.x || aabb.max.x < other.min.x) + return 0; + if (aabb.min.y > other.max.y || aabb.max.y < other.min.y) + return 0; + if (aabb.min.z > other.max.z || aabb.max.z < other.min.z) + return 0; + return 1; +} + +inline U8 aabb_contains_point( const AABB& aabb, const VEC3& point ) { + if (point.x < aabb.min.x || point.x > aabb.max.x) + return 0; + if (point.y < aabb.min.y || point.y > aabb.max.y) + return 0; + if (point.z < aabb.min.z || point.z > aabb.max.z) + return 0; + return 1; +} diff --git a/src/util/vector.h b/src/util/vector.h index 6065343..a01689c 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -55,6 +55,7 @@ struct VEC3 { VEC3( const VEC2& v ) { x = v.x; y = v.y; z = 0.f; } bool operator==( const VEC3& v ) const { return ( x == v.x && y == v.y && z == v.z ); } + bool operator!=( const VEC3& v ) const { return !( x == v.x && y == v.y && z == v.z ); } VEC3& operator=( const VEC3& v ) { x = v.x; y = v.y; z = v.z; return *this; } F32& operator[]( I32 i ) { return ( (F32*)this )[i]; } F32 operator[]( I32 i ) const { return ( (F32*)this )[i]; } @@ -119,6 +120,15 @@ struct VEC4 { VEC4 operator/( const F32& v ) { return VEC4( x / v, y / v, z / v, w / v ); } }; +static const VEC2 vec2_right = { 1.f, 0.f }; +static const VEC2 vec2_forward = { 0.f, 1.f }; +static const VEC2 vec2_axis[] = { vec2_right, vec2_forward }; + +static const VEC3 vec3_up = { 0.f, 0.f, 1.f }; +static const VEC3 vec3_right = { 1.f, 0.f, 0.f }; +static const VEC3 vec3_forward = { 0.f, 1.f, 0.f }; +static const VEC3 vec3_axis[] = { vec3_right, vec3_forward, vec3_up }; + inline U8 is_zero( VEC2 v ) { return v.x == 0.f && v.y == 0.f; } inline U8 is_zero( VEC3 v ) { return v.x == 0.f && v.y == 0.f && v.z == 0.f; } inline U8 is_zero( VEC4 v ) { return v.x == 0.f && v.y == 0.f && v.z == 0.f && v.w == 0.f; } |
