packages feed

shapes-demo-0.1.0.0: src/Physics/Draw.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards #-}

module Physics.Draw where

import Control.Lens ((^.), _1, _2)
import Linear.Affine
import Linear.V2
import qualified SDL.Video.Renderer as R
import Physics.Draw.Canonical
import Physics.Draw.Transform (WorldTransform, joinTransforms', translateTransform, scaleTransform, translateTransform)
import Physics.Draw.Linear

toRenderable :: (Functor f, RealFrac a, Integral b) => f a -> f b
toRenderable = fmap floor

centeredRectangle :: (Fractional a) => P2 a -> V2 a -> R.Rectangle a
centeredRectangle center size = R.Rectangle (center .-^ halfSize) size
  where halfSize = fmap (/2) size

viewTransform :: (Floating a) => V2 a -> V2 a -> V2 a -> WorldTransform a
viewTransform window (V2 x y) d = joinTransforms' [ translateTransform window'
                                                  , scaleTransform (V2 x (-y))
                                                  , translateTransform (-d) ]
  where window' = fmap (/2) window

drawLine :: (RealFrac a) => R.Renderer -> P2 a -> P2 a -> IO ()
drawLine r a b = R.drawLine r (toRenderable a) (toRenderable b)

drawLine_ :: (RealFrac a) => R.Renderer -> (P2 a, P2 a) -> IO ()
drawLine_ r = uncurry (drawLine r)

drawPoint :: (RealFrac a) => R.Renderer -> P2 a -> IO ()
drawPoint r p = R.drawPoint r (toRenderable p)

drawThickPoint :: (RealFrac a) => R.Renderer -> P2 a -> IO ()
drawThickPoint r p = R.fillRect r (Just . toRenderable $ centeredRectangle p (V2 4 4))

drawAabb :: R.Renderer -> Aabb -> IO ()
drawAabb r (Aabb aabb) = do
  drawLine r nw ne
  drawLine r ne se
  drawLine r se sw
  drawLine r sw nw
  where nw = extractCorner _1 _2
        ne = extractCorner _2 _2
        sw = extractCorner _1 _1
        se = extractCorner _2 _1
        extractCorner lx ly = P $ V2 (aabb ^._x.lx) (aabb ^._y.ly)

drawPolygon :: R.Renderer -> Polygon -> IO ()
drawPolygon r vertices = sequence_ (fmap f segments)
  where f (v1, v2) = drawLine r v1 v2
        segments = zip vertices (tail vertices ++ [head vertices])

drawOverlap :: R.Renderer -> Overlap -> IO ()
drawOverlap r Overlap{..} = do
  drawLine r a b
  drawLine r c c'
  drawThickPoint r _overlapPenetrator
  where (a, b) = _overlapEdge
        c = center2 a b
        c' = c .+^ _overlapVector

drawContact :: R.Renderer -> Contact -> IO ()
drawContact r Contact{..} = do
  (c, c') <- either f g _contactPoints
  drawLine r c c'
  where f a = do
          drawThickPoint r a
          return (a, a .+^ _contactNormal)
        g (a, b) = do
          drawThickPoint r a
          drawThickPoint r b
          return (c, c')
            where c = center2 a b
                  c' = c .+^ _contactNormal