{- Raybox.hs; Mun Hon Cheong (mhch295@cse.unsw.edu.au) 2005

This module performs collision tests between AABBs, spheres and rays.

-}

module Raybox where

import Matrix
import Graphics.UI.GLUT

-- tests if a ray intersects a box
rayBox :: (Double,Double,Double) ->  (Double,Double,Double) ->
               (Double,Double,Double) -> (Double,Double,Double) -> Bool
rayBox (rayOx,rayOy,rayOz) (rayDx,rayDy,rayDz) (minx,miny,minz)(maxx,maxy,maxz)
   | (rayOx,rayOy,rayOz) == (rayDx,rayDy,rayDz) = False
   | otherwise =
       case ((txmin > tymax) || (tymin > txmax)) of
          True -> False
          _    -> intersectz
    where (txmin,txmax) = getT rayOx rayDx minx maxx
          (tymin,tymax) = getT rayOy rayDy miny maxy
          (tzmin,tzmax) = getT rayOz rayDz minz maxz
          intersectz    =
             not (((max txmin tymin) > tzmax) || (tzmin > (min txmax tymax)))

getT :: Double ->  Double -> Double -> Double -> (Double, Double)
getT rayO rayD mn mx
   | dd >= 0   = ((mn-rayO)*dd, (mx-rayO)*dd)
   | otherwise = ((mx-rayO)*dd, (mn-rayO)*dd)
   where dd = (1/(rayO-rayD))


-- tests if 2 AABBs intersect
boxBox :: Vec3 -> Vec3 -> Vec3 -> Vec3  -> Bool
boxBox (x1,y1,z1) (w1,h1,d1) (x2,y2,z2) (w2,h2,d2)
   | abs (x1 - x2) <= w1+w2 = True
   | abs (y1 - y2) <= h1+h2 = True
   | abs (z1 - z2) <= d1+d2 = True
   | otherwise = False


-- tests if an AABB intersects a sphere
boxSphere :: Vec3 -> Vec3 -> Vec3 -> GLdouble  -> Bool
boxSphere (x1,y1,z1) (w1,h1,d1) (x2,y2,z2) rad
   | (abs (x1 - x2)) <= (w1+rad) = True
   | (abs (y1 - y2)) <= (h1+rad) = True
   | (abs (z1 - z2)) <= (d1+rad) = True
   | otherwise = False


-- test if two spheres intersect
sphereSphere ::  Vec3 -> Vec3 -> GLdouble -> GLdouble -> Bool
sphereSphere (x1,y1,z1) (x2,y2,z2) rad1 rad2 =
   (sqrt ((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2))+((z1-z2)*(z1-z2))) <= (rad1+rad2)


-- tests if a point lies within a sphere
spherePoint :: Vec3 -> Vec3 -> GLdouble -> Bool
spherePoint (x1,y1,z1) (x2,y2,z2) rad =
   (sqrt $ ((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)) + ((z1-z2)*(z1-z2))) <= rad


-- test if a point lies in an AABB
pointBox :: Vec3 -> Vec3 -> Vec3   -> Bool
pointBox (x1,y1,z1) (x2,y2,z2) (w,h,d)
   | abs (x1 - x2) <= w && abs (y1 - y2) <= h && abs (z1 - z2) <= d = True
   | otherwise = False
