summaryrefslogtreecommitdiff
path: root/u_ray.c
diff options
context:
space:
mode:
Diffstat (limited to 'u_ray.c')
-rw-r--r--u_ray.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/u_ray.c b/u_ray.c
new file mode 100644
index 0000000..8473799
--- /dev/null
+++ b/u_ray.c
@@ -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;
+}