diff options
Diffstat (limited to 'src/game/world/trace.cpp')
| -rw-r--r-- | src/game/world/trace.cpp | 151 |
1 files changed, 129 insertions, 22 deletions
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( |
