diff options
Diffstat (limited to 'u_ray.c')
-rw-r--r-- | u_ray.c | 257 |
1 files changed, 257 insertions, 0 deletions
@@ -0,0 +1,257 @@ +/* +======================================================================= +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 <http://www.gnu.org/licenses/>. +======================================================================= +*/ + +#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; +} |