/* ======================================================================= This file is part of Redman's RT. Redman's RT is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Redman's RT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Redman's RT. If not, see . ======================================================================= */ #include "common.h" void U_BuildRay( const vec3_t org, const vec3_t dir, vec_t limit, ray_t *ray, rtres_t *rt ) { size_t i; if( org ) V3Copy( ray->org, org ); if( dir ) V3Copy( ray->dir, dir ); for( i = 0; i < 3; i++ ) ray->dinv[ i ] = 1.0 / ray->dir[ i ]; for( i = 0; i < 3; i++ ) ray->dinvsign[ i ] = ( ray->dinv[ i ] < 0 ); for( i = 0; i < 3; i++ ) ray->dsign[ i ] = ( ray->dir[ i ] >= 0.0 ? 1 : 0 ); for( i = 0; i < 3; i++ ) ray->dsign2[ i ] = ( ray->dir[ i ] <= 0.0 ? 1 : -1 ); #define ORDER( a, b, c, d, e, f, g, h ) \ ray->otorder[ 0 ] = a; \ ray->otorder[ 1 ] = b; \ ray->otorder[ 2 ] = c; \ ray->otorder[ 3 ] = d; \ ray->otorder[ 4 ] = e; \ ray->otorder[ 5 ] = f; \ ray->otorder[ 6 ] = g; \ ray->otorder[ 7 ] = h; switch( ray->dsign[ 0 ] | ray->dsign[ 1 ] << 1 | ray->dsign[ 2 ] << 2 ) { case 0: // nnn ORDER( 7, 5, 6, 3, 4, 1, 2, 0 ); break; case 1: // pnn ORDER( 6, 4, 7, 2, 5, 0, 3, 1 ); break; case 2: // npn ORDER( 5, 4, 7, 1, 6, 0, 3, 2 ); break; case 3: // ppn ORDER( 4, 5, 6, 0, 7, 1, 2, 3 ); break; case 4: // nnp ORDER( 3, 1, 2, 7, 5, 0, 6, 4 ); break; case 5: // pnp ORDER( 2, 0, 3, 6, 4, 7, 1, 5 ); break; case 6: // npp ORDER( 1, 0, 3, 5, 4, 7, 2, 6 ); break; case 7: // ppp ORDER( 0, 1, 2, 4, 5, 6, 3, 7 ); break; } ray->limit = limit; V3Copy( ray->aabb[ 0 ], ray->org ); V3MA( ray->aabb[ 1 ], ray->org, limit, ray->dir ); for( i = 0; i < 3; i++ ) if( ray->aabb[ 0 ][ i ] > ray->aabb[ 1 ][ i ] ) Swap( vec_t, ray->aabb[ 0 ][ i ], ray->aabb[ 1 ][ i ] ); if( rt ) memset( rt, 0, sizeof( rtres_t ) ); } bool_t U_PointInAABB2( const vec3_t point, const vec3_t *aabb ) { return ( point[ 0 ] > aabb[ 0 ][ 0 ] && point[ 1 ] > aabb[ 0 ][ 1 ] && point[ 2 ] > aabb[ 0 ][ 2 ] && point[ 0 ] < aabb[ 1 ][ 0 ] && point[ 1 ] < aabb[ 1 ][ 1 ] && point[ 2 ] < aabb[ 1 ][ 2 ] ); } bool_t U_PointInAABB( const vec3_t point, const vec3_t *aabb ) { return ( point[ 0 ] >= aabb[ 0 ][ 0 ] && point[ 1 ] >= aabb[ 0 ][ 1 ] && point[ 2 ] >= aabb[ 0 ][ 2 ] && point[ 0 ] <= aabb[ 1 ][ 0 ] && point[ 1 ] <= aabb[ 1 ][ 1 ] && point[ 2 ] <= aabb[ 1 ][ 2 ] ); } //based upon ioquake3's BoundsIntersect bool_t U_AABBIntersect( const vec3_t a[ 2 ], const vec3_t b[ 2 ] ) { if( a[ 1 ][ 0 ] < b[ 0 ][ 0 ] || a[ 1 ][ 1 ] < b[ 0 ][ 1 ] || a[ 1 ][ 2 ] < b[ 0 ][ 2 ] || a[ 0 ][ 0 ] > b[ 1 ][ 0 ] || a[ 0 ][ 1 ] > b[ 1 ][ 1 ] || a[ 0 ][ 2 ] > b[ 1 ][ 2 ] ) return false; return true; } bool_t U_RT_Zplane( vec_t z, const ray_t *ray, rtres_t *rt ) { vec_t dz; if( ray->dinvsign[ 2 ] || ray->org[ 2 ] > z ) return false; dz = z - ray->org[ 2 ]; rt->hit[ 0 ] = ray->org[ 0 ] + ray->dir[ 0 ] * ray->dinv[ 2 ] * dz; rt->hit[ 1 ] = ray->org[ 1 ] + ray->dir[ 1 ] * ray->dinv[ 2 ] * dz; rt->hit[ 2 ] = z; V3Set( rt->normal, 0, 0, -1 ); return true; } //all the ray-box intersection code is based upon the paper: // Amy Williams, Steve Barrus, R. Keith Morley, and Peter Shirley // "An Efficient and Robust Ray-Box Intersection Algorithm" // Journal of graphics tools, 10(1):49-54, 2005 bool_t U_RT_AABB_Fast( const vec3_t const *aabb, const ray_t *ray, rtres_t *rt ) { vec_t tn, tp, tyn, typ, tzn, tzp; //if( !U_AABBIntersect( ray->aabb, aabb ) ) // return false; if( U_PointInAABB( ray->org, aabb ) ) return true; tn = ( aabb[ ray->dinvsign[ 0 ] ][ 0 ] - ray->org[ 0 ] ) * ray->dinv[ 0 ]; tp = ( aabb[ 1 - ray->dinvsign[ 0 ] ][ 0 ] - ray->org[ 0 ] ) * ray->dinv[ 0 ]; tyn = ( aabb[ ray->dinvsign[ 1 ] ][ 1 ] - ray->org[ 1 ] ) * ray->dinv[ 1 ]; typ = ( aabb[ 1 - ray->dinvsign[ 1 ] ][ 1 ] - ray->org[ 1 ] ) * ray->dinv[ 1 ]; if( ( tn > typ ) || ( tyn > tp ) ) return false; if( tyn > tn ) tn = tyn; if( typ < tp ) tp = typ; tzn = ( aabb[ ray->dinvsign[ 2 ] ][ 2 ] - ray->org[ 2 ] ) * ray->dinv[ 2 ]; tzp = ( aabb[ 1 - ray->dinvsign[ 2 ] ][ 2 ] - ray->org[ 2 ] ) * ray->dinv[ 2 ]; if( ( tn > tzp ) || ( tzn > tp ) ) return false; if( tzn > tn ) tn = tzn; if( tzp < tp ) tp = tzp; rt->dist = tn; return tn > 0; } bool_t U_RT_AABB( const vec3_t const *aabb, const ray_t *ray, rtres_t *rt ) { vec_t tn, tp, tyn, typ, tzn, tzp; if( !U_AABBIntersect( ray->aabb, aabb ) ) return false; if( U_PointInAABB( ray->org, aabb ) ) return true; tn = ( aabb[ ray->dinvsign[ 0 ] ][ 0 ] - ray->org[ 0 ] ) * ray->dinv[ 0 ]; tp = ( aabb[ 1 - ray->dinvsign[ 0 ] ][ 0 ] - ray->org[ 0 ] ) * ray->dinv[ 0 ]; tyn = ( aabb[ ray->dinvsign[ 1 ] ][ 1 ] - ray->org[ 1 ] ) * ray->dinv[ 1 ]; typ = ( aabb[ 1 - ray->dinvsign[ 1 ] ][ 1 ] - ray->org[ 1 ] ) * ray->dinv[ 1 ]; V3Set( rt->normal, ray->dsign2[ 0 ], 0, 0 ); if( ( tn > typ ) || ( tyn > tp ) ) return false; if( tyn > tn ) tn = tyn, V3Set( rt->normal, 0, ray->dsign2[ 1 ], 0 ); if( typ < tp ) tp = typ; tzn = ( aabb[ ray->dinvsign[ 2 ] ][ 2 ] - ray->org[ 2 ] ) * ray->dinv[ 2 ]; tzp = ( aabb[ 1 - ray->dinvsign[ 2 ] ][ 2 ] - ray->org[ 2 ] ) * ray->dinv[ 2 ]; if( ( tn > tzp ) || ( tzn > tp ) ) return false; if( tzn > tn ) tn = tzn, V3Set( rt->normal, 0, 0, ray->dsign2[ 2 ] ); if( tzp < tp ) tp = tzp; rt->dist = tn; return tn > 0; }