packages feed

GlomeVec 0.1.1 → 0.1.2

raw patch · 5 files changed

+867/−867 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.GlomeTexture: gamma :: Int -> Int -> Int -> Vec
- Data.GlomeTexture: grad :: Array Int Vec
- Data.GlomeTexture: intGamma :: Int -> Int -> Int
- Data.GlomeTexture: knot :: Int -> Int -> Int -> Vec -> Flt
- Data.GlomeTexture: lump_wave :: Flt -> Flt
- Data.GlomeTexture: noise :: Vec -> Flt
- Data.GlomeTexture: omega :: Flt -> Flt
- Data.GlomeTexture: perlin :: Vec -> Flt
- Data.GlomeTexture: perlin_turb :: Vec -> Int -> Flt
- Data.GlomeTexture: phi :: Array Int Int
- Data.GlomeTexture: sine_wave :: Flt -> Flt
- Data.GlomeTexture: square_wave :: Flt -> Flt
- Data.GlomeTexture: stripe :: Vec -> (Flt -> Flt) -> (Vec -> Flt)
- Data.GlomeTexture: triangle_wave :: Flt -> Flt
- Data.GlomeTexture: turbulence :: Vec -> Int -> Flt
- Data.GlomeVec: Bbox :: !Vec -> !Vec -> Bbox
- Data.GlomeVec: Interval :: !Flt -> !Flt -> Interval
- Data.GlomeVec: Matrix :: !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> Matrix
- Data.GlomeVec: Ray :: !Vec -> !Vec -> Ray
- Data.GlomeVec: Vec :: !Flt -> !Flt -> !Flt -> Vec
- Data.GlomeVec: Xfm :: Matrix -> Matrix -> Xfm
- Data.GlomeVec: about_equal :: Flt -> Flt -> Bool
- Data.GlomeVec: assert_norm :: Vec -> Vec
- Data.GlomeVec: bbclip :: Ray -> Bbox -> Interval
- Data.GlomeVec: bbinside :: Bbox -> Vec -> Bool
- Data.GlomeVec: bbjoin :: Bbox -> Bbox -> Bbox
- Data.GlomeVec: bboverlap :: Bbox -> Bbox -> Bbox
- Data.GlomeVec: bbpts :: [Vec] -> Bbox
- Data.GlomeVec: bbsa :: Bbox -> Flt
- Data.GlomeVec: bbsplit :: Bbox -> Int -> Flt -> (Bbox, Bbox)
- Data.GlomeVec: bbvol :: Bbox -> Flt
- Data.GlomeVec: bisect :: Vec -> Vec -> Vec
- Data.GlomeVec: check_xfm :: Xfm -> Xfm
- Data.GlomeVec: clamp :: Flt -> Flt -> Flt -> Flt
- Data.GlomeVec: compose :: [Xfm] -> Xfm
- Data.GlomeVec: data Bbox
- Data.GlomeVec: data Interval
- Data.GlomeVec: data Matrix
- Data.GlomeVec: data Ray
- Data.GlomeVec: data Vec
- Data.GlomeVec: data Xfm
- Data.GlomeVec: dcos :: Flt -> Flt
- Data.GlomeVec: deg :: Flt -> Flt
- Data.GlomeVec: dir :: Ray -> !Vec
- Data.GlomeVec: empty_bbox :: Bbox
- Data.GlomeVec: everything_bbox :: Bbox
- Data.GlomeVec: fabs :: Flt -> Flt
- Data.GlomeVec: fmax :: Flt -> Flt -> Flt
- Data.GlomeVec: fmax3 :: Flt -> Flt -> Flt -> Flt
- Data.GlomeVec: fmax4 :: Flt -> Flt -> Flt -> Flt -> Flt
- Data.GlomeVec: fmin :: Flt -> Flt -> Flt
- Data.GlomeVec: fmin3 :: Flt -> Flt -> Flt -> Flt
- Data.GlomeVec: fmin4 :: Flt -> Flt -> Flt -> Flt -> Flt
- Data.GlomeVec: iabs :: Int -> Int
- Data.GlomeVec: ident_matrix :: Matrix
- Data.GlomeVec: ident_xfm :: Xfm
- Data.GlomeVec: infinity :: Flt
- Data.GlomeVec: instance Show Bbox
- Data.GlomeVec: instance Show Interval
- Data.GlomeVec: instance Show Matrix
- Data.GlomeVec: instance Show Ray
- Data.GlomeVec: instance Show Vec
- Data.GlomeVec: instance Show Xfm
- Data.GlomeVec: invxfm_norm :: Xfm -> Vec -> Vec
- Data.GlomeVec: invxfm_point :: Xfm -> Vec -> Vec
- Data.GlomeVec: invxfm_ray :: Xfm -> Ray -> Ray
- Data.GlomeVec: invxfm_vec :: Xfm -> Vec -> Vec
- Data.GlomeVec: mat_mult :: Matrix -> Matrix -> Matrix
- Data.GlomeVec: nvx :: Vec
- Data.GlomeVec: nvy :: Vec
- Data.GlomeVec: nvz :: Vec
- Data.GlomeVec: origin :: Ray -> !Vec
- Data.GlomeVec: orth :: Vec -> (Vec, Vec)
- Data.GlomeVec: p1 :: Bbox -> !Vec
- Data.GlomeVec: p2 :: Bbox -> !Vec
- Data.GlomeVec: plane_int :: Ray -> Vec -> Vec -> Vec
- Data.GlomeVec: plane_int_dist :: Ray -> Vec -> Vec -> Flt
- Data.GlomeVec: rad :: Flt -> Flt
- Data.GlomeVec: ray_move :: Ray -> Flt -> Ray
- Data.GlomeVec: reflect :: Vec -> Vec -> Vec
- Data.GlomeVec: rot :: Flt -> Flt
- Data.GlomeVec: rotate :: Vec -> Flt -> Xfm
- Data.GlomeVec: sas2s :: Flt -> Flt -> Flt -> Flt
- Data.GlomeVec: scale :: Vec -> Xfm
- Data.GlomeVec: translate :: Vec -> Xfm
- Data.GlomeVec: type Flt = Double
- Data.GlomeVec: uvw_to_xyz :: Vec -> Vec -> Vec -> Xfm
- Data.GlomeVec: va :: Vec -> Int -> Flt
- Data.GlomeVec: vadd :: Vec -> Vec -> Vec
- Data.GlomeVec: vadd3 :: Vec -> Vec -> Vec -> Vec
- Data.GlomeVec: vcross :: Vec -> Vec -> Vec
- Data.GlomeVec: vdec :: Vec -> Flt -> Vec
- Data.GlomeVec: vdist :: Vec -> Vec -> Flt
- Data.GlomeVec: vdot :: Vec -> Vec -> Flt
- Data.GlomeVec: vec :: Flt -> Flt -> Flt -> Vec
- Data.GlomeVec: veq :: Vec -> Vec -> Bool
- Data.GlomeVec: veqsign :: Vec -> Vec -> Bool
- Data.GlomeVec: vinc :: Vec -> Flt -> Vec
- Data.GlomeVec: vinvert :: Vec -> Vec
- Data.GlomeVec: vlen :: Vec -> Flt
- Data.GlomeVec: vlensqr :: Vec -> Flt
- Data.GlomeVec: vmap :: (Flt -> Flt) -> Vec -> Vec
- Data.GlomeVec: vmap2 :: (Flt -> Flt -> Flt) -> Vec -> Vec -> Vec
- Data.GlomeVec: vmax :: Vec -> Vec -> Vec
- Data.GlomeVec: vmaxaxis :: Vec -> Int
- Data.GlomeVec: vmin :: Vec -> Vec -> Vec
- Data.GlomeVec: vmul :: Vec -> Vec -> Vec
- Data.GlomeVec: vnorm :: Vec -> Vec
- Data.GlomeVec: vnudge :: Vec -> Vec
- Data.GlomeVec: vrcp :: Vec -> Vec
- Data.GlomeVec: vrotate :: Vec -> Ray -> Flt -> Vec
- Data.GlomeVec: vscale :: Vec -> Flt -> Vec
- Data.GlomeVec: vscaleadd :: Vec -> Vec -> Flt -> Vec
- Data.GlomeVec: vset :: Vec -> Int -> Flt -> Vec
- Data.GlomeVec: vsub :: Vec -> Vec -> Vec
- Data.GlomeVec: vunit :: Vec
- Data.GlomeVec: vx :: Vec
- Data.GlomeVec: vy :: Vec
- Data.GlomeVec: vz :: Vec
- Data.GlomeVec: vzero :: Vec
- Data.GlomeVec: x :: Vec -> Flt
- Data.GlomeVec: xfm_mult :: Xfm -> Xfm -> Xfm
- Data.GlomeVec: xfm_point :: Xfm -> Vec -> Vec
- Data.GlomeVec: xfm_ray :: Xfm -> Ray -> Ray
- Data.GlomeVec: xfm_vec :: Xfm -> Vec -> Vec
- Data.GlomeVec: xyz_to_uvw :: Vec -> Vec -> Vec -> Xfm
- Data.GlomeVec: y :: Vec -> Flt
- Data.GlomeVec: z :: Vec -> Flt
+ Data.Glome.Texture: gamma :: Int -> Int -> Int -> Vec
+ Data.Glome.Texture: grad :: Array Int Vec
+ Data.Glome.Texture: intGamma :: Int -> Int -> Int
+ Data.Glome.Texture: knot :: Int -> Int -> Int -> Vec -> Flt
+ Data.Glome.Texture: lump_wave :: Flt -> Flt
+ Data.Glome.Texture: noise :: Vec -> Flt
+ Data.Glome.Texture: omega :: Flt -> Flt
+ Data.Glome.Texture: perlin :: Vec -> Flt
+ Data.Glome.Texture: perlin_turb :: Vec -> Int -> Flt
+ Data.Glome.Texture: phi :: Array Int Int
+ Data.Glome.Texture: sine_wave :: Flt -> Flt
+ Data.Glome.Texture: square_wave :: Flt -> Flt
+ Data.Glome.Texture: stripe :: Vec -> (Flt -> Flt) -> (Vec -> Flt)
+ Data.Glome.Texture: triangle_wave :: Flt -> Flt
+ Data.Glome.Texture: turbulence :: Vec -> Int -> Flt
+ Data.Glome.Vec: Bbox :: !Vec -> !Vec -> Bbox
+ Data.Glome.Vec: Interval :: !Flt -> !Flt -> Interval
+ Data.Glome.Vec: Matrix :: !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> !Flt -> Matrix
+ Data.Glome.Vec: Ray :: !Vec -> !Vec -> Ray
+ Data.Glome.Vec: Vec :: !Flt -> !Flt -> !Flt -> Vec
+ Data.Glome.Vec: Xfm :: Matrix -> Matrix -> Xfm
+ Data.Glome.Vec: about_equal :: Flt -> Flt -> Bool
+ Data.Glome.Vec: assert_norm :: Vec -> Vec
+ Data.Glome.Vec: bbclip :: Ray -> Bbox -> Interval
+ Data.Glome.Vec: bbinside :: Bbox -> Vec -> Bool
+ Data.Glome.Vec: bbjoin :: Bbox -> Bbox -> Bbox
+ Data.Glome.Vec: bboverlap :: Bbox -> Bbox -> Bbox
+ Data.Glome.Vec: bbpts :: [Vec] -> Bbox
+ Data.Glome.Vec: bbsa :: Bbox -> Flt
+ Data.Glome.Vec: bbsplit :: Bbox -> Int -> Flt -> (Bbox, Bbox)
+ Data.Glome.Vec: bbvol :: Bbox -> Flt
+ Data.Glome.Vec: bisect :: Vec -> Vec -> Vec
+ Data.Glome.Vec: check_xfm :: Xfm -> Xfm
+ Data.Glome.Vec: clamp :: Flt -> Flt -> Flt -> Flt
+ Data.Glome.Vec: compose :: [Xfm] -> Xfm
+ Data.Glome.Vec: data Bbox
+ Data.Glome.Vec: data Interval
+ Data.Glome.Vec: data Matrix
+ Data.Glome.Vec: data Ray
+ Data.Glome.Vec: data Vec
+ Data.Glome.Vec: data Xfm
+ Data.Glome.Vec: dcos :: Flt -> Flt
+ Data.Glome.Vec: deg :: Flt -> Flt
+ Data.Glome.Vec: dir :: Ray -> !Vec
+ Data.Glome.Vec: empty_bbox :: Bbox
+ Data.Glome.Vec: everything_bbox :: Bbox
+ Data.Glome.Vec: fabs :: Flt -> Flt
+ Data.Glome.Vec: fmax :: Flt -> Flt -> Flt
+ Data.Glome.Vec: fmax3 :: Flt -> Flt -> Flt -> Flt
+ Data.Glome.Vec: fmax4 :: Flt -> Flt -> Flt -> Flt -> Flt
+ Data.Glome.Vec: fmin :: Flt -> Flt -> Flt
+ Data.Glome.Vec: fmin3 :: Flt -> Flt -> Flt -> Flt
+ Data.Glome.Vec: fmin4 :: Flt -> Flt -> Flt -> Flt -> Flt
+ Data.Glome.Vec: iabs :: Int -> Int
+ Data.Glome.Vec: ident_matrix :: Matrix
+ Data.Glome.Vec: ident_xfm :: Xfm
+ Data.Glome.Vec: infinity :: Flt
+ Data.Glome.Vec: instance Show Bbox
+ Data.Glome.Vec: instance Show Interval
+ Data.Glome.Vec: instance Show Matrix
+ Data.Glome.Vec: instance Show Ray
+ Data.Glome.Vec: instance Show Vec
+ Data.Glome.Vec: instance Show Xfm
+ Data.Glome.Vec: invxfm_norm :: Xfm -> Vec -> Vec
+ Data.Glome.Vec: invxfm_point :: Xfm -> Vec -> Vec
+ Data.Glome.Vec: invxfm_ray :: Xfm -> Ray -> Ray
+ Data.Glome.Vec: invxfm_vec :: Xfm -> Vec -> Vec
+ Data.Glome.Vec: mat_mult :: Matrix -> Matrix -> Matrix
+ Data.Glome.Vec: nvx :: Vec
+ Data.Glome.Vec: nvy :: Vec
+ Data.Glome.Vec: nvz :: Vec
+ Data.Glome.Vec: origin :: Ray -> !Vec
+ Data.Glome.Vec: orth :: Vec -> (Vec, Vec)
+ Data.Glome.Vec: p1 :: Bbox -> !Vec
+ Data.Glome.Vec: p2 :: Bbox -> !Vec
+ Data.Glome.Vec: plane_int :: Ray -> Vec -> Vec -> Vec
+ Data.Glome.Vec: plane_int_dist :: Ray -> Vec -> Vec -> Flt
+ Data.Glome.Vec: rad :: Flt -> Flt
+ Data.Glome.Vec: ray_move :: Ray -> Flt -> Ray
+ Data.Glome.Vec: reflect :: Vec -> Vec -> Vec
+ Data.Glome.Vec: rot :: Flt -> Flt
+ Data.Glome.Vec: rotate :: Vec -> Flt -> Xfm
+ Data.Glome.Vec: sas2s :: Flt -> Flt -> Flt -> Flt
+ Data.Glome.Vec: scale :: Vec -> Xfm
+ Data.Glome.Vec: translate :: Vec -> Xfm
+ Data.Glome.Vec: type Flt = Double
+ Data.Glome.Vec: uvw_to_xyz :: Vec -> Vec -> Vec -> Xfm
+ Data.Glome.Vec: va :: Vec -> Int -> Flt
+ Data.Glome.Vec: vadd :: Vec -> Vec -> Vec
+ Data.Glome.Vec: vadd3 :: Vec -> Vec -> Vec -> Vec
+ Data.Glome.Vec: vcross :: Vec -> Vec -> Vec
+ Data.Glome.Vec: vdec :: Vec -> Flt -> Vec
+ Data.Glome.Vec: vdist :: Vec -> Vec -> Flt
+ Data.Glome.Vec: vdot :: Vec -> Vec -> Flt
+ Data.Glome.Vec: vec :: Flt -> Flt -> Flt -> Vec
+ Data.Glome.Vec: veq :: Vec -> Vec -> Bool
+ Data.Glome.Vec: veqsign :: Vec -> Vec -> Bool
+ Data.Glome.Vec: vinc :: Vec -> Flt -> Vec
+ Data.Glome.Vec: vinvert :: Vec -> Vec
+ Data.Glome.Vec: vlen :: Vec -> Flt
+ Data.Glome.Vec: vlensqr :: Vec -> Flt
+ Data.Glome.Vec: vmap :: (Flt -> Flt) -> Vec -> Vec
+ Data.Glome.Vec: vmap2 :: (Flt -> Flt -> Flt) -> Vec -> Vec -> Vec
+ Data.Glome.Vec: vmax :: Vec -> Vec -> Vec
+ Data.Glome.Vec: vmaxaxis :: Vec -> Int
+ Data.Glome.Vec: vmin :: Vec -> Vec -> Vec
+ Data.Glome.Vec: vmul :: Vec -> Vec -> Vec
+ Data.Glome.Vec: vnorm :: Vec -> Vec
+ Data.Glome.Vec: vnudge :: Vec -> Vec
+ Data.Glome.Vec: vrcp :: Vec -> Vec
+ Data.Glome.Vec: vrotate :: Vec -> Ray -> Flt -> Vec
+ Data.Glome.Vec: vscale :: Vec -> Flt -> Vec
+ Data.Glome.Vec: vscaleadd :: Vec -> Vec -> Flt -> Vec
+ Data.Glome.Vec: vset :: Vec -> Int -> Flt -> Vec
+ Data.Glome.Vec: vsub :: Vec -> Vec -> Vec
+ Data.Glome.Vec: vunit :: Vec
+ Data.Glome.Vec: vx :: Vec
+ Data.Glome.Vec: vy :: Vec
+ Data.Glome.Vec: vz :: Vec
+ Data.Glome.Vec: vzero :: Vec
+ Data.Glome.Vec: x :: Vec -> Flt
+ Data.Glome.Vec: xfm_mult :: Xfm -> Xfm -> Xfm
+ Data.Glome.Vec: xfm_point :: Xfm -> Vec -> Vec
+ Data.Glome.Vec: xfm_ray :: Xfm -> Ray -> Ray
+ Data.Glome.Vec: xfm_vec :: Xfm -> Vec -> Vec
+ Data.Glome.Vec: xyz_to_uvw :: Vec -> Vec -> Vec -> Xfm
+ Data.Glome.Vec: y :: Vec -> Flt
+ Data.Glome.Vec: z :: Vec -> Flt

Files

+ Data/Glome/Texture.hs view
@@ -0,0 +1,126 @@+{-+module SolidTexture (square_wave, triangle_wave, sine_wave, +                     stripe, noise, turbulence+                    ) where -}++module Data.Glome.Texture where+import Data.Glome.Vec+import Data.Array.IArray++-- INTERPOLATION FUNCTIONS --+square_wave :: Flt -> Flt+square_wave x =+ let offset = x - (fromIntegral (floor x))+ in if offset < 0.5 then 0 else 1++triangle_wave :: Flt -> Flt+triangle_wave x =+ let offset = x - (fromIntegral (floor x))+ in if offset < 0.5 +    then (offset*2)+    else (2-(offset*2))++sine_wave :: Flt -> Flt+sine_wave x = (sin (x*2*pi))*0.5 + 0.5+++lump_wave :: Flt -> Flt+lump_wave x = 1 - x*x*x++-- SCALAR TEXTURE FUNCTIONS --++-- These are simple solid texture functions that take a +-- point as argument and return a number 0 < n < 1++stripe :: Vec -> (Flt -> Flt) -> (Vec -> Flt)+stripe axis interp =+ let len = vlen axis + in+  (\pos -> let offset = vdot pos axis +           in interp offset)+++-- PERLIN NOISE --++-- (-6 t^5 + 15 t^4 - 10t^3 +1)+-- "realistic ray tracing 2nd edition" inconsistent +-- on whether it should be t^5 or t^6,+-- but t^5 works and t^6 doesn't.+omega :: Flt -> Flt+omega t_ = + let t     = fabs t_+     tsqr  = t*t+     tcube = tsqr*t+ in (-6)*tcube*tsqr + 15*tcube*t - 10*tcube + 1++-- questionably random+phi :: Array Int Int+phi = listArray (0,11) [3,0,2,7,4,1,5,11,8,10,9,6]++grad :: Array Int Vec+grad = listArray (0,11) +         $ filter (\x -> let l = vlen x in l < 1.5 && l > 1.1) +                  [Vec x y z | x <- [(-1),0,1],+                               y <- [(-1),0,1],+                               z <- [(-1),0,1]] ++gamma :: Int -> Int -> Int -> Vec+gamma i j k =+ let a = phi!(mod (iabs k) 12)+     b = phi!(mod (iabs (j+a)) 12)+     c = phi!(mod (iabs (i+b)) 12)+ in grad!c++knot :: Int -> Int -> Int -> Vec -> Flt+knot i j k v =+ let Vec x y z = v+ in (omega x) * (omega y) * (omega z) * (vdot (gamma i j k) v)++intGamma :: Int -> Int -> Int+intGamma i j =+ let a = phi!(mod (iabs j) 16)+     b = phi!(mod (iabs (i+a)) 16)+ in b++turbulence :: Vec -> Int -> Flt+turbulence p 1 = fabs(noise(p))+turbulence p n =+ let newp = vscale p 0.5+     t = fabs (noise p)+ in t + (0.5 * (turbulence newp (n-1)))++noise :: Vec -> Flt +noise (Vec x y z) =+ let i = floor x+     j = floor y+     k = floor z+     u = x-(fromIntegral i)+     v = y-(fromIntegral j)+     w = z-(fromIntegral k)+ in knot i j k             (Vec u v w) ++    knot (i+1) j k         (Vec (u-1) v w) ++    knot i (j+1) k         (Vec u (v-1) w) ++    knot i j (k+1)         (Vec u v (w-1)) ++    knot (i+1) (j+1) k     (Vec (u-1) (v-1) w) ++    knot (i+1) j (k+1)     (Vec (u-1) v (w-1)) ++    knot i (j+1) (k+1)     (Vec u (v-1) (w-1)) ++    knot (i+1) (j+1) (k+1) (Vec (u-1) (v-1) (w-1))++perlin :: Vec -> Flt+perlin v =+ let p = ((noise v)+1)*0.5+ in if p > 1 +    then error $ "perlin noise error, 1 < " ++ (show p)+    else if p < 0 +         then error $ "perlin noise error, 0 > " ++ (show p)+         else p++--untested+perlin_turb :: Vec -> Int -> Flt+perlin_turb v l =+ let p = turbulence v l+ in if p > 1 +    then error $ "perlin turbulence error, 1 < " ++ (show p)+    else if p < 0 +         then error $ "perlin turbulence error, 0 > " ++ (show p)+         else p
+ Data/Glome/Vec.hs view
@@ -0,0 +1,738 @@+{-# OPTIONS_GHC -fexcess-precision #-}+{-# OPTIONS_GHC -funbox-strict-fields #-}+{-# LANGUAGE BangPatterns #-}++module Data.Glome.Vec where++-- | Performance is pretty similar with Floats or Doubles.+-- Todo: make separate Float and Double instances of this library.+type Flt = Double++-- maybe this is defined somewhere?+infinity :: Flt+--infinity = 1.0 / 0.0+infinity = 1000000.0++-- | Convert from degrees to native angle format (radians).+deg :: Flt -> Flt+deg !x = (x*3.1415926535897)/180++-- | Convert from radians to native format (noop).+rad :: Flt -> Flt+rad !x = x++-- | Convert from rotations to native format.  (rot 1 == deg 360)+rot :: Flt -> Flt+rot !x = x*3.1415926535897*2++-- | Trig with degrees instead of radians.+dcos :: Flt -> Flt+dcos d = cos $ deg d++-- | Force a value to be within a range.  Usage: clamp min x max+clamp :: Flt -> Flt -> Flt -> Flt+clamp !min !x !max+ | x < min = min+ | x > max = max+ | otherwise = x++-- | Tuning parameter.+delta = 0.0001 :: Flt++-- | Non-polymorphic fmin; this speeds+-- things up in ocaml, not sure about haskell.+fmin :: Flt -> Flt -> Flt+fmin !a !b = if a > b then b else a++-- | Non-polymorphic fmax.+fmax :: Flt -> Flt -> Flt+fmax !a !b = if a > b then a else b++-- | Non-polymorphic min of 3 values.+fmin3 :: Flt -> Flt -> Flt -> Flt+fmin3 !a !b !c = if a > b +                 then if b > c +                      then c+                      else b+                 else if a > c+                      then c+                      else a++-- | Non-polymorphic max of 3 values.+fmax3 :: Flt -> Flt -> Flt -> Flt+fmax3 !a !b !c = if a > b+                 then if a > c+                      then a+                      else c+                 else if b > c+                      then b+                      else c++-- | Min of 4 values.+fmin4 :: Flt -> Flt -> Flt -> Flt -> Flt+fmin4 !a !b !c !d = fmin (fmin a b) (fmin c d)++-- | Max of 4 values.+fmax4 :: Flt -> Flt -> Flt -> Flt -> Flt+fmax4 !a !b !c !d = fmax (fmax a b) (fmax c d)++-- | Non-polymorphic absolute value.+fabs :: Flt -> Flt+fabs !a = + if a < 0 then (-a) else a++-- | Non-polymorphic integer absolute value.+iabs :: Int -> Int+iabs !a =+ if a < 0 then (-a) else a++-- | Force user to use fabs or iabs, for performance reasons.  Not sure if+-- this really helps, though.+abs a = error "use non-polymorphic version, fabs"++-- | Approximate equality for Flt.  True if a and b are "almost" equal.+-- The (abs $ a-b) test doesn't work if+-- a and b are large.+about_equal :: Flt -> Flt -> Bool+about_equal !a !b =+ if a > 1 + then+  fabs (1 - (a/b)) < (delta*10) + else+  (fabs $ a - b) < (delta*10)++-- | 3d type represented as a record of unboxed floats.+data Vec = Vec !Flt !Flt !Flt deriving Show++-- | A Ray is made up of an origin and direction Vec.+data Ray = Ray {origin, dir :: !Vec} deriving Show+--data Plane = Plane {norm :: !Vec, offset :: !Flt} deriving Show++-- | Vec constructor.+vec :: Flt -> Flt -> Flt -> Vec+vec !x !y !z = (Vec x y z)++-- | Zero Vec.+vzero :: Vec+vzero = Vec 0.0 0.0 0.0++-- | For when we need a unit vector, but we +-- don't care where it points.+vunit :: Vec+vunit = vx++-- | Unit X vector.+vx :: Vec+vx  = Vec 1 0 0++-- | Unit y vector.+vy :: Vec+vy  = Vec 0 1 0++-- | Unit z vector.+vz :: Vec+vz  = Vec 0 0 1++-- | Negative x vector.+nvx :: Vec+nvx = Vec (-1) 0 0++-- | Negative y vector.+nvy :: Vec+nvy = Vec 0 (-1) 0++-- | Negative z vector.+nvz :: Vec+nvz = Vec 0 0 (-1)++-- Extract x coordinate.+x :: Vec -> Flt+x (Vec x_ _ _) = x_++-- Extract y coordinate.+y :: Vec -> Flt+y (Vec _ y_ _) = y_++-- Extract z coordinate.+z :: Vec -> Flt+z (Vec _ _ z_) = z_++-- | Access the Vec as if it were an array indexed from 0..2.+-- Note: this actually accounts for a noticeable amount of cpu +-- time in the Glome ray tracer.+va :: Vec -> Int -> Flt+va !(Vec x y z) !n = + case n of+  0 -> x+  1 -> y+  2 -> z++-- | Create a new Vec with the Nth field overwritten by new value.+-- I could have used record update syntax.+vset :: Vec -> Int -> Flt -> Vec+vset !(Vec x y z) !i !f =+ case i of+  0 -> Vec f y z+  1 -> Vec x f z+  2 -> Vec x y f++-- | Dot product of 2 vectors.  We use this all the time.  Dot product of 2+-- normal vectors is the cosine of the angle between them.+vdot :: Vec -> Vec -> Flt+vdot !(Vec x1 y1 z1) !(Vec x2 y2 z2) =+ (x1*x2)+(y1*y2)+(z1*z2)++-- | Cross product of 2 vectors.  Produces a vector perpendicular +-- to the given vectors.  We use this for things like making the forward,+-- up, and right camera vectors orthogonal.  If the input vectors are+-- normalized, the output vector will be as well.+vcross :: Vec -> Vec -> Vec+vcross !(Vec x1 y1 z1) !(Vec x2 y2 z2) =+ Vec +  ((y1 * z2) - (z1 * y2))+  ((z1 * x2) - (x1 * z2))+  ((x1 * y2) - (y1 * x2))++-- | Apply a unary Flt operator to each field of the Vec.+vmap :: (Flt -> Flt) -> Vec -> Vec+vmap f !v1 = + Vec (f (x v1)) (f (y v1)) (f (z v1))++-- | Apply a binary Flt operator to pairs of fields from 2 Vecs.+vmap2 :: (Flt -> Flt -> Flt) -> Vec -> Vec -> Vec+vmap2 f !v1 !v2 =+ Vec (f (x v1) (x v2)) +     (f (y v1) (y v2)) +     (f (z v1) (z v2))++-- | Reverse the direction of a Vec.+vinvert :: Vec -> Vec+vinvert !(Vec x1 y1 z1) =+ Vec (-x1) (-y1) (-z1)++-- | Get the length of a Vec squared.  We use this to avoid a slow sqrt. +vlensqr :: Vec -> Flt+vlensqr !v1 = vdot v1 v1++-- | Get the length of a Vec.  This is expensive because sqrt is slow.+vlen :: Vec -> Flt+vlen !v1 = sqrt (vdot v1 v1)++-- | Add 2 vectors.+vadd :: Vec -> Vec -> Vec+vadd !(Vec x1 y1 z1) !(Vec x2 y2 z2) =+ Vec (x1 + x2)+     (y1 + y2)+     (z1 + z2)++-- | Add 3 vectors.+vadd3 :: Vec -> Vec -> Vec -> Vec+vadd3 !(Vec x1 y1 z1) !(Vec x2 y2 z2) !(Vec x3 y3 z3) =+    Vec (x1 + x2 + x3)+        (y1 + y2 + y3)+        (z1 + z2 + z3)++-- | Subtract vectors.  "vsub b a" is the vector from a to b.+vsub :: Vec -> Vec -> Vec+vsub !(Vec x1 y1 z1) !(Vec x2 y2 z2) =+ Vec (x1 - x2)+     (y1 - y2)+     (z1 - z2)++-- | Multiply corresponding fields.  Rarely useful.+vmul :: Vec -> Vec -> Vec+vmul !(Vec x1 y1 z1) !(Vec x2 y2 z2) =+ Vec (x1 * x2)+     (y1 * y2)+     (z1 * z2)++-- | Add a value to all the fields of a Vec.  Useful, for instance, to get+-- one corner of the bounding box around a sphere.+vinc :: Vec -> Flt -> Vec+vinc !(Vec x y z) !n =+ Vec (x + n)+     (y + n)+     (z + n)++-- | Subtract a value from all fields of a Vec.+vdec :: Vec -> Flt -> Vec+vdec !(Vec x y z) !n =+ Vec (x - n)+     (y - n)+     (z - n)++-- | Get the maximum of all corresponding fields between 2 Vecs.+vmax :: Vec -> Vec -> Vec+vmax !(Vec x1 y1 z1) !(Vec x2 y2 z2) =+ Vec (fmax x1 x2)+     (fmax y1 y2)+     (fmax z1 z2)++-- | Get the minimum of all corresponding fields between 2 Vecs.+vmin :: Vec -> Vec -> Vec+vmin !(Vec x1 y1 z1) !(Vec x2 y2 z2) =+ Vec (fmin x1 x2)+     (fmin y1 y2)+     (fmin z1 z2)++-- | Return the largest axis.  Often used with "va".+vmaxaxis :: Vec -> Int+vmaxaxis !(Vec x y z) =+ if (x > y) + then if (x > z) +      then 0+      else 2+ else if (y > z) +      then 1+      else 2++-- | Scale a Vec by some value.+vscale :: Vec -> Flt -> Vec+vscale !(Vec x y z) !fac =+ Vec (x * fac)+     (y * fac)+     (z * fac)++-- | Take the first Vec, and add to it the second Vec scaled by some amount.+-- This is used quite a lot in Glome.+vscaleadd :: Vec -> Vec -> Flt -> Vec+vscaleadd !(Vec x1 y1 z1) !(Vec x2 y2 z2) fac =+ Vec (x1 + (x2 * fac))+     (y1 + (y2 * fac))+     (z1 + (z2 * fac))+            +-- | Make the length of a Vec just a little shorter.+vnudge :: Vec -> Vec+vnudge x = vscale x (1-delta)++-- | Normalize a vector.  Division is expensive, so we compute the reciprocol +-- of the length and multiply by that.  The sqrt is also expensive.+vnorm :: Vec -> Vec+vnorm !(Vec x1 y1 z1) = + let !invlen = 1.0 / (sqrt ((x1*x1)+(y1*y1)+(z1*z1))) in+ Vec (x1*invlen) (y1*invlen) (z1*invlen)++-- | Throw an exception if a vector hasn't been normalized.+assert_norm :: Vec -> Vec+assert_norm v =+ let l = vdot v v+ in if l > (1+delta) +    then error $ "vector too long" ++ (show v)+    else if l < (1-delta)+         then error $ "vector too short: " ++ (show v)+         else v++-- | Get the victor bisecting two other vectors (which ought to be the same+-- length).+bisect :: Vec -> Vec -> Vec+bisect !v1 !v2 = vnorm (vadd v1 v2)++-- | Distance between 2 vectors.+vdist :: Vec -> Vec -> Flt+vdist v1 v2 = + let d = vsub v2 v1 in vlen d++-- | Reflect a vector "v" off of a surface with normal "norm".+reflect :: Vec -> Vec -> Vec+reflect !v !norm =+  -- vadd v $ vscale norm $ (-2) * (vdot v norm)+  vscaleadd v norm $ (-2) * (vdot v norm)++-- | Reciprocol of all fields of a Vec.+vrcp :: Vec -> Vec+vrcp !(Vec x y z) =+ Vec (1/x) (1/y) (1/z)++-- | Test Vecs for approximate equality+veq :: Vec -> Vec -> Bool+veq !(Vec ax ay az) !(Vec bx by bz) =+ (about_equal ax bx) && (about_equal ay by) && (about_equal az bz)++-- | Test Vecs for matching sign on all fields.  Returns false if any value is+-- zero.  Used by packet tracing.+veqsign :: Vec -> Vec -> Bool+veqsign !(Vec ax ay az) !(Vec bx by bz) =+ ax*bx > 0 && ay*by > 0 && az*bz > 0++-- | Translate a ray's origin in ray's direction by d amount.+ray_move :: Ray -> Flt -> Ray+ray_move !(Ray orig dir) !d =+ (Ray (vscaleadd orig dir d) dir)++-- | Find a pair of orthogonal vectors to the one given.+orth :: Vec -> (Vec,Vec)+orth v1 =+ if about_equal (vdot v1 v1) 1+ then+  let x = (Vec 1 0 0)+      y = (Vec 0 1 0)+      dvx = vdot v1 x+      v2 = if dvx < 0.8 && dvx > (-0.8) -- don't want to cross with a+           then vnorm $ vcross v1 x     -- vector that's too similar+           else vnorm $ vcross v1 y+      v3 = vcross v1 v2+  in (v2,v3)+ else error $ "orth: unnormalized vector" ++ (show v1)++-- | Intersect a ray with a plane +-- defined by a point "p" and a normal "norm".+-- (Ray does not need to be normalized.)+plane_int :: Ray -> Vec -> Vec -> Vec+plane_int !(Ray orig dir) !p !norm =+ let newo = vsub orig p+     dist = -(vdot norm newo) / (vdot norm dir)+ in vscaleadd orig dir dist++-- | Find the distance along a ray until it intersects with a plane defined+-- by a point "p" and normal "norm".+plane_int_dist :: Ray -> Vec -> Vec -> Flt+plane_int_dist !(Ray orig dir) !p !norm =+ let newo = vsub orig p+ in -(vdot norm newo) / (vdot norm dir)++-- find intersection with plane+-- from graphics gems -- an efficient ray-polygon intersection+-- it seems that the ray need not be normalized+-- let plane_intersect ray (n,d) =+--  let t = -.((d +. (vdot n ray.origin)) /. (vdot n ray.dir))+--  in vadd ray.origin (vscale ray.dir t)+++-- TRANSFORMATIONS --++-- | 3x4 Transformation matrix.  These are described in most graphics texts.+data Matrix = Matrix !Flt !Flt !Flt !Flt  +                     !Flt !Flt !Flt !Flt  +                     !Flt !Flt !Flt !Flt deriving Show++-- | A transformation.  Inverting a matrix is expensive, so we keep a forward+-- transformation matrix and a reverse transformation matrix.+-- Note: This can be made a little faster if the matricies are non-strict.+data Xfm = Xfm Matrix Matrix deriving Show++-- | Identity matrix.  Transforming a vector by this matrix does nothing.+ident_matrix :: Matrix+ident_matrix = (Matrix 1 0 0 0  0 1 0 0  0 0 1 0)++-- | Identity transformation.+ident_xfm :: Xfm+ident_xfm = Xfm ident_matrix ident_matrix++-- | Multiply two matricies.  This is unrolled for efficiency, and it's also+-- a little bit easier (in my opinion) to see what's going on.+mat_mult :: Matrix -> Matrix -> Matrix+mat_mult (Matrix a00 a01 a02 a03  a10 a11 a12 a13  a20 a21 a22 a23)+         (Matrix b00 b01 b02 b03  b10 b11 b12 b13  b20 b21 b22 b23) =+ Matrix+   (a00*b00 + a01*b10 + a02*b20)+   (a00*b01 + a01*b11 + a02*b21)+   (a00*b02 + a01*b12 + a02*b22)+   (a00*b03 + a01*b13 + a02*b23 + a03)++   (a10*b00 + a11*b10 + a12*b20)+   (a10*b01 + a11*b11 + a12*b21)+   (a10*b02 + a11*b12 + a12*b22)+   (a10*b03 + a11*b13 + a12*b23 + a13)++   (a20*b00 + a21*b10 + a22*b20)+   (a20*b01 + a21*b11 + a22*b21)+   (a20*b02 + a21*b12 + a22*b22)+   (a20*b03 + a21*b13 + a22*b23 + a23)++-- | Multiply two tranformations.  This just multiplies the forward and +-- reverse transformations.+xfm_mult :: Xfm -> Xfm -> Xfm+xfm_mult (Xfm a inva) (Xfm b invb) =+ Xfm (mat_mult a b) (mat_mult invb inva)++-- TRANSFORM UTILITY FUNCTIONS --++-- | There is a seemingly-magical property of transformation matricies, that+-- we can combine the effects of any number of transformations into a single+-- transformation just by multiplying them together in reverse order.  For +-- instance, we could move a point, then rotate it about the origin by some +-- angle around some vector, then move it again, and this can all be done by +-- a single transformation.+-- This function combines transformations in this way, though it reverses the+-- list first so the transformations take effect in their expected order.+compose :: [Xfm] -> Xfm+compose xfms = check_xfm $ foldr xfm_mult ident_xfm (reverse xfms)++-- | Make sure a transformation is valid.  Multipy the forward and reverse+-- matrix and verify that the result is the identity matrix.+check_xfm :: Xfm -> Xfm+check_xfm (Xfm m i) = + let (Matrix m00 m01 m02 m03  +             m10 m11 m12 m13  +             m20 m21 m22 m23) = mat_mult m i+     ae = about_equal+ in+  if ae m00 1 && ae m01 0 && ae m02 0 && ae m03 0 &&+     ae m10 0 && ae m11 1 && ae m12 0 && ae m13 0 &&+     ae m20 0 && ae m21 0 && ae m22 1 && ae m23 0+  then (Xfm m i)+  else error $ "corrupt matrix " ++ (show (Xfm m i)) ++ "\n" ++ (show (mat_mult m i)) ++-- | Complex transformations: Rotate point (or vector) "pt" about ray by +-- angle c.  The angle is in radians,+-- but using the angle conversion routines "deg", "rad" and "rot" is +-- recommended.+vrotate :: Vec -> Ray -> Flt -> Vec+vrotate pt (Ray orig axis_) angle =+ let axis = assert_norm axis_+     transform = compose [ translate (vinvert orig)+                         , rotate axis angle+                         , translate orig+                         ]+     new_pt = xfm_point transform pt+ in if about_equal (vlen (vsub orig pt)) (vlen (vsub orig new_pt))+    then new_pt+    else error $ "something is wrong with vrotate" ++ +                 (show $ vlen (vsub orig pt)) ++ " " ++ +                 (show $ vlen (vsub orig new_pt))+++-- TRANSFORM APPLICATION --+-- these need to be fast++-- | Transform a point.  The point is treated as (x y z 1).+xfm_point :: Xfm -> Vec -> Vec+xfm_point !(Xfm (Matrix m00 m01 m02 m03  +                        m10 m11 m12 m13  +                        m20 m21 m22 m23) inv) +          !(Vec x y z) =+ Vec (m00*x + m01*y + m02*z + m03)+     (m10*x + m11*y + m12*z + m13)+     (m20*x + m21*y + m22*z + m23)++-- | Inverse transform a point.+invxfm_point :: Xfm -> Vec -> Vec+invxfm_point !(Xfm fwd (Matrix i00 i01 i02 i03  +                               i10 i11 i12 i13  +                               i20 i21 i22 i23)) +             !(Vec x y z) =+  Vec (i00*x + i01*y + i02*z + i03)+      (i10*x + i11*y + i12*z + i13)+      (i20*x + i21*y + i22*z + i23)++-- | Transform a vector.  The vector is treated as (x y z 0).+xfm_vec :: Xfm -> Vec -> Vec+xfm_vec !(Xfm (Matrix m00 m01 m02 m03  +                      m10 m11 m12 m13  +                      m20 m21 m22 m23) inv) +        !(Vec x y z) =+ Vec (m00*x + m01*y + m02*z)+     (m10*x + m11*y + m12*z)+     (m20*x + m21*y + m22*z)++-- | Inverse transform a vector.+invxfm_vec :: Xfm -> Vec -> Vec+invxfm_vec !(Xfm fwd (Matrix i00 i01 i02 i03  +                             i10 i11 i12 i13  +                             i20 i21 i22 i23)) +           !(Vec x y z) =+  Vec (i00*x + i01*y + i02*z)+      (i10*x + i11*y + i12*z)+      (i20*x + i21*y + i22*z)++-- | Inverse transform a normal.  This one is tricky: we need to transform +-- by the inverse transpose.+invxfm_norm :: Xfm -> Vec -> Vec+invxfm_norm !(Xfm fwd (Matrix i00 i01 i02 i03  +                              i10 i11 i12 i13  +                              i20 i21 i22 i23)) +            !(Vec x y z) =+ Vec (i00*x + i10*y + i20*z)+     (i01*x + i11*y + i21*z)+     (i02*x + i12*y + i22*z)++-- | Transform a Ray.+xfm_ray :: Xfm -> Ray -> Ray+xfm_ray !xfm !(Ray orig dir) =+ Ray (xfm_point xfm orig) (vnorm (xfm_vec xfm dir))++-- | Inverse transform a Ray.+invxfm_ray :: Xfm -> Ray -> Ray+invxfm_ray !xfm !(Ray orig dir) =+ Ray (invxfm_point xfm orig) (vnorm (invxfm_vec xfm dir))++-- BASIC TRANSFORMS --+-- | Basic transforms: move by some displacement vector.+translate :: Vec -> Xfm+translate (Vec x y z) =+ check_xfm $ Xfm (Matrix 1 0 0   x   0 1 0   y   0 0 1   z) +                 (Matrix 1 0 0 (-x)  0 1 0 (-y)  0 0 1 (-z))++-- | Basic transforms: stretch along the three axes, by the amount+-- in the given vector.  (If x==y==z, then it's uniform scaling.)+scale :: Vec -> Xfm+scale (Vec x y z) =+ check_xfm $ Xfm (Matrix   x  0 0 0  0   y  0 0  0 0   z  0)+                (Matrix (1/x) 0 0 0  0 (1/y) 0 0  0 0 (1/z) 0)++-- | Basic transforms: rotate about a given axis by some angle.+rotate :: Vec -> Flt -> Xfm+rotate v@(Vec x y z) angle =+ if not $ (vlen v) `about_equal` 1+ then error $ "please use a normalized vector for rotation: " ++ (show (vlen v))+ else +  let s = sin angle+      c = cos angle ++      m00 = ((x*x)+((1-(x*x))*c)) +      m01 = (((x*y)*(1-c))-(z*s)) +      m02 = ((x*z*(1-c))+(y*s))++      m10 = (((x*y)*(1-c))+(z*s))+      m11 = ((y*y)+((1-(y*y))*c))+      m12 = ((y*z*(1-c))-(x*s))++      m20 = ((x*z*(1-c))-(y*s))+      m21 = ((y*z*(1-c))+(x*s))+      m22 = ((z*z)+((1-(z*z))*c))+  in+  check_xfm $ Xfm (Matrix m00 m01 m02 0  m10 m11 m12 0  m20 m21 m22 0)+                  (Matrix m00 m10 m20 0  m01 m11 m21 0  m02 m12 m22 0)++-- | Basic transforms: Convert coordinate system from canonical xyz +-- coordinates to uvw coordinates.+xyz_to_uvw :: Vec -> Vec -> Vec -> Xfm+xyz_to_uvw u v w =+ let Vec ux uy uz = u+     Vec vx vy vz = v+     Vec wx wy wz = w+ in if (vdot u u) `about_equal` 1+    then+     if (vdot v v) `about_equal` 1+     then+      if (vdot w w) `about_equal` 1+      then +       if ((vdot u v) `about_equal` 0) && +          ((vdot u w) `about_equal` 0) && +          ((vdot v w) `about_equal` 0)+       then+        check_xfm $ Xfm (Matrix ux vx wx 0  uy vy wy 0  uz vz wz 0)+                        (Matrix ux uy uz 0  vx vy vz 0  wx wy wz 0)+       else error  "vectors aren't orthogonal"+      else error $ "unnormalized w " ++ (show w)+     else error $ "unnormalized v " ++ (show v)+    else error $ "unnormalized u " ++ (show u)++-- | Basic transforms: Convert from uvw coordinates back to normal xyz +-- coordinates.+uvw_to_xyz :: Vec -> Vec -> Vec -> Xfm+uvw_to_xyz (Vec ux uy uz) (Vec vx vy vz) (Vec wx wy wz) =+ check_xfm $ Xfm (Matrix ux uy uz 0  vx vy vz 0  wx wy wz 0)+                 (Matrix ux vx wx 0  uy vy wy 0  uz vz wz 0)++++-- TRIANGLE UTILITY FUNCTIONS --++-- | Given a side, angle, and side of a triangle, produce the length of the +-- opposite side.+sas2s :: Flt -> Flt -> Flt -> Flt+sas2s s1 a s2 =+  sqrt (((s1 * s1) + (s2 * s2)) - ((2 * s1 * s2 * (dcos a))))++++-- BOUNDING BOXES --+-- | Axis-aligned Bounding Box (AABB), defined by opposite corners.  P1 is the+-- min values, p2 has the max values.+data Bbox = Bbox {p1 :: !Vec, p2 :: !Vec} deriving Show++-- | A near-far pair of distances.  Basically just a tuple.+data Interval = Interval !Flt !Flt deriving Show -- used instead of a tuple++-- | Bounding box that encloses two bounding boxes.+bbjoin :: Bbox -> Bbox -> Bbox+bbjoin (Bbox p1a p2a) (Bbox p1b p2b) =+ (Bbox (vmin p1a p1b) (vmax p2a p2b))++-- | Find the overlap of two bounding boxes.+bboverlap :: Bbox -> Bbox -> Bbox+bboverlap (Bbox p1a p2a) (Bbox p1b p2b) =+ (Bbox (vmax p1a p1b) (vmin p2a p2b))++-- | Test if a Vec is inside the bounding box.+bbinside :: Bbox -> Vec -> Bool+bbinside (Bbox (Vec p1x p1y p1z) (Vec p2x p2y p2z)) (Vec x y z) =+ p1x <= x && x <= p2x && p1y <= y && y <= p2y && p1z <= z && z <= p2z++-- | Split a bounding box into two, given an axis and offset.  Throw exception+-- if the offset isn't inside the bounding box.+bbsplit :: Bbox -> Int -> Flt -> (Bbox,Bbox)+bbsplit (Bbox p1 p2) axis offset =+ if (offset < (va p1 axis)) || (offset > (va p2 axis))+ then error "degenerate bounding box split"+ else ((Bbox p1 (vset p2 axis offset)),+       (Bbox (vset p1 axis offset) p2))++-- | Generate a minimum bounding box that encloses a list of points.+bbpts :: [Vec] -> Bbox+bbpts [] = empty_bbox+bbpts ((Vec x y z):[]) =+ Bbox (Vec (x-delta) (y-delta) (z-delta)) +      (Vec (x+delta) (y+delta) (z+delta))++bbpts ((Vec x y z):pts) =+ let (Bbox (Vec p1x p1y p1z) (Vec p2x p2y p2z)) = bbpts pts+     minx = fmin (x-delta) p1x+     miny = fmin (y-delta) p1y+     minz = fmin (z-delta) p1z+     maxx = fmax (x+delta) p2x+     maxy = fmax (y+delta) p2y+     maxz = fmax (z+delta) p2z in+ Bbox (Vec minx miny minz) (Vec maxx maxy maxz)++-- | Surface area of a bounding box.  Useful for cost heuristics when attempting+-- to build optimal bounding box heirarchies.  Undefined for degenerate bounding+-- boxes.+bbsa :: Bbox -> Flt+bbsa (Bbox p1 p2) =+ let Vec dx dy dz = vsub p2 p1 + in dx*dy + dx*dz + dy*dz++-- | Volume of a bounding box.  Undefined for degenerate bounding boxes.+bbvol :: Bbox -> Flt+bbvol (Bbox p1 p2) =+ let (Vec dx dy dz) = vsub p2 p1+ in dx*dy*dz++-- | Degenerate bounding box that contains an empty volume.+empty_bbox :: Bbox+empty_bbox = + Bbox (Vec infinity infinity infinity) +      (Vec (-infinity) (-infinity) (-infinity))++-- | "Infinite" bounding box.+everything_bbox :: Bbox+everything_bbox =+ Bbox (Vec (-infinity) (-infinity) (-infinity))+      (Vec infinity infinity infinity)++-- | Find a ray's entrance and exit from a bounding +-- box.  If last entrance is before the first exit,+-- we hit.  Otherwise, we miss. (It's up to the +-- caller to figure that out.)++bbclip :: Ray -> Bbox -> Interval+bbclip (Ray (Vec ox oy oz) (Vec dx dy dz)) +       (Bbox (Vec p1x p1y p1z) (Vec p2x p2y p2z)) =+ let dxrcp = 1/dx+     dyrcp = 1/dy+     dzrcp = 1/dz+     Interval inx outx = if dx > 0 +                         then Interval ((p1x-ox)*dxrcp) ((p2x-ox)*dxrcp)+                         else Interval ((p2x-ox)*dxrcp) ((p1x-ox)*dxrcp)+     Interval iny outy = if dy > 0+                         then Interval ((p1y-oy)*dyrcp) ((p2y-oy)*dyrcp)+                         else Interval ((p2y-oy)*dyrcp) ((p1y-oy)*dyrcp)+     Interval inz outz = if dz > 0+                         then Interval ((p1z-oz)*dzrcp) ((p2z-oz)*dzrcp)+                         else Interval ((p2z-oz)*dzrcp) ((p1z-oz)*dzrcp)+ in+   Interval (fmax3 inx iny inz) (fmin3 outx outy outz)++
− Data/GlomeTexture.hs
@@ -1,126 +0,0 @@-{--module SolidTexture (square_wave, triangle_wave, sine_wave, -                     stripe, noise, turbulence-                    ) where -}--module Data.GlomeTexture where-import Data.GlomeVec-import Data.Array.IArray---- INTERPOLATION FUNCTIONS ---square_wave :: Flt -> Flt-square_wave x =- let offset = x - (fromIntegral (floor x))- in if offset < 0.5 then 0 else 1--triangle_wave :: Flt -> Flt-triangle_wave x =- let offset = x - (fromIntegral (floor x))- in if offset < 0.5 -    then (offset*2)-    else (2-(offset*2))--sine_wave :: Flt -> Flt-sine_wave x = (sin (x*2*pi))*0.5 + 0.5---lump_wave :: Flt -> Flt-lump_wave x = 1 - x*x*x---- SCALAR TEXTURE FUNCTIONS ------ These are simple solid texture functions that take a --- point as argument and return a number 0 < n < 1--stripe :: Vec -> (Flt -> Flt) -> (Vec -> Flt)-stripe axis interp =- let len = vlen axis - in-  (\pos -> let offset = vdot pos axis -           in interp offset)----- PERLIN NOISE ------ (-6 t^5 + 15 t^4 - 10t^3 +1)--- "realistic ray tracing 2nd edition" inconsistent --- on whether it should be t^5 or t^6,--- but t^5 works and t^6 doesn't.-omega :: Flt -> Flt-omega t_ = - let t     = fabs t_-     tsqr  = t*t-     tcube = tsqr*t- in (-6)*tcube*tsqr + 15*tcube*t - 10*tcube + 1---- questionably random-phi :: Array Int Int-phi = listArray (0,11) [3,0,2,7,4,1,5,11,8,10,9,6]--grad :: Array Int Vec-grad = listArray (0,11) -         $ filter (\x -> let l = vlen x in l < 1.5 && l > 1.1) -                  [Vec x y z | x <- [(-1),0,1],-                               y <- [(-1),0,1],-                               z <- [(-1),0,1]] --gamma :: Int -> Int -> Int -> Vec-gamma i j k =- let a = phi!(mod (iabs k) 12)-     b = phi!(mod (iabs (j+a)) 12)-     c = phi!(mod (iabs (i+b)) 12)- in grad!c--knot :: Int -> Int -> Int -> Vec -> Flt-knot i j k v =- let Vec x y z = v- in (omega x) * (omega y) * (omega z) * (vdot (gamma i j k) v)--intGamma :: Int -> Int -> Int-intGamma i j =- let a = phi!(mod (iabs j) 16)-     b = phi!(mod (iabs (i+a)) 16)- in b--turbulence :: Vec -> Int -> Flt-turbulence p 1 = fabs(noise(p))-turbulence p n =- let newp = vscale p 0.5-     t = fabs (noise p)- in t + (0.5 * (turbulence newp (n-1)))--noise :: Vec -> Flt -noise (Vec x y z) =- let i = floor x-     j = floor y-     k = floor z-     u = x-(fromIntegral i)-     v = y-(fromIntegral j)-     w = z-(fromIntegral k)- in knot i j k             (Vec u v w) +-    knot (i+1) j k         (Vec (u-1) v w) +-    knot i (j+1) k         (Vec u (v-1) w) +-    knot i j (k+1)         (Vec u v (w-1)) +-    knot (i+1) (j+1) k     (Vec (u-1) (v-1) w) +-    knot (i+1) j (k+1)     (Vec (u-1) v (w-1)) +-    knot i (j+1) (k+1)     (Vec u (v-1) (w-1)) +-    knot (i+1) (j+1) (k+1) (Vec (u-1) (v-1) (w-1))--perlin :: Vec -> Flt-perlin v =- let p = ((noise v)+1)*0.5- in if p > 1 -    then error $ "perlin noise error, 1 < " ++ (show p)-    else if p < 0 -         then error $ "perlin noise error, 0 > " ++ (show p)-         else p----untested-perlin_turb :: Vec -> Int -> Flt-perlin_turb v l =- let p = turbulence v l- in if p > 1 -    then error $ "perlin turbulence error, 1 < " ++ (show p)-    else if p < 0 -         then error $ "perlin turbulence error, 0 > " ++ (show p)-         else p
− Data/GlomeVec.hs
@@ -1,738 +0,0 @@-{-# OPTIONS_GHC -fexcess-precision #-}-{-# OPTIONS_GHC -funbox-strict-fields #-}-{-# LANGUAGE BangPatterns #-}--module Data.GlomeVec where---- | Performance is pretty similar with Floats or Doubles.--- Todo: make separate Float and Double instances of this library.-type Flt = Double---- maybe this is defined somewhere?-infinity :: Flt---infinity = 1.0 / 0.0-infinity = 1000000.0---- | Convert from degrees to native angle format (radians).-deg :: Flt -> Flt-deg !x = (x*3.1415926535897)/180---- | Convert from radians to native format (noop).-rad :: Flt -> Flt-rad !x = x---- | Convert from rotations to native format.  (rot 1 == deg 360)-rot :: Flt -> Flt-rot !x = x*3.1415926535897*2---- | Trig with degrees instead of radians.-dcos :: Flt -> Flt-dcos d = cos $ deg d---- | Force a value to be within a range.  Usage: clamp min x max-clamp :: Flt -> Flt -> Flt -> Flt-clamp !min !x !max- | x < min = min- | x > max = max- | otherwise = x---- | Tuning parameter.-delta = 0.0001 :: Flt---- | Non-polymorphic fmin; this speeds--- things up in ocaml, not sure about haskell.-fmin :: Flt -> Flt -> Flt-fmin !a !b = if a > b then b else a---- | Non-polymorphic fmax.-fmax :: Flt -> Flt -> Flt-fmax !a !b = if a > b then a else b---- | Non-polymorphic min of 3 values.-fmin3 :: Flt -> Flt -> Flt -> Flt-fmin3 !a !b !c = if a > b -                 then if b > c -                      then c-                      else b-                 else if a > c-                      then c-                      else a---- | Non-polymorphic max of 3 values.-fmax3 :: Flt -> Flt -> Flt -> Flt-fmax3 !a !b !c = if a > b-                 then if a > c-                      then a-                      else c-                 else if b > c-                      then b-                      else c---- | Min of 4 values.-fmin4 :: Flt -> Flt -> Flt -> Flt -> Flt-fmin4 !a !b !c !d = fmin (fmin a b) (fmin c d)---- | Max of 4 values.-fmax4 :: Flt -> Flt -> Flt -> Flt -> Flt-fmax4 !a !b !c !d = fmax (fmax a b) (fmax c d)---- | Non-polymorphic absolute value.-fabs :: Flt -> Flt-fabs !a = - if a < 0 then (-a) else a---- | Non-polymorphic integer absolute value.-iabs :: Int -> Int-iabs !a =- if a < 0 then (-a) else a---- | Force user to use fabs or iabs, for performance reasons.  Not sure if--- this really helps, though.-abs a = error "use non-polymorphic version, fabs"---- | Approximate equality for Flt.  True if a and b are "almost" equal.--- The (abs $ a-b) test doesn't work if--- a and b are large.-about_equal :: Flt -> Flt -> Bool-about_equal !a !b =- if a > 1 - then-  fabs (1 - (a/b)) < (delta*10) - else-  (fabs $ a - b) < (delta*10)---- | 3d type represented as a record of unboxed floats.-data Vec = Vec !Flt !Flt !Flt deriving Show---- | A Ray is made up of an origin and direction Vec.-data Ray = Ray {origin, dir :: !Vec} deriving Show---data Plane = Plane {norm :: !Vec, offset :: !Flt} deriving Show---- | Vec constructor.-vec :: Flt -> Flt -> Flt -> Vec-vec !x !y !z = (Vec x y z)---- | Zero Vec.-vzero :: Vec-vzero = Vec 0.0 0.0 0.0---- | For when we need a unit vector, but we --- don't care where it points.-vunit :: Vec-vunit = vx---- | Unit X vector.-vx :: Vec-vx  = Vec 1 0 0---- | Unit y vector.-vy :: Vec-vy  = Vec 0 1 0---- | Unit z vector.-vz :: Vec-vz  = Vec 0 0 1---- | Negative x vector.-nvx :: Vec-nvx = Vec (-1) 0 0---- | Negative y vector.-nvy :: Vec-nvy = Vec 0 (-1) 0---- | Negative z vector.-nvz :: Vec-nvz = Vec 0 0 (-1)---- Extract x coordinate.-x :: Vec -> Flt-x (Vec x_ _ _) = x_---- Extract y coordinate.-y :: Vec -> Flt-y (Vec _ y_ _) = y_---- Extract z coordinate.-z :: Vec -> Flt-z (Vec _ _ z_) = z_---- | Access the Vec as if it were an array indexed from 0..2.--- Note: this actually accounts for a noticeable amount of cpu --- time in the Glome ray tracer.-va :: Vec -> Int -> Flt-va !(Vec x y z) !n = - case n of-  0 -> x-  1 -> y-  2 -> z---- | Create a new Vec with the Nth field overwritten by new value.--- I could have used record update syntax.-vset :: Vec -> Int -> Flt -> Vec-vset !(Vec x y z) !i !f =- case i of-  0 -> Vec f y z-  1 -> Vec x f z-  2 -> Vec x y f---- | Dot product of 2 vectors.  We use this all the time.  Dot product of 2--- normal vectors is the cosine of the angle between them.-vdot :: Vec -> Vec -> Flt-vdot !(Vec x1 y1 z1) !(Vec x2 y2 z2) =- (x1*x2)+(y1*y2)+(z1*z2)---- | Cross product of 2 vectors.  Produces a vector perpendicular --- to the given vectors.  We use this for things like making the forward,--- up, and right camera vectors orthogonal.  If the input vectors are--- normalized, the output vector will be as well.-vcross :: Vec -> Vec -> Vec-vcross !(Vec x1 y1 z1) !(Vec x2 y2 z2) =- Vec -  ((y1 * z2) - (z1 * y2))-  ((z1 * x2) - (x1 * z2))-  ((x1 * y2) - (y1 * x2))---- | Apply a unary Flt operator to each field of the Vec.-vmap :: (Flt -> Flt) -> Vec -> Vec-vmap f !v1 = - Vec (f (x v1)) (f (y v1)) (f (z v1))---- | Apply a binary Flt operator to pairs of fields from 2 Vecs.-vmap2 :: (Flt -> Flt -> Flt) -> Vec -> Vec -> Vec-vmap2 f !v1 !v2 =- Vec (f (x v1) (x v2)) -     (f (y v1) (y v2)) -     (f (z v1) (z v2))---- | Reverse the direction of a Vec.-vinvert :: Vec -> Vec-vinvert !(Vec x1 y1 z1) =- Vec (-x1) (-y1) (-z1)---- | Get the length of a Vec squared.  We use this to avoid a slow sqrt. -vlensqr :: Vec -> Flt-vlensqr !v1 = vdot v1 v1---- | Get the length of a Vec.  This is expensive because sqrt is slow.-vlen :: Vec -> Flt-vlen !v1 = sqrt (vdot v1 v1)---- | Add 2 vectors.-vadd :: Vec -> Vec -> Vec-vadd !(Vec x1 y1 z1) !(Vec x2 y2 z2) =- Vec (x1 + x2)-     (y1 + y2)-     (z1 + z2)---- | Add 3 vectors.-vadd3 :: Vec -> Vec -> Vec -> Vec-vadd3 !(Vec x1 y1 z1) !(Vec x2 y2 z2) !(Vec x3 y3 z3) =-    Vec (x1 + x2 + x3)-        (y1 + y2 + y3)-        (z1 + z2 + z3)---- | Subtract vectors.  "vsub b a" is the vector from a to b.-vsub :: Vec -> Vec -> Vec-vsub !(Vec x1 y1 z1) !(Vec x2 y2 z2) =- Vec (x1 - x2)-     (y1 - y2)-     (z1 - z2)---- | Multiply corresponding fields.  Rarely useful.-vmul :: Vec -> Vec -> Vec-vmul !(Vec x1 y1 z1) !(Vec x2 y2 z2) =- Vec (x1 * x2)-     (y1 * y2)-     (z1 * z2)---- | Add a value to all the fields of a Vec.  Useful, for instance, to get--- one corner of the bounding box around a sphere.-vinc :: Vec -> Flt -> Vec-vinc !(Vec x y z) !n =- Vec (x + n)-     (y + n)-     (z + n)---- | Subtract a value from all fields of a Vec.-vdec :: Vec -> Flt -> Vec-vdec !(Vec x y z) !n =- Vec (x - n)-     (y - n)-     (z - n)---- | Get the maximum of all corresponding fields between 2 Vecs.-vmax :: Vec -> Vec -> Vec-vmax !(Vec x1 y1 z1) !(Vec x2 y2 z2) =- Vec (fmax x1 x2)-     (fmax y1 y2)-     (fmax z1 z2)---- | Get the minimum of all corresponding fields between 2 Vecs.-vmin :: Vec -> Vec -> Vec-vmin !(Vec x1 y1 z1) !(Vec x2 y2 z2) =- Vec (fmin x1 x2)-     (fmin y1 y2)-     (fmin z1 z2)---- | Return the largest axis.  Often used with "va".-vmaxaxis :: Vec -> Int-vmaxaxis !(Vec x y z) =- if (x > y) - then if (x > z) -      then 0-      else 2- else if (y > z) -      then 1-      else 2---- | Scale a Vec by some value.-vscale :: Vec -> Flt -> Vec-vscale !(Vec x y z) !fac =- Vec (x * fac)-     (y * fac)-     (z * fac)---- | Take the first Vec, and add to it the second Vec scaled by some amount.--- This is used quite a lot in Glome.-vscaleadd :: Vec -> Vec -> Flt -> Vec-vscaleadd !(Vec x1 y1 z1) !(Vec x2 y2 z2) fac =- Vec (x1 + (x2 * fac))-     (y1 + (y2 * fac))-     (z1 + (z2 * fac))-            --- | Make the length of a Vec just a little shorter.-vnudge :: Vec -> Vec-vnudge x = vscale x (1-delta)---- | Normalize a vector.  Division is expensive, so we compute the reciprocol --- of the length and multiply by that.  The sqrt is also expensive.-vnorm :: Vec -> Vec-vnorm !(Vec x1 y1 z1) = - let !invlen = 1.0 / (sqrt ((x1*x1)+(y1*y1)+(z1*z1))) in- Vec (x1*invlen) (y1*invlen) (z1*invlen)---- | Throw an exception if a vector hasn't been normalized.-assert_norm :: Vec -> Vec-assert_norm v =- let l = vdot v v- in if l > (1+delta) -    then error $ "vector too long" ++ (show v)-    else if l < (1-delta)-         then error $ "vector too short: " ++ (show v)-         else v---- | Get the victor bisecting two other vectors (which ought to be the same--- length).-bisect :: Vec -> Vec -> Vec-bisect !v1 !v2 = vnorm (vadd v1 v2)---- | Distance between 2 vectors.-vdist :: Vec -> Vec -> Flt-vdist v1 v2 = - let d = vsub v2 v1 in vlen d---- | Reflect a vector "v" off of a surface with normal "norm".-reflect :: Vec -> Vec -> Vec-reflect !v !norm =-  -- vadd v $ vscale norm $ (-2) * (vdot v norm)-  vscaleadd v norm $ (-2) * (vdot v norm)---- | Reciprocol of all fields of a Vec.-vrcp :: Vec -> Vec-vrcp !(Vec x y z) =- Vec (1/x) (1/y) (1/z)---- | Test Vecs for approximate equality-veq :: Vec -> Vec -> Bool-veq !(Vec ax ay az) !(Vec bx by bz) =- (about_equal ax bx) && (about_equal ay by) && (about_equal az bz)---- | Test Vecs for matching sign on all fields.  Returns false if any value is--- zero.  Used by packet tracing.-veqsign :: Vec -> Vec -> Bool-veqsign !(Vec ax ay az) !(Vec bx by bz) =- ax*bx > 0 && ay*by > 0 && az*bz > 0---- | Translate a ray's origin in ray's direction by d amount.-ray_move :: Ray -> Flt -> Ray-ray_move !(Ray orig dir) !d =- (Ray (vscaleadd orig dir d) dir)---- | Find a pair of orthogonal vectors to the one given.-orth :: Vec -> (Vec,Vec)-orth v1 =- if about_equal (vdot v1 v1) 1- then-  let x = (Vec 1 0 0)-      y = (Vec 0 1 0)-      dvx = vdot v1 x-      v2 = if dvx < 0.8 && dvx > (-0.8) -- don't want to cross with a-           then vnorm $ vcross v1 x     -- vector that's too similar-           else vnorm $ vcross v1 y-      v3 = vcross v1 v2-  in (v2,v3)- else error $ "orth: unnormalized vector" ++ (show v1)---- | Intersect a ray with a plane --- defined by a point "p" and a normal "norm".--- (Ray does not need to be normalized.)-plane_int :: Ray -> Vec -> Vec -> Vec-plane_int !(Ray orig dir) !p !norm =- let newo = vsub orig p-     dist = -(vdot norm newo) / (vdot norm dir)- in vscaleadd orig dir dist---- | Find the distance along a ray until it intersects with a plane defined--- by a point "p" and normal "norm".-plane_int_dist :: Ray -> Vec -> Vec -> Flt-plane_int_dist !(Ray orig dir) !p !norm =- let newo = vsub orig p- in -(vdot norm newo) / (vdot norm dir)---- find intersection with plane--- from graphics gems -- an efficient ray-polygon intersection--- it seems that the ray need not be normalized--- let plane_intersect ray (n,d) =---  let t = -.((d +. (vdot n ray.origin)) /. (vdot n ray.dir))---  in vadd ray.origin (vscale ray.dir t)----- TRANSFORMATIONS ------ | 3x4 Transformation matrix.  These are described in most graphics texts.-data Matrix = Matrix !Flt !Flt !Flt !Flt  -                     !Flt !Flt !Flt !Flt  -                     !Flt !Flt !Flt !Flt deriving Show---- | A transformation.  Inverting a matrix is expensive, so we keep a forward--- transformation matrix and a reverse transformation matrix.--- Note: This can be made a little faster if the matricies are non-strict.-data Xfm = Xfm Matrix Matrix deriving Show---- | Identity matrix.  Transforming a vector by this matrix does nothing.-ident_matrix :: Matrix-ident_matrix = (Matrix 1 0 0 0  0 1 0 0  0 0 1 0)---- | Identity transformation.-ident_xfm :: Xfm-ident_xfm = Xfm ident_matrix ident_matrix---- | Multiply two matricies.  This is unrolled for efficiency, and it's also--- a little bit easier (in my opinion) to see what's going on.-mat_mult :: Matrix -> Matrix -> Matrix-mat_mult (Matrix a00 a01 a02 a03  a10 a11 a12 a13  a20 a21 a22 a23)-         (Matrix b00 b01 b02 b03  b10 b11 b12 b13  b20 b21 b22 b23) =- Matrix-   (a00*b00 + a01*b10 + a02*b20)-   (a00*b01 + a01*b11 + a02*b21)-   (a00*b02 + a01*b12 + a02*b22)-   (a00*b03 + a01*b13 + a02*b23 + a03)--   (a10*b00 + a11*b10 + a12*b20)-   (a10*b01 + a11*b11 + a12*b21)-   (a10*b02 + a11*b12 + a12*b22)-   (a10*b03 + a11*b13 + a12*b23 + a13)--   (a20*b00 + a21*b10 + a22*b20)-   (a20*b01 + a21*b11 + a22*b21)-   (a20*b02 + a21*b12 + a22*b22)-   (a20*b03 + a21*b13 + a22*b23 + a23)---- | Multiply two tranformations.  This just multiplies the forward and --- reverse transformations.-xfm_mult :: Xfm -> Xfm -> Xfm-xfm_mult (Xfm a inva) (Xfm b invb) =- Xfm (mat_mult a b) (mat_mult invb inva)---- TRANSFORM UTILITY FUNCTIONS ------ | There is a seemingly-magical property of transformation matricies, that--- we can combine the effects of any number of transformations into a single--- transformation just by multiplying them together in reverse order.  For --- instance, we could move a point, then rotate it about the origin by some --- angle around some vector, then move it again, and this can all be done by --- a single transformation.--- This function combines transformations in this way, though it reverses the--- list first so the transformations take effect in their expected order.-compose :: [Xfm] -> Xfm-compose xfms = check_xfm $ foldr xfm_mult ident_xfm (reverse xfms)---- | Make sure a transformation is valid.  Multipy the forward and reverse--- matrix and verify that the result is the identity matrix.-check_xfm :: Xfm -> Xfm-check_xfm (Xfm m i) = - let (Matrix m00 m01 m02 m03  -             m10 m11 m12 m13  -             m20 m21 m22 m23) = mat_mult m i-     ae = about_equal- in-  if ae m00 1 && ae m01 0 && ae m02 0 && ae m03 0 &&-     ae m10 0 && ae m11 1 && ae m12 0 && ae m13 0 &&-     ae m20 0 && ae m21 0 && ae m22 1 && ae m23 0-  then (Xfm m i)-  else error $ "corrupt matrix " ++ (show (Xfm m i)) ++ "\n" ++ (show (mat_mult m i)) ---- | Complex transformations: Rotate point (or vector) "pt" about ray by --- angle c.  The angle is in radians,--- but using the angle conversion routines "deg", "rad" and "rot" is --- recommended.-vrotate :: Vec -> Ray -> Flt -> Vec-vrotate pt (Ray orig axis_) angle =- let axis = assert_norm axis_-     transform = compose [ translate (vinvert orig)-                         , rotate axis angle-                         , translate orig-                         ]-     new_pt = xfm_point transform pt- in if about_equal (vlen (vsub orig pt)) (vlen (vsub orig new_pt))-    then new_pt-    else error $ "something is wrong with vrotate" ++ -                 (show $ vlen (vsub orig pt)) ++ " " ++ -                 (show $ vlen (vsub orig new_pt))----- TRANSFORM APPLICATION ----- these need to be fast---- | Transform a point.  The point is treated as (x y z 1).-xfm_point :: Xfm -> Vec -> Vec-xfm_point !(Xfm (Matrix m00 m01 m02 m03  -                        m10 m11 m12 m13  -                        m20 m21 m22 m23) inv) -          !(Vec x y z) =- Vec (m00*x + m01*y + m02*z + m03)-     (m10*x + m11*y + m12*z + m13)-     (m20*x + m21*y + m22*z + m23)---- | Inverse transform a point.-invxfm_point :: Xfm -> Vec -> Vec-invxfm_point !(Xfm fwd (Matrix i00 i01 i02 i03  -                               i10 i11 i12 i13  -                               i20 i21 i22 i23)) -             !(Vec x y z) =-  Vec (i00*x + i01*y + i02*z + i03)-      (i10*x + i11*y + i12*z + i13)-      (i20*x + i21*y + i22*z + i23)---- | Transform a vector.  The vector is treated as (x y z 0).-xfm_vec :: Xfm -> Vec -> Vec-xfm_vec !(Xfm (Matrix m00 m01 m02 m03  -                      m10 m11 m12 m13  -                      m20 m21 m22 m23) inv) -        !(Vec x y z) =- Vec (m00*x + m01*y + m02*z)-     (m10*x + m11*y + m12*z)-     (m20*x + m21*y + m22*z)---- | Inverse transform a vector.-invxfm_vec :: Xfm -> Vec -> Vec-invxfm_vec !(Xfm fwd (Matrix i00 i01 i02 i03  -                             i10 i11 i12 i13  -                             i20 i21 i22 i23)) -           !(Vec x y z) =-  Vec (i00*x + i01*y + i02*z)-      (i10*x + i11*y + i12*z)-      (i20*x + i21*y + i22*z)---- | Inverse transform a normal.  This one is tricky: we need to transform --- by the inverse transpose.-invxfm_norm :: Xfm -> Vec -> Vec-invxfm_norm !(Xfm fwd (Matrix i00 i01 i02 i03  -                              i10 i11 i12 i13  -                              i20 i21 i22 i23)) -            !(Vec x y z) =- Vec (i00*x + i10*y + i20*z)-     (i01*x + i11*y + i21*z)-     (i02*x + i12*y + i22*z)---- | Transform a Ray.-xfm_ray :: Xfm -> Ray -> Ray-xfm_ray !xfm !(Ray orig dir) =- Ray (xfm_point xfm orig) (vnorm (xfm_vec xfm dir))---- | Inverse transform a Ray.-invxfm_ray :: Xfm -> Ray -> Ray-invxfm_ray !xfm !(Ray orig dir) =- Ray (invxfm_point xfm orig) (vnorm (invxfm_vec xfm dir))---- BASIC TRANSFORMS ----- | Basic transforms: move by some displacement vector.-translate :: Vec -> Xfm-translate (Vec x y z) =- check_xfm $ Xfm (Matrix 1 0 0   x   0 1 0   y   0 0 1   z) -                 (Matrix 1 0 0 (-x)  0 1 0 (-y)  0 0 1 (-z))---- | Basic transforms: stretch along the three axes, by the amount--- in the given vector.  (If x==y==z, then it's uniform scaling.)-scale :: Vec -> Xfm-scale (Vec x y z) =- check_xfm $ Xfm (Matrix   x  0 0 0  0   y  0 0  0 0   z  0)-                (Matrix (1/x) 0 0 0  0 (1/y) 0 0  0 0 (1/z) 0)---- | Basic transforms: rotate about a given axis by some angle.-rotate :: Vec -> Flt -> Xfm-rotate v@(Vec x y z) angle =- if not $ (vlen v) `about_equal` 1- then error $ "please use a normalized vector for rotation: " ++ (show (vlen v))- else -  let s = sin angle-      c = cos angle --      m00 = ((x*x)+((1-(x*x))*c)) -      m01 = (((x*y)*(1-c))-(z*s)) -      m02 = ((x*z*(1-c))+(y*s))--      m10 = (((x*y)*(1-c))+(z*s))-      m11 = ((y*y)+((1-(y*y))*c))-      m12 = ((y*z*(1-c))-(x*s))--      m20 = ((x*z*(1-c))-(y*s))-      m21 = ((y*z*(1-c))+(x*s))-      m22 = ((z*z)+((1-(z*z))*c))-  in-  check_xfm $ Xfm (Matrix m00 m01 m02 0  m10 m11 m12 0  m20 m21 m22 0)-                  (Matrix m00 m10 m20 0  m01 m11 m21 0  m02 m12 m22 0)---- | Basic transforms: Convert coordinate system from canonical xyz --- coordinates to uvw coordinates.-xyz_to_uvw :: Vec -> Vec -> Vec -> Xfm-xyz_to_uvw u v w =- let Vec ux uy uz = u-     Vec vx vy vz = v-     Vec wx wy wz = w- in if (vdot u u) `about_equal` 1-    then-     if (vdot v v) `about_equal` 1-     then-      if (vdot w w) `about_equal` 1-      then -       if ((vdot u v) `about_equal` 0) && -          ((vdot u w) `about_equal` 0) && -          ((vdot v w) `about_equal` 0)-       then-        check_xfm $ Xfm (Matrix ux vx wx 0  uy vy wy 0  uz vz wz 0)-                        (Matrix ux uy uz 0  vx vy vz 0  wx wy wz 0)-       else error  "vectors aren't orthogonal"-      else error $ "unnormalized w " ++ (show w)-     else error $ "unnormalized v " ++ (show v)-    else error $ "unnormalized u " ++ (show u)---- | Basic transforms: Convert from uvw coordinates back to normal xyz --- coordinates.-uvw_to_xyz :: Vec -> Vec -> Vec -> Xfm-uvw_to_xyz (Vec ux uy uz) (Vec vx vy vz) (Vec wx wy wz) =- check_xfm $ Xfm (Matrix ux uy uz 0  vx vy vz 0  wx wy wz 0)-                 (Matrix ux vx wx 0  uy vy wy 0  uz vz wz 0)------ TRIANGLE UTILITY FUNCTIONS ------ | Given a side, angle, and side of a triangle, produce the length of the --- opposite side.-sas2s :: Flt -> Flt -> Flt -> Flt-sas2s s1 a s2 =-  sqrt (((s1 * s1) + (s2 * s2)) - ((2 * s1 * s2 * (dcos a))))------ BOUNDING BOXES ----- | Axis-aligned Bounding Box (AABB), defined by opposite corners.  P1 is the--- min values, p2 has the max values.-data Bbox = Bbox {p1 :: !Vec, p2 :: !Vec} deriving Show---- | A near-far pair of distances.  Basically just a tuple.-data Interval = Interval !Flt !Flt deriving Show -- used instead of a tuple---- | Bounding box that encloses two bounding boxes.-bbjoin :: Bbox -> Bbox -> Bbox-bbjoin (Bbox p1a p2a) (Bbox p1b p2b) =- (Bbox (vmin p1a p1b) (vmax p2a p2b))---- | Find the overlap of two bounding boxes.-bboverlap :: Bbox -> Bbox -> Bbox-bboverlap (Bbox p1a p2a) (Bbox p1b p2b) =- (Bbox (vmax p1a p1b) (vmin p2a p2b))---- | Test if a Vec is inside the bounding box.-bbinside :: Bbox -> Vec -> Bool-bbinside (Bbox (Vec p1x p1y p1z) (Vec p2x p2y p2z)) (Vec x y z) =- p1x <= x && x <= p2x && p1y <= y && y <= p2y && p1z <= z && z <= p2z---- | Split a bounding box into two, given an axis and offset.  Throw exception--- if the offset isn't inside the bounding box.-bbsplit :: Bbox -> Int -> Flt -> (Bbox,Bbox)-bbsplit (Bbox p1 p2) axis offset =- if (offset < (va p1 axis)) || (offset > (va p2 axis))- then error "degenerate bounding box split"- else ((Bbox p1 (vset p2 axis offset)),-       (Bbox (vset p1 axis offset) p2))---- | Generate a minimum bounding box that encloses a list of points.-bbpts :: [Vec] -> Bbox-bbpts [] = empty_bbox-bbpts ((Vec x y z):[]) =- Bbox (Vec (x-delta) (y-delta) (z-delta)) -      (Vec (x+delta) (y+delta) (z+delta))--bbpts ((Vec x y z):pts) =- let (Bbox (Vec p1x p1y p1z) (Vec p2x p2y p2z)) = bbpts pts-     minx = fmin (x-delta) p1x-     miny = fmin (y-delta) p1y-     minz = fmin (z-delta) p1z-     maxx = fmax (x+delta) p2x-     maxy = fmax (y+delta) p2y-     maxz = fmax (z+delta) p2z in- Bbox (Vec minx miny minz) (Vec maxx maxy maxz)---- | Surface area of a bounding box.  Useful for cost heuristics when attempting--- to build optimal bounding box heirarchies.  Undefined for degenerate bounding--- boxes.-bbsa :: Bbox -> Flt-bbsa (Bbox p1 p2) =- let Vec dx dy dz = vsub p2 p1 - in dx*dy + dx*dz + dy*dz---- | Volume of a bounding box.  Undefined for degenerate bounding boxes.-bbvol :: Bbox -> Flt-bbvol (Bbox p1 p2) =- let (Vec dx dy dz) = vsub p2 p1- in dx*dy*dz---- | Degenerate bounding box that contains an empty volume.-empty_bbox :: Bbox-empty_bbox = - Bbox (Vec infinity infinity infinity) -      (Vec (-infinity) (-infinity) (-infinity))---- | "Infinite" bounding box.-everything_bbox :: Bbox-everything_bbox =- Bbox (Vec (-infinity) (-infinity) (-infinity))-      (Vec infinity infinity infinity)---- | Find a ray's entrance and exit from a bounding --- box.  If last entrance is before the first exit,--- we hit.  Otherwise, we miss. (It's up to the --- caller to figure that out.)--bbclip :: Ray -> Bbox -> Interval-bbclip (Ray (Vec ox oy oz) (Vec dx dy dz)) -       (Bbox (Vec p1x p1y p1z) (Vec p2x p2y p2z)) =- let dxrcp = 1/dx-     dyrcp = 1/dy-     dzrcp = 1/dz-     Interval inx outx = if dx > 0 -                         then Interval ((p1x-ox)*dxrcp) ((p2x-ox)*dxrcp)-                         else Interval ((p2x-ox)*dxrcp) ((p1x-ox)*dxrcp)-     Interval iny outy = if dy > 0-                         then Interval ((p1y-oy)*dyrcp) ((p2y-oy)*dyrcp)-                         else Interval ((p2y-oy)*dyrcp) ((p1y-oy)*dyrcp)-     Interval inz outz = if dz > 0-                         then Interval ((p1z-oz)*dzrcp) ((p2z-oz)*dzrcp)-                         else Interval ((p2z-oz)*dzrcp) ((p1z-oz)*dzrcp)- in-   Interval (fmax3 inx iny inz) (fmin3 outx outy outz)--
GlomeVec.cabal view
@@ -1,5 +1,5 @@ Name:                GlomeVec-Version:             0.1.1+Version:             0.1.2 Synopsis:            Simple 3D vector library Description:         A simple library for dealing with 3D vectors, suitable for graphics projects.  A small texture library with Perlin noise is included as well. License:             GPL@@ -14,7 +14,7 @@ Cabal-Version: >= 1.2 extra-source-files:   README.txt- library-  exposed-modules:   Data.GlomeVec, Data.GlomeTexture+  exposed-modules:   Data.Glome.Vec+                     Data.Glome.Texture   Build-Depends:     base >= 3 && < 4, array