diff --git a/call.cabal b/call.cabal
--- a/call.cabal
+++ b/call.cabal
@@ -1,7 +1,7 @@
 name:                call
-version:             0.0.1
+version:             0.1
 synopsis:            The call game engine
-description:         Call is a minimalistic game engine which supports 2D graphics and sounds.
+description:         Call is a minimalistic game engine that supports 2D/3D graphics and sounds.
 homepage:            https://github.com/fumieval/call
 license:             BSD3
 license-file:        LICENSE
@@ -10,51 +10,76 @@
 copyright:           (c) Fumiaki Kinoshita 2014
 category:            Game
 build-type:          Simple
--- extra-source-files:  
+data-files:
+  shaders/*.glsl
+  data/*.ttf
 cabal-version:       >=1.10
 
+flag BuildHelloWorld
+    default: False
+
+source-repository head
+  type: git
+  location: https://github.com/fumieval/call.git
+
 library
   exposed-modules:
     Call
     Call.Types
     Call.TH
     Call.System
-    Call.Picture
-    Call.Component
-    Call.Component.Deck
+    Call.Sight
     Call.Internal.GLFW
     Call.Internal.PortAudio
     Call.Data.Wave
     Call.Data.Font
     Call.Data.Bitmap
     Call.Util
+    Call.Util.Deck
+    Call.Util.Sampler
+  other-modules:
+    Paths_call
   ghc-options: -Wall -fexcess-precision -O2 -threaded
   other-extensions:    Rank2Types, DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveDataTypeable, TemplateHaskell, CPP, GeneralizedNewtypeDeriving, MultiParamTypeClasses, TypeSynonymInstances, ScopedTypeVariables, FlexibleInstances, FlexibleContexts, KindSignatures, TypeFamilies, BangPatterns, ViewPatterns, LambdaCase, DataKinds, GADTs
   build-depends:
     base >=4.5 && <5,
-    transformers >=0.3 && <0.5,
-    control-bool >=0.2 && <0.3,
-    colors >=0.1 && <0.2,
-    linear >=1.10 && <1.11,
-    boundingboxes >=0.2 && <0.3,
-    template-haskell == 2.*,
+    bindings-portaudio,
+    boundingboxes >=0.2 && <0.4,
+    clean-unions >= 0.1 && <0.3,
+    colors >=0.2 && <0.3,
+    containers >=0.5 && <0.7,
+    control-bool >=0.2 && <0.4,
     directory,
+    distributive == 0.4.*,
+    elevator,
     filepath,
-    mtl >=2.0 && <2.7,
-    reflection >=1.5 && <1.6,
-    containers >=0.5 && <0.7,
-    vector >=0.9 && <0.13,
+    freetype2 >=0.1 && <0.2,
     GLFW-b >=1.3 && <2,
+    hashable >=1.2 && <1.3,
+    JuicyPixels == 3.*,
+    JuicyPixels-util >= 0.2 && <0.4,
     lens >=4.0 && <5,
+    linear >=1.13 && <2,
+    mtl >=2.0 && <2.7,
+    objective >= 0.5 && <0.7,
     OpenGL == 2.9.*,
     OpenGLRaw >=1.4 && <1.7,
-    JuicyPixels == 3.*,
-    JuicyPixels-util <0.3,
-    WAVE >=0.1 && <0.2,
-    freetype2 >=0.1 && <0.2,
     random ==1.*,
-    hashable >=1.2 && <1.3,
-    objective >= 0.2 && <0.3,
-    bindings-portaudio
+    reflection >=1.4 && <1.7,
+    template-haskell == 2.*,
+    text >= 1.0 && <1.5,
+    transformers >=0.3 && <0.5,
+    vector >=0.9 && <0.13,
+    WAVE >=0.1 && <0.2
   hs-source-dirs:      src
+  default-language:    Haskell2010
+
+executable hello-world
+  ghc-options: -threaded
+  main-is: examples/hello-world.hs
+  if flag(BuildHelloWorld)
+    buildable: True
+  else
+    buildable: False
+  build-depends: base == 4.*, call <= 0.1, lens == 4.*
   default-language:    Haskell2010
diff --git a/data/VL-PGothic-Regular.ttf b/data/VL-PGothic-Regular.ttf
new file mode 100644
# file too large to diff: data/VL-PGothic-Regular.ttf
diff --git a/examples/hello-world.hs b/examples/hello-world.hs
new file mode 100644
--- /dev/null
+++ b/examples/hello-world.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE Rank2Types, LambdaCase, FlexibleContexts #-}
+-- $ ghc -threaded hello-world.hs
+import Call
+import Call.Util.Deck
+import Control.Lens
+import Control.Monad.State.Strict
+
+-- calculates the root-mean-square value of the playing sound
+currentRMS :: MonadState Deck m => Int -> m (V2 Float)
+currentRMS n = do
+  Source s <- use source
+  t <- use pos
+  let t0 = t - fromIntegral (n-1)/44100
+  return $ fmap realToFrac
+    $ fmap (/fromIntegral n)
+    $ sum $ map (fmap (^(2::Int)) . s) [t0, t0 + 1 / 44100..t]
+
+main = runSystemDefault $ do
+  setTitle "Hello, world!"
+  src <- readWAVE "examples/hello-world.wav"
+  deck <- new $ variable $ Call.Util.Deck.empty & source .~ sampleSource src
+  linkAudio $ ((deck .-) .) . playback
+  linkPicture $ \_ -> do
+    let s x = (10 + max (log (realToFrac x) / log 10) (-10)) / 10
+    V2 a b <- fmap (fmap s) $ deck .- currentRMS 1024
+    return $ translate (V2 0 240) $ mconcat
+      [color black $ polygonOutline [V2 0 0, V2 40 0, V2 40 (-240), V2 0 (-240)]
+      ,color red $ mconcat [polygonOutline [V2 0 0, V2 16 0, V2 16 (-a * 240), V2 0 (-a * 240)]
+        , polygonOutline [V2 24 0, V2 40 0, V2 40 (-b * 240), V2 24 (-b * 240)]]
+        ]
+  linkKeyboard $ \case
+    Down KeySpace -> deck .- pos .= 0
+    _ -> return ()
+  deck .- playing .= True
+  stand
+ 
diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl
new file mode 100644
--- /dev/null
+++ b/shaders/fragment.glsl
@@ -0,0 +1,25 @@
+#version 330
+in vec2 UV;
+in vec2 envUV;
+out vec4 fragColor;
+uniform vec4 color;
+uniform bool useTexture;
+uniform int useEnv;
+uniform sampler2D tex;
+uniform sampler2D env;
+
+void main(void){
+  if(useTexture){
+    fragColor = texture( tex, UV ).rgba * color;
+  }else{
+    fragColor = color;
+  }
+  if (useEnv == 1)
+  {
+    fragColor += texture( env, envUV ).rgba;
+  }
+  else if (useEnv == 2)
+  {
+    fragColor *= texture( env, envUV ).rgba;
+  }
+}
diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl
new file mode 100644
--- /dev/null
+++ b/shaders/vertex.glsl
@@ -0,0 +1,26 @@
+#version 330
+uniform mat4 projection;
+uniform mat4 matrices[13];
+uniform int level;
+uniform int useEnv;
+out vec2 UV;
+out vec2 envUV;
+in vec3 in_Position;
+in vec2 in_UV;
+in vec3 in_Normal;
+
+void main(void) {
+  mat4 model = mat4(1.0);
+  for(int i=0; i < level; i++)
+  {
+    model *= matrices[i];
+  }
+  gl_Position = projection * model * vec4(in_Position, 1.0);
+  UV = in_UV;
+  if(useEnv != 0)
+  {
+    vec3 r = reflect( normalize(vec3(model * vec4(in_Position, 1.0))), in_Normal );
+    float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) );
+    envUV = r.xy / m + 0.5;
+  }
+}
diff --git a/src/Call.hs b/src/Call.hs
--- a/src/Call.hs
+++ b/src/Call.hs
@@ -1,62 +1,31 @@
 {-# LANGUAGE Rank2Types #-}
 module Call ( -- * System
-    Time,
-    MonadObjective(..),
-    (.&),
-    System,
-    runSystem,
     runSystemDefault,
-    MonadSystem(..),
-    -- * Component crafting
-    module Control.Object,
-    Mouse(..),
-    Keyboard(..),
-    Graphic(..),
-    Audio(..),
-    -- * Free instances
-    PullGraphic(..),
-    PullAudio(..),
-    KeyEvent(..),
-    MouseEvent(..),
-    -- * Concrete types
-    Vec2,
-    WindowMode(..),
-    BoundingBox2,
-    Box(..),
-    isInside,
-    Picture(..),
-    Affine(..),
-    Picture2D(..),
-    opacity,
-    BlendMode(..),
-    Key(..),
-    charToKey,
-    -- * Bitmap
-    Bitmap,
-    readBitmap,
-    clipBitmap,
-    loadBitmapsWith,
-    -- * Sound
-    Source(..),
-    readWAVE,
-    -- * IO
-    liftIO,
+    module Call.Sight,
+    module Call.Util,
+    module Call.System,
+    module Call.Types,
+    module Call.TH,
+    module Call.Data.Wave,
     -- * Reexports
     module Control.Monad,
     module Control.Applicative,
     module Control.Bool,
+    module Data.Monoid,
     module Data.Color,
     module Data.Color.Names,
     module Linear,
+    module Control.Object,
+    module Control.Monad.Objective.Class,
+    module Control.Monad.IO.Class
 ) where
 
 import Call.TH
 import Call.Types
-import Call.Component
-import Call.Data.Bitmap
 import Call.Data.Wave
-import Call.Picture
+import Call.Sight
 import Call.System
+import Call.Util
 import Control.Monad.IO.Class
 import Control.Monad
 import Control.Applicative
@@ -65,6 +34,7 @@
 import Control.Monad.Objective.Class
 import Data.Color
 import Data.Color.Names
+import Data.Monoid
 import Linear
 import Data.BoundingBox
 
diff --git a/src/Call/Component.hs b/src/Call/Component.hs
deleted file mode 100644
--- a/src/Call/Component.hs
+++ /dev/null
@@ -1,70 +0,0 @@
-{-# LANGUAGE DeriveFunctor #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Call.Component
--- Copyright   :  (c) Fumiaki Kinoshita 2014
--- License     :  BSD3
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
---
------------------------------------------------------------------------------
-module Call.Component where
-
-import Call.Types
-import Linear
-import Call.Picture
-import Control.Object
-
-class Mouse f where
-  cursorEvent :: Vec2 -> f ()
-  scrollEvent :: Vec2 -> f ()
-  mouseButtonEvent :: Int -> Bool -> f ()
-
-class Keyboard f where
-  keyEvent :: Key -> Bool -> f ()
-
-class Graphic e where
-  pullGraphic :: Time -> e (Picture ())
-
-class Audio e where
-  pullAudio :: Time -> Int -> e [V2 Float]
-
-data PullGraphic a = PullGraphic !Time (Picture () -> a) deriving Functor
-
-instance Graphic PullGraphic where
-  pullGraphic t = PullGraphic t id
-
-data PullAudio a = PullAudio !Time !Int ([V2 Float] -> a) deriving Functor
-
-instance Audio PullAudio where
-  pullAudio t n = PullAudio t n id
-
-data KeyEvent a = KeyEvent !Key !Bool a deriving Functor
-
-instance Keyboard KeyEvent where
-  keyEvent k b = KeyEvent k b ()
-
-data MouseEvent a = CursorEvent !Vec2 a | ScrollEvent !Vec2 a | MouseButtonEvent !Int !Bool a
-
-instance Mouse MouseEvent where
-  cursorEvent v = CursorEvent v ()
-  scrollEvent v = ScrollEvent v ()
-  mouseButtonEvent i b = MouseButtonEvent i b ()
-
-------------------------------------------------------------------
-
-instance Mouse e => Mouse (AccessT s e) where
-  cursorEvent v = LiftAccessT (cursorEvent v)
-  scrollEvent v = LiftAccessT (scrollEvent v)
-  mouseButtonEvent i b = LiftAccessT (mouseButtonEvent i b)
-
-instance Keyboard e => Keyboard (AccessT s e) where
-  keyEvent k b = LiftAccessT (keyEvent k b)
-
-instance Graphic e => Graphic (AccessT s e) where
-  pullGraphic dt = LiftAccessT (pullGraphic dt)
-
-instance Audio e => Audio (AccessT s e) where
-  pullAudio dt n = LiftAccessT (pullAudio dt n)
diff --git a/src/Call/Component/Deck.hs b/src/Call/Component/Deck.hs
deleted file mode 100644
--- a/src/Call/Component/Deck.hs
+++ /dev/null
@@ -1,65 +0,0 @@
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE Rank2Types #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE ViewPatterns #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Call.Component.Deck
--- Copyright   :  (c) Fumiaki Kinoshita 2014
--- License     :  BSD3
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
---
--- Decks that plays sounds
---
------------------------------------------------------------------------------
-module Call.Component.Deck (emptyDeck, States, source, pos, pitch, playing, sampleRate) where
-import Call.Component
-import Control.Lens
-import Linear
-import Call.Types
-import Control.Monad.State.Strict
-import Call.Data.Wave
-import Control.Object
-
-data States = States
-  { _src :: Maybe (Source (V2 Float))
-  , _pos :: !Time
-  , _pitch :: !Double
-  , _playing :: !Bool
-  , _sampleRate :: !Double }
-
---
-source :: Lens' States (Maybe (Source (V2 Float)))
-source f s = f (_src s) <&> \a -> s { _src = a }
-pos :: Lens' States Time
-pos f s = f (_pos s) <&> \a -> s { _pos = a }
-pitch :: Lens' States Time
-pitch f s = f (_pitch s) <&> \a -> s { _pitch = a }
-playing :: Lens' States Bool
-playing f s = f (_playing s) <&> \a -> s { _playing = a }
-sampleRate :: Lens' States Double
-sampleRate f s = f (_sampleRate s) <&> \a -> s { _sampleRate = a }
-
-emptyDeck :: Monad m => Object (AccessT States PullAudio) m
-emptyDeck = stateful handle $ States Nothing 0 1 False 44100 where -- FIXME: sample rate
-
-handle :: MonadState States m => PullAudio (m a) -> m a
-handle (PullAudio dt0 n cont) = use source >>= \case
-  Just (Source s) -> do
-    pl <- use playing
-    t0 <- use pos
-    k <- use pitch
-    let dt = dt0 * k
-    if pl
-      then do
-        r <- use sampleRate
-        pos += dt
-        cont $ map s [t0,t0 + dt / fromIntegral n..t0 + dt - 1 / r]
-      else do
-        cont $ replicate n zero
-  Nothing -> cont $ replicate n zero
diff --git a/src/Call/Data/Bitmap.hs b/src/Call/Data/Bitmap.hs
--- a/src/Call/Data/Bitmap.hs
+++ b/src/Call/Data/Bitmap.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE TemplateHaskell #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Call.Data.Bitmap
@@ -10,60 +11,90 @@
 --
 -----------------------------------------------------------------------------
 module Call.Data.Bitmap (
-    -- * Basic types and functions
-    Bitmap(..)
-    ,bitmapSize
-    ,liftBitmapIO
-    -- * Load and Save
-    ,readBitmap
-    ,writeBitmap
-
-    -- * Bitmap operations
-    ,cropBitmap
-    -- * V2
-    ,sizeBitmap
-    ,clipBitmap
-    ) where
-
+  Bitmap(Blank, Bitmap)
+  ,image
+  ,offset
+  ,hash
+  ,liftImage
+  ,liftImage'
+  ,size
+  ,clip
+  ,bbox
+  ,readFile
+  ,writeFile
+  ) where
+import Prelude hiding (readFile, writeFile)
 import qualified Codec.Picture as C
+import qualified Codec.Picture.Types as C
 import qualified Codec.Picture.RGBA8 as C
 import Control.Monad.IO.Class
-import Data.BoundingBox
-import Linear.V2
+import qualified Data.BoundingBox as B
+import Linear
 import System.Random
 import Control.Applicative
-import Data.Hashable
+import qualified Data.Hashable as H
+import qualified Data.Vector.Storable as V
+import Data.Monoid
+import Control.Lens
+import Control.Monad.ST
 
-data Bitmap = Bitmap { bitmapImage :: C.Image C.PixelRGBA8, bitmapHash :: Int }
+data Bitmap = Blank | Bitmap { _image :: C.Image C.PixelRGBA8, _offset :: V2 Int, _hash :: Int }
 
--- | Get the size of the 'Bitmap'.
-bitmapSize :: Bitmap -> (Int, Int)
-bitmapSize (Bitmap (C.Image w h _) _) = (w, h)
+image :: Traversal' Bitmap (C.Image C.PixelRGBA8)
+image _ Blank = pure Blank
+image f (Bitmap i o h) = f i <&> \i' -> Bitmap i' o h
 
-liftBitmapIO :: MonadIO m => C.Image C.PixelRGBA8 -> m Bitmap
-liftBitmapIO b = liftIO $ Bitmap b <$> randomIO
+offset :: Traversal' Bitmap (V2 Int)
+offset _ Blank = pure Blank
+offset f (Bitmap i o h) = f o <&> \o' -> Bitmap i o' h
 
--- | Load an image file.
-readBitmap :: MonadIO m => FilePath -> m Bitmap
-readBitmap path = liftIO $ Bitmap <$> C.readImageRGBA8 path <*> randomIO
+hash :: Traversal' Bitmap Int
+hash _ Blank = pure Blank
+hash f (Bitmap i o h) = f h <&> \h' -> Bitmap i o h'
 
--- | Save 'Bitmap' into a file.
-writeBitmap :: MonadIO m => FilePath -> Bitmap -> m ()
-writeBitmap path (Bitmap p _) = liftIO $ C.writePng path p
+-- | `mappend` stitches the right operand to the left
+instance Monoid Bitmap where
+  mempty = Blank
+  mappend base@(Bitmap b (V2 x0 y0) h0) lay@(Bitmap l (V2 x1 y1) h1) = runST $ do
+    let box = B.union (bbox base) (bbox lay)
+    let V2 w h = box ^. B.size 0
+    img <- C.createMutableImage w h (C.PixelRGBA8 0 0 0 0) >>= C.unsafeFreezeImage
+    let ox = max 0 (x0 - x1)
+    let oy = max 0 (y0 - y1)
+    return $ Bitmap
+      (C.patchImage (C.patchImage img (ox, oy) b) (max 0 (x1 - x0), max 0 (y1 - y0)) l)
+      (V2 (x0 + ox) (y0 + oy))
+      (H.hash (h0, h1))
+  mappend Blank b = b
+  mappend b Blank = b
 
--- | Extract a 'Bitmap' from the specified range.
-cropBitmap :: Bitmap -- ^original bitmap
-    -> (Int, Int) -- ^width and height
-    -> (Int, Int) -- ^x and y
-    -> Bitmap -- ^result
-cropBitmap (Bitmap b k) (w, h) (x, y) = Bitmap
-    (C.trimImage b (w, h) (x, y))
-    (hash (w, h, x, y, k))
+clip :: Bitmap -> B.Box V2 Int -> Bitmap
+clip (Bitmap b (V2 ox oy) k) (B.Box (V2 x0 y0) (V2 x1 y1)) = Bitmap
+  (C.trimImage b (x1 - x0, y1 - y0) (x0 - ox, y0 - oy))
+  (V2 ox oy)
+  (H.hash (x0, y0, x1, y1, k))
 
-clipBitmap :: Bitmap -> Box V2 Int -> Bitmap
-clipBitmap (Bitmap b k) (Box (V2 x0 y0) (V2 x1 y1)) = Bitmap
-    (C.trimImage b (x1 - x0, y1 - y0) (x0, y0))
-    (hash (x0, y0, x1, y1, k))
+clip Blank _ = Blank
 
-sizeBitmap :: Bitmap -> V2 Int
-sizeBitmap (Bitmap (C.Image w h _) _) = V2 w h
+bbox :: Bitmap -> B.Box V2 Int
+bbox (Bitmap (C.Image w h _) (V2 x y) _) = B.Box (V2 x y) (V2 (x+w) (y+h))
+bbox Blank = B.Box zero zero
+
+size :: Bitmap -> V2 Int
+size (Bitmap (C.Image w h _) _ _) = V2 w h
+size Blank = zero
+
+liftImage :: C.Image C.PixelRGBA8 -> Bitmap
+liftImage b@(C.Image _ _ r) = Bitmap b zero (V.foldl H.hashWithSalt 0 r)
+
+liftImage' :: MonadIO m => C.Image C.PixelRGBA8 -> m Bitmap
+liftImage' b = liftIO $ Bitmap b zero <$> randomIO
+
+-- | Load an image file.
+readFile :: MonadIO m => FilePath -> m Bitmap
+readFile path = liftIO $ Bitmap <$> C.readImageRGBA8 path <*> pure zero <*> randomIO
+
+-- | Save 'Bitmap' into a file.
+writeFile :: MonadIO m => FilePath -> Bitmap -> m ()
+writeFile path (Bitmap p _ _) = liftIO $ C.writePng path p
+writeFile _ Blank = fail "Blank bitmap"
diff --git a/src/Call/Data/Font.hs b/src/Call/Data/Font.hs
--- a/src/Call/Data/Font.hs
+++ b/src/Call/Data/Font.hs
@@ -14,19 +14,17 @@
 module Call.Data.Font 
   ( Font
   , readFont
+  , defaultFont
   , fontBoundingBox
   , metricsAscent
   , metricsDescent
-  , charToBitmap
-  , RenderedChar(..)
+  , renderChar
   ) where
 
 import Control.Applicative
 import Control.Monad.IO.Class
 import Control.Monad
-import Data.IORef
 import Data.BoundingBox
-import qualified Data.Map as M
 import qualified Data.Vector.Storable as V
 import Linear
 import Call.Data.Bitmap
@@ -47,36 +45,41 @@
 import System.IO.Unsafe
 import Codec.Picture
 import Codec.Picture.RGBA8
+import Paths_call
 
 -- | Font object
-data Font = Font FT_Face (Double, Double) (Box V2 Double) (IORef (M.Map (Double, Char) RenderedChar))
+data Font = Font FT_Face (Float, Float) (Box V2 Float)
 
+defaultFont :: Font
+defaultFont = unsafePerformIO $ do
+  path <- getDataFileName "data/VL-PGothic-Regular.ttf"
+  readFont path
+
 -- | Create a 'Font' from the given file.
 readFont :: MonadIO m => FilePath -> m Font
 readFont path = liftIO $ alloca $ \p -> do
     runFreeType $ withCString path $ \str -> ft_New_Face freeType str 0 p
     f <- peek p
-    b <- peek (bbox f)
+    b <- peek (F.bbox f)
     asc <- peek (ascender f)
     desc <- peek (descender f)
     u <- fromIntegral <$> peek (units_per_EM f)
-    let box = fmap (/u) $ Box
-            (V2 (fromIntegral (xMin b)) (fromIntegral (yMin b)))
-            (V2 (fromIntegral (xMax b)) (fromIntegral (yMax b)))
-    Font f (fromIntegral asc/u, fromIntegral desc/u) box <$> newIORef M.empty
-
+    let box = fmap ((/u).fromIntegral) $ Box
+            (V2 (xMin b) (yMin b))
+            (V2 (xMax b) (yMax b))
+    return $ Font f (fromIntegral asc/u, fromIntegral desc/u) box
 
 -- | Get the font's metrics.
-metricsAscent :: Font -> Double
-metricsAscent (Font _ (a, _) _ _) = a
+metricsAscent :: Font -> Float
+metricsAscent (Font _ (a, _) _) = a
 
 -- | Get the font's metrics.
-metricsDescent :: Font -> Double
-metricsDescent (Font _ (_, d) _ _) = d
+metricsDescent :: Font -> Float
+metricsDescent (Font _ (_, d) _) = d
 
--- | Get the font's boundingbox.
-fontBoundingBox :: Font -> Box V2 Double
-fontBoundingBox (Font _ _ b _) = b
+-- | Get the font's bounding box.
+fontBoundingBox :: Font -> Box V2 Float
+fontBoundingBox (Font _ _ b) = b
 
 runFreeType :: IO CInt -> IO ()
 runFreeType m = do
@@ -85,55 +88,37 @@
 
 freeType :: FT_Library
 freeType = unsafePerformIO $ alloca $ \p -> do
-    runFreeType $ ft_Init_FreeType p
-    peek p
-
-data RenderedChar = RenderedChar
-    { charBitmap :: Bitmap
-    , charOffset :: V2 Double
-    ,　charAdvance :: Double
-    }
+  runFreeType $ ft_Init_FreeType p
+  peek p
 
 -- | The resolution used to render fonts.
 resolutionDPI :: Int
 resolutionDPI = 300
 
-charToBitmap :: MonadIO m => Font -> Double -> Char -> m RenderedChar
-charToBitmap (Font face _ _ refCache) pixel ch = liftIO $ do
-    let siz = pixel * 72 / fromIntegral resolutionDPI
-    cache <- liftIO $ readIORef refCache
-    case M.lookup (siz, ch) cache of
-        Just d -> return d
-        Nothing -> do
-            d <- liftIO $ render face siz ch
-            liftIO $ writeIORef refCache $ M.insert (siz, ch) d cache
-            return d
-
-render :: FT_Face -> Double -> Char -> IO RenderedChar
-render face siz ch = do
-    let dpi = fromIntegral resolutionDPI
+renderChar :: Font -> Float -> Char -> IO (Bitmap, V2 Float, V2 Float)
+renderChar (Font face _ _) siz ch = do
+  let dpi = fromIntegral resolutionDPI
 
-    runFreeType $ ft_Set_Char_Size face 0 (floor $ siz * 64) dpi dpi
-    
-    ix <- ft_Get_Char_Index face (fromIntegral $ fromEnum ch)
-    runFreeType $ ft_Load_Glyph face ix ft_LOAD_DEFAULT
+  runFreeType $ ft_Set_Char_Size face 0 (floor $ siz * 64) dpi dpi
+  
+  ix <- ft_Get_Char_Index face (fromIntegral $ fromEnum ch)
+  runFreeType $ ft_Load_Glyph face ix ft_LOAD_DEFAULT
 
-    slot <- peek $ glyph face
-    runFreeType $ ft_Render_Glyph slot ft_RENDER_MODE_NORMAL
+  slot <- peek $ glyph face
+  runFreeType $ ft_Render_Glyph slot ft_RENDER_MODE_NORMAL
 
-    bmp <- peek $ GS.bitmap slot
-    left <- fmap fromIntegral $ peek $ GS.bitmap_left slot
-    top <- fmap fromIntegral $ peek $ GS.bitmap_top slot
+  bmp <- peek $ GS.bitmap slot
+  left <- fmap fromIntegral $ peek $ GS.bitmap_left slot
+  top <- fmap fromIntegral $ peek $ GS.bitmap_top slot
 
-    let h = fromIntegral $ B.rows bmp
-        w = fromIntegral $ B.width bmp
-    
-    fptr <- newForeignPtr_ $ castPtr $ buffer bmp
+  let h = fromIntegral $ B.rows bmp
+      w = fromIntegral $ B.width bmp
+  
+  fptr <- newForeignPtr_ $ castPtr $ buffer bmp
 
-    adv <- peek $ GS.advance slot
-    b <- liftBitmapIO $ fromColorAndOpacity (PixelRGB8 255 255 255)
-        $ Image w h $ V.unsafeFromForeignPtr0 fptr $ h * w
-    return $ RenderedChar
-        b
-        (V2 (left + fromIntegral w / 2) (-top + fromIntegral h / 2))
-        (fromIntegral (V.x adv) / 64)
+  adv <- peek $ GS.advance slot
+  b <- liftImage' $ fromColorAndOpacity (PixelRGB8 255 255 255)
+      $ Image w h $ V.unsafeFromForeignPtr0 fptr $ h * w
+  return (b
+    , V2 (left + fromIntegral w / 2) (-top + fromIntegral h / 2)
+    , V2 (fromIntegral (V.x adv) / 64) 0)
diff --git a/src/Call/Data/Wave.hs b/src/Call/Data/Wave.hs
--- a/src/Call/Data/Wave.hs
+++ b/src/Call/Data/Wave.hs
@@ -12,6 +12,7 @@
 -----------------------------------------------------------------------------
 module Call.Data.Wave (
   Source(..),
+  Sample(..),
   Stereo,
   readWAVE
 ) where
@@ -21,19 +22,24 @@
 import Call.Types
 import Control.Monad.IO.Class
 import qualified Data.Vector.Unboxed as V
+import GHC.Float
 
 newtype Source a = Source (Time -> a)
 
-type Stereo = V2 Float
-
-readWAVE :: MonadIO m => FilePath -> m (Source Stereo)
+readWAVE :: MonadIO m => FilePath -> m (Sample Stereo)
 readWAVE path = liftIO $ do
   WAVE h ss <- getWAVEFile path
-  
-  return $ Source $ sample h $ V.fromList (map fr ss)
+  let vec = V.fromList (map fr ss)
+      rate = fromIntegral (waveFrameRate h)
+      !dur = fromIntegral (V.length vec) / rate
+      sample t
+        | t < 0 || t >= dur = zero
+        | otherwise = vec V.! floor (t * rate)
+  return $ Sample dur (Source sample)
   where
-    fr [!a, !b] = (realToFrac $ sampleToDouble a, realToFrac $ sampleToDouble b)
-    fr _ = (0, 0)
-    sample h v t = maybe zero (uncurry V2) $ v V.!? floor (t * fromIntegral (waveFrameRate h))
+    fr [a, b] = V2 (double2Float $ sampleToDouble a) (double2Float $ sampleToDouble b)
+    fr _ = zero
+
+data Sample a = Sample { sampleLength :: Time ,sampleSource :: Source a} 
 
 -- TODO: Lazy processing
diff --git a/src/Call/Internal/GLFW.hs b/src/Call/Internal/GLFW.hs
--- a/src/Call/Internal/GLFW.hs
+++ b/src/Call/Internal/GLFW.hs
@@ -13,15 +13,14 @@
 module Call.Internal.GLFW where
 import Control.Bool
 import Control.Applicative
-import Control.Monad.IO.Class
 import Control.Lens
-import Data.Color
 import Data.IORef
 import Call.Types
 import Data.BoundingBox
+import Control.Monad
 import Graphics.Rendering.OpenGL.GL.StateVar
-import Graphics.Rendering.OpenGL.Raw.ARB.Compatibility
 import Linear
+import qualified Graphics.Rendering.OpenGL.Raw as GL
 import qualified Graphics.Rendering.OpenGL.GL as GL
 import qualified Graphics.UI.GLFW as GLFW
 import Unsafe.Coerce
@@ -30,181 +29,170 @@
 import Codec.Picture
 import Codec.Picture.RGBA8
 import qualified GHC.IO.Encoding as Encoding
-
+import qualified Data.Text.IO as Text
+import qualified Data.Text.Encoding as Text
+import Foreign.C (CFloat)
+import Foreign (nullPtr, plusPtr, sizeOf)
+import Paths_call
 data System = System
-    { refRegion :: IORef BoundingBox2
-    , theWindow :: GLFW.Window
-    }
+  { refRegion :: IORef (Box V2 Float)
+  , theWindow :: GLFW.Window
+  , theProgram :: GL.Program
+  }
 
 type Texture = (GL.TextureObject, Double, Double)
 
-runVertices :: MonadIO m => [V2 Double] -> m ()
-runVertices = liftIO . mapM_ (GL.vertex . mkVertex2)
-{-# INLINE runVertices #-}
-
-preservingMatrix' :: MonadIO m => m a -> m a
-preservingMatrix' m = do
-    liftIO glPushMatrix
-    r <- m
-    liftIO glPopMatrix
-    return r
-{-# INLINE preservingMatrix' #-}
-
-drawTexture :: Texture -> IO ()
-drawTexture (tex, !w, !h) = drawTextureAt tex (V2 (-w) (-h)) (V2 w (-h)) (V2 w h) (V2 (-w) h)
-{-# INLINE drawTexture #-}
-
-drawTextureAt :: GL.TextureObject -> V2 Double -> V2 Double -> V2 Double -> V2 Double -> IO ()
-drawTextureAt tex a b c d = do
-    GL.texture GL.Texture2D $= GL.Enabled
-    GL.textureFilter GL.Texture2D $= ((GL.Nearest, Nothing), GL.Nearest)
-    GL.textureBinding GL.Texture2D $= Just tex
-    GL.unsafeRenderPrimitive GL.TriangleStrip $ do
-        GL.texCoord $ GL.TexCoord2 (0 :: GL.GLdouble) 0
-        GL.vertex $ mkVertex2 a
-        GL.texCoord $ GL.TexCoord2 (1 :: GL.GLdouble) 0
-        GL.vertex $ mkVertex2 b
-        GL.texCoord $ GL.TexCoord2 (0 :: GL.GLdouble) 1
-        GL.vertex $ mkVertex2 d
-        GL.texCoord $ GL.TexCoord2 (1 :: GL.GLdouble) 1
-        GL.vertex $ mkVertex2 c
-    GL.texture GL.Texture2D $= GL.Disabled
-
-mkVertex2 :: V2 Double -> GL.Vertex2 GL.GLdouble
-{-# INLINE mkVertex2 #-}
-mkVertex2 = unsafeCoerce
-
 gf :: Float -> GL.GLfloat
 {-# INLINE gf #-}
 gf = unsafeCoerce
 
-gd :: Double -> GL.GLdouble
-{-# INLINE gd #-}
-gd = unsafeCoerce
-
 gsizei :: Int -> GL.GLsizei
 {-# INLINE gsizei #-}
 gsizei = unsafeCoerce
 
-translate :: V2 Double -> IO a -> IO a
-translate (V2 tx ty) m = preservingMatrix' $ GL.translate (GL.Vector3 (gd tx) (gd ty) 0) >> m
-
-rotateD :: Double -> IO a -> IO a
-rotateD theta m = preservingMatrix' $ GL.rotate (gd (-theta)) (GL.Vector3 0 0 1) >> m
+installTexture :: Image PixelRGBA8 -> IO Texture
+installTexture (Image w h v) = do
+  [tex] <- GL.genObjectNames 1
+  GL.textureBinding GL.Texture2D GL.$= Just tex
+  let siz = GL.TextureSize2D (gsizei w) (gsizei h)
+  V.unsafeWith v
+    $ GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.RGBA8 siz 0
+    . GL.PixelData GL.ABGR GL.UnsignedInt8888
+  return (tex, fromIntegral w / 2, fromIntegral h / 2)
 
-scale :: V2 Double -> IO a -> IO a
-scale (V2 sx sy) m = preservingMatrix' $ GL.scale (gd sx) (gd sy) 1 >> m
+releaseTexture :: Texture -> IO ()
+releaseTexture (tex, _, _) = GL.deleteObjectNames [tex]
 
-circle :: Double -> IO ()
-circle r = do
-    let s = 2 * pi / 64
-    GL.renderPrimitive GL.Polygon $ runVertices [V2 (cos t * r) (sin t * r) | t <- [0,s..2 * pi]]
+beginFrame :: System -> IO ()
+beginFrame _ = do
+  GL.clear [GL.ColorBuffer, GL.DepthBuffer]
 
-circleOutline :: Double -> IO ()
-circleOutline r = do
-    let s = 2 * pi / 64
-    GL.renderPrimitive GL.LineLoop $ runVertices [V2 (cos t * r) (sin t * r) | t <- [0,s..2 * pi]]
+endFrame :: System -> IO Bool
+endFrame sys = do
+  GLFW.swapBuffers $ theWindow sys
+  GLFW.pollEvents
+  GLFW.windowShouldClose (theWindow sys)
 
-color :: Color -> IO a -> IO a
-color col m = do
-    oldColor <- liftIO $ get GL.currentColor
-    liftIO $ GL.currentColor $= unsafeCoerce col
-    res <- m
-    liftIO $ GL.currentColor $= oldColor
-    return res
+beginGLFW :: WindowMode -> Box V2 Float -> IO System
+beginGLFW mode bbox@(Box (V2 x0 y0) (V2 x1 y1)) = do
+  Encoding.setForeignEncoding Encoding.utf8
+  let title = "call"
+      ww = floor $ x1 - x0
+      wh = floor $ y1 - y0
+  () <- unlessM GLFW.init (fail "Failed to initialize")
 
-polygon :: [V2 Double] -> IO ()
-polygon path = GL.renderPrimitive GL.Polygon $ runVertices path
+  mon <- case mode of
+    FullScreen -> GLFW.getPrimaryMonitor
+    _ -> return Nothing
 
-polygonOutline :: [V2 Double] -> IO ()
-polygonOutline path = GL.renderPrimitive GL.LineLoop $ runVertices path
+  -- GLFW.windowHint $ GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core
+  -- GLFW.windowHint $ GLFW.WindowHint'OpenGLForwardCompat True
+  GLFW.windowHint $ GLFW.WindowHint'Resizable $ mode == Resizable
+  win <- GLFW.createWindow ww wh title mon Nothing >>= maybe (fail "Failed to create a window") return
+  GLFW.makeContextCurrent (Just win)
+  prog <- initializeGL
 
-line :: [V2 Double] -> IO ()
-line path = GL.renderPrimitive GL.LineStrip $ runVertices path
+  GLFW.swapInterval 1
+  -- GL.clearColor $= GL.Color4 1 1 1 1
+  
+  rbox <- newIORef bbox
 
-thickness :: Float -> IO a -> IO a
-thickness t m = do
-    oldWidth <- liftIO $ get GL.lineWidth
-    liftIO $ GL.lineWidth $= gf t
-    res <- m
-    liftIO $ GL.lineWidth $= oldWidth
-    return res
+  GLFW.setFramebufferSizeCallback win $ Just $ \_ w h -> do
+      modifyIORef rbox $ size zero .~ fmap fromIntegral (V2 w h)
 
-installTexture :: Image PixelRGBA8 -> IO Texture
-installTexture (Image w h v) = do
-    [tex] <- GL.genObjectNames 1
-    GL.textureBinding GL.Texture2D GL.$= Just tex
-    let siz = GL.TextureSize2D (gsizei w) (gsizei h)
-    V.unsafeWith v
-        $ GL.texImage2D GL.Texture2D GL.NoProxy 0 GL.RGBA8 siz 0
-        . GL.PixelData GL.ABGR GL.UnsignedInt8888
-    return (tex, fromIntegral w / 2, fromIntegral h / 2)
+  return $ System rbox win prog
 
-releaseTexture :: Texture -> IO ()
-releaseTexture (tex, _, _) = GL.deleteObjectNames [tex]
+compileShader :: FilePath -> GL.Shader -> IO ()
+compileShader path shader = do
+  src <- getDataFileName path >>= Text.readFile
+  GL.shaderSourceBS shader $= Text.encodeUtf8 src
+  GL.compileShader shader
+  GL.get (GL.shaderInfoLog shader) >>= putStrLn
 
-beginFrame :: System -> IO ()
-beginFrame sys = do
-    Box (V2 wl wt) (V2 wr wb) <- fmap realToFrac <$> readIORef (refRegion sys)
-    GL.viewport $= (GL.Position 0 0, GL.Size (floor $ wr - wl) (floor $ wb - wt))
-    GL.matrixMode $= GL.Projection
-    GL.loadIdentity
-    GL.ortho wl wr wb wt 0 (-100)
-    GL.matrixMode $= GL.Modelview 0
-    GL.clear [GL.ColorBuffer]
+initializeGL :: IO GL.Program
+initializeGL = do
+  let vertexAttribute = GL.AttribLocation 0
+  let uvAttribute = GL.AttribLocation 1
+  let normalAttribute = GL.AttribLocation 2
+  
+  cubeVao <- GL.genObjectName
+  cubeVbo <- GL.genObjectName
 
-endFrame :: System -> IO Bool
-endFrame sys = do
-    GLFW.swapBuffers $ theWindow sys
-    GLFW.pollEvents
-    GLFW.windowShouldClose (theWindow sys)
+  GL.bindVertexArrayObject $= Just cubeVao
+  GL.bindBuffer GL.ArrayBuffer $= Just cubeVbo
 
-beginGLFW :: WindowMode -> BoundingBox2 -> IO System
-beginGLFW mode bbox@(Box (V2 x0 y0) (V2 x1 y1)) = do
-    Encoding.setForeignEncoding Encoding.utf8
-    let title = "call"
-        ww = floor $ x1 - x0
-        wh = floor $ y1 - y0
-    () <- unlessM GLFW.init (fail "Failed to initialize")
+  let stride = fromIntegral $ sizeOf (undefined :: Vertex)
 
-    mon <- case mode of
-        FullScreen -> GLFW.getPrimaryMonitor
-        _ -> return Nothing
+  GL.vertexAttribPointer vertexAttribute $=
+    (GL.ToFloat,GL.VertexArrayDescriptor 3 GL.Float stride nullPtr)
 
-    GLFW.windowHint $ GLFW.WindowHint'Resizable $ mode == Resizable
-    win <- GLFW.createWindow ww wh title mon Nothing >>= maybe (fail "Failed to create a window") return
-    GLFW.makeContextCurrent (Just win)
-    GL.lineSmooth $= GL.Enabled
-    GL.blend      $= GL.Enabled
-    GL.blendFunc  $= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
-    -- GL.shadeModel $= GL.Flat
-    GL.textureFunction $= GL.Combine
+  GL.vertexAttribArray vertexAttribute $= GL.Enabled
+  GL.bindBuffer GL.ArrayBuffer $= Just cubeVbo
 
-    GLFW.swapInterval 1
-    GL.clearColor $= GL.Color4 1 1 1 1
+  GL.vertexAttribPointer uvAttribute $=
+    (GL.ToFloat
+    ,GL.VertexArrayDescriptor 2 GL.Float stride (nullPtr `plusPtr` sizeOf (0 :: V3 CFloat)))
+  GL.vertexAttribArray uvAttribute $= GL.Enabled
 
-    rbox <- newIORef bbox
+  GL.vertexAttribPointer normalAttribute $=
+    (GL.ToFloat
+    ,GL.VertexArrayDescriptor 3 GL.Float stride
+      (nullPtr `plusPtr` sizeOf (0 :: V3 CFloat) `plusPtr` sizeOf (0 :: V2 CFloat)))
+  GL.vertexAttribArray normalAttribute $= GL.Enabled
 
-    GLFW.setFramebufferSizeCallback win $ Just $ \_ w h -> do
-        modifyIORef rbox $ size zero .~ fmap fromIntegral (V2 w h)
+  vertexShader <- GL.createShader GL.VertexShader
+  fragmentShader <- GL.createShader GL.FragmentShader
+  compileShader "shaders/vertex.glsl" vertexShader
+  compileShader "shaders/fragment.glsl" fragmentShader
+  shaderProg <- GL.createProgram
+  GL.attachShader shaderProg vertexShader
+  GL.attachShader shaderProg fragmentShader
+  GL.attribLocation shaderProg "in_Position" $= vertexAttribute
+  GL.attribLocation shaderProg "in_UV" $= uvAttribute
+  GL.attribLocation shaderProg "in_Normal" $= normalAttribute
+  GL.linkProgram shaderProg
+  GL.currentProgram $= Just shaderProg
+  
+  -- GL.blend $= GL.Disabled
+  GL.depthMask $= GL.Enabled
+  GL.depthFunc $= Just GL.Lequal
+  GL.colorMask $= GL.Color4 GL.Enabled GL.Enabled GL.Enabled GL.Enabled
+  {-
+  GL.depthMask $= GL.Disabled
+  GL.depthFunc $= Nothing
+  
+  GL.colorMask $= GL.Color4 GL.Enabled GL.Enabled GL.Enabled GL.Enabled
+  -}
+  -- GL.cullFace $= GL.Back
+  GL.blend      $= GL.Enabled
+  GL.blendFunc  $= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
+  linked <- GL.get (GL.linkStatus shaderProg)
+  unless linked $ do
+    GL.get (GL.programInfoLog shaderProg) >>= putStrLn
+  
+  GL.lineSmooth $= GL.Enabled
+  GL.textureFunction $= GL.Combine
+  GL.clearColor $= GL.Color4 1 1 1 1
+  GL.UniformLocation loc <- GL.get $ GL.uniformLocation shaderProg "useEnv"
+  GL.glUniform1i loc 0
 
-    return $ System rbox win
+  return shaderProg
 
 endGLFW :: System -> IO ()
 endGLFW sys = do
-    GLFW.destroyWindow (theWindow sys)
-    GLFW.terminate
+  GLFW.destroyWindow (theWindow sys)
+  GLFW.terminate
 
 screenshotFlipped :: System -> IO (Image PixelRGBA8)
 screenshotFlipped sys = do
-    V2 w h <- fmap floor <$> view (size zero) <$> readIORef (refRegion sys)
-    mv <- MV.unsafeNew (w * h * 4)
-    GL.readBuffer $= GL.FrontBuffers
-    MV.unsafeWith mv
-        $ \ptr -> GL.readPixels (GL.Position 0 0) (GL.Size (gsizei w) (gsizei h))
-            (GL.PixelData GL.RGBA GL.UnsignedByte ptr)
+  V2 w h <- fmap floor <$> view (size zero) <$> readIORef (refRegion sys)
+  mv <- MV.unsafeNew (w * h * 4)
+  GL.readBuffer $= GL.FrontBuffers
+  MV.unsafeWith mv
+      $ \ptr -> GL.readPixels (GL.Position 0 0) (GL.Size (gsizei w) (gsizei h))
+          (GL.PixelData GL.RGBA GL.UnsignedByte ptr)
 
-    Image w h <$> V.unsafeFreeze mv
+  Image w h <$> V.unsafeFreeze mv
 
 screenshot :: System -> IO (Image PixelRGBA8)
 screenshot sys = flipVertically <$> screenshotFlipped sys
@@ -218,8 +206,8 @@
 
 blendMode :: BlendMode -> IO a -> IO a
 blendMode mode m = do
-    oldFunc <- get GL.blendFunc
-    GL.blendFunc $= blendMode2BlendingFactors mode
-    a <- m
-    GL.blendFunc $= oldFunc
-    return a
+  oldFunc <- get GL.blendFunc
+  GL.blendFunc $= blendMode2BlendingFactors mode
+  a <- m
+  GL.blendFunc $= oldFunc
+  return a
diff --git a/src/Call/Internal/PortAudio.hs b/src/Call/Internal/PortAudio.hs
--- a/src/Call/Internal/PortAudio.hs
+++ b/src/Call/Internal/PortAudio.hs
@@ -10,6 +10,9 @@
 import Linear
 import Control.Exception
 import Data.Typeable
+import qualified Data.Vector.Storable as V
+import qualified Data.Vector.Storable.Mutable as MV
+
 data Error = NotInitialized
   | UnanticipatedHostError
   | InvalidChannelCount
@@ -56,34 +59,35 @@
       name <- peekCAString $ c'PaHostApiInfo'name info
       return (Host (fromIntegral i) name)
 -}
-callback :: (Int -> IO [V2 Float]) -> Ptr () -> Ptr () -> CULong -> x -> y -> z -> IO CUInt
-callback f (castPtr -> _) (castPtr -> pout) (fromIntegral -> n) _ _ _ = do
-  f n >>= pokeArray pout
+callback :: (Int -> IO (V.Vector (V2 Float))) -> Ptr () -> Ptr () -> CULong -> x -> y -> z -> IO CUInt
+callback f _ (castPtr -> pout) (fromIntegral -> n) _ _ _ = do
+  fp <- newForeignPtr_ pout
+  f n >>= V.unsafeCopy (MV.unsafeFromForeignPtr0 fp n)
   return c'paContinue
 
-with :: MonadIO m => Double -> Int -> (Int -> IO [V2 Float]) -> m a -> m a
+with :: MonadIO m => Float -> Int -> (Int -> IO (V.Vector (V2 Float))) -> m a -> m a
 with rate buf f m = do
-    w c'Pa_Initialize
-    cb <- liftIO $ mk'PaStreamCallback $ callback f
-    
-    ps <- liftIO malloc
-    w $ c'Pa_OpenDefaultStream ps
-        0
-        2
-        1 -- Float
-        (realToFrac rate)
-        (fromIntegral buf)
-        cb
-        nullPtr
-    s <- liftIO $ peek ps
+  w c'Pa_Initialize
+  cb <- liftIO $ mk'PaStreamCallback $ callback f
+  
+  ps <- liftIO malloc
+  w $ c'Pa_OpenDefaultStream ps
+      0
+      2
+      1 -- Float
+      (realToFrac rate)
+      (fromIntegral buf)
+      cb
+      nullPtr
+  s <- liftIO $ peek ps
 
-    w $ c'Pa_StartStream s
-    r <- m
-    w $ c'Pa_StopStream s
-    w $ c'Pa_CloseStream s
-    w $ c'Pa_Terminate
-    return r
-    where
-      w n = do
-        r <- liftIO n
-        unless (r == 0) $ liftIO $ throwIO $ fromErrorCode r
+  w $ c'Pa_StartStream s
+  r <- m
+  w $ c'Pa_StopStream s
+  w $ c'Pa_CloseStream s
+  w $ c'Pa_Terminate
+  return r
+  where
+    w n = do
+      r <- liftIO n
+      unless (r == 0) $ liftIO $ throwIO $ fromErrorCode r
diff --git a/src/Call/Picture.hs b/src/Call/Picture.hs
deleted file mode 100644
--- a/src/Call/Picture.hs
+++ /dev/null
@@ -1,85 +0,0 @@
-{-# LANGUAGE BangPatterns, DeriveFunctor, Rank2Types #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Call.Picture
--- Copyright   :  (c) Fumiaki Kinoshita 2014
--- License     :  BSD3
---
--- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
---
------------------------------------------------------------------------------
-module Call.Picture where
-import Call.Types
-import Call.Data.Bitmap
-import Data.Color
-import Control.Applicative
-
-infixr 5 `translate`
-infixr 5 `rotateR`
-infixr 5 `rotateD`
-infixr 5 `scale`
-infixr 5 `color`
-infixr 5 `thickness`
-infixr 5 `blendMode`
-
-class Functor p => Affine p where
-    -- | (radians)
-    rotateR :: Double -> p a -> p a
-    -- | (degrees)
-    rotateD :: Double -> p a -> p a
-    scale :: Vec2 -> p a -> p a
-    translate :: Vec2 -> p a -> p a
-
-    rotateR = rotateD . (* 180) . (/ pi)
-    rotateD = rotateR . (/ 180) . (* pi)
-
--- | The class of types that can be regarded as a kind of picture.
-class Affine p => Picture2D p where
-    -- | Construct a 'Picture2D' from a 'Bitmap'.
-    bitmap :: Bitmap -> p ()
-    -- | Same as 'bitmap', but it does not create a cache.
-    bitmapOnce :: Bitmap -> p ()
-    line :: [Vec2] -> p ()
-    polygon :: [Vec2] -> p ()
-    polygonOutline :: [Vec2] -> p ()
-    circle :: Double -> p ()
-    circleOutline :: Double -> p ()
-    thickness :: Float -> p a -> p a
-    color :: Color -> p a -> p a
-    blendMode :: BlendMode -> p a -> p a
-
-opacity :: Picture2D p => Float -> p a -> p a
-opacity a = color (Color 1 1 1 a)
-
-newtype Picture a = Picture { runPicture :: forall m. (Applicative m, Monad m, Picture2D m) => m a }
-
-instance Functor Picture where
-    fmap f (Picture m) = Picture (fmap f m)
-
-instance Applicative Picture where
-    pure a = Picture (pure a)
-    Picture a <*> Picture b = Picture (a <*> b)
-
-instance Monad Picture where
-    return a = Picture (return a)
-    Picture m >>= k = Picture (m >>= runPicture . k)
-
-instance Affine Picture where
-    rotateR t (Picture m) = Picture (rotateR t m)
-    rotateD t (Picture m) = Picture (rotateD t m)
-    scale v (Picture m) = Picture (scale v m)
-    translate v (Picture m) = Picture (translate v m)
-
-instance Picture2D Picture where
-    bitmap b = Picture (bitmap b)
-    bitmapOnce b = Picture (bitmapOnce b)
-    line vs = Picture (line vs)
-    polygon vs = Picture (polygon vs)
-    polygonOutline vs = Picture (polygonOutline vs)
-    circle r = Picture (circle r)
-    circleOutline r = Picture (circleOutline r)
-    thickness t (Picture m) = Picture (thickness t m)
-    color c (Picture m) = Picture (color c m)
-    blendMode b (Picture m) = Picture (blendMode b m)
diff --git a/src/Call/Sight.hs b/src/Call/Sight.hs
new file mode 100644
--- /dev/null
+++ b/src/Call/Sight.hs
@@ -0,0 +1,183 @@
+{-# LANGUAGE TypeFamilies
+  , FlexibleContexts
+  , BangPatterns
+  , DeriveFunctor
+  , Rank2Types
+  , FlexibleInstances
+  , UndecidableInstances
+  , ViewPatterns
+  , ScopedTypeVariables
+  , GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Call.Scene
+-- Copyright   :  (c) Fumiaki Kinoshita 2014
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-----------------------------------------------------------------------------
+module Call.Sight (Affine(..)
+    , Figure(..)
+    , Picture(..)
+    , bitmap
+    , toward
+    , Scene(..)
+    , transformScene
+    , vertices
+    , Sight(..)
+    , viewPicture
+    , viewScene
+    , fromPerspective
+    , VFX(..)
+    , applyVFX
+    , GL.PrimitiveMode(..)
+    ) where
+import qualified Call.Data.Bitmap as B
+import qualified Data.BoundingBox as X
+import Data.Monoid
+import Linear
+import qualified Data.Vector.Storable as V
+import Control.Lens
+import qualified Graphics.Rendering.OpenGL.GL as GL
+import Data.Color
+import Call.Types
+import Control.Monad.Trans.Writer.Strict as Strict
+import Control.Monad.Trans.Writer.Lazy as Lazy
+
+class Affine a where
+  type Vec a :: *
+  type Normal a :: *
+  rotateOn :: Normal a -> a -> a
+  scale :: Vec a -> a -> a
+  translate :: Vec a -> a -> a
+
+class Affine a => Figure a where
+  primitive :: GL.PrimitiveMode -> [Vec a] -> a
+  color :: RGBA -> a -> a
+  line :: [Vec a] -> a
+  polygon :: [Vec a] -> a
+  polygonOutline :: [Vec a] -> a
+  circle :: Normal a -> a
+  circleOutline :: Normal a -> a
+
+bitmap :: B.Bitmap -> Picture
+bitmap bmp = Picture $ Scene
+  $ \_ _ f _ _ -> f bmp GL.TriangleStrip
+    (V.fromList [V3 (-w/2) (-h/2) 0 `positionUV` V2 0 0
+        , V3 (w/2) (-h/2) 0 `positionUV` V2 1 0
+        , V3 (-w/2) (h/2) 0 `positionUV` V2 0 1
+        , V3 (w/2) (h/2) 0 `positionUV` V2 1 1]) where
+  V2 w h = fmap fromIntegral $ B.size bmp
+
+toward :: Vec3 -> Picture -> Scene
+toward n@((^/norm n) -> V3 x y z) (Picture s) = transformScene
+  (m33_to_m44 $ fromQuaternion $ axisAngle (V3 (-y) x 0) $ acos $ z / norm n)
+  s
+
+newtype Scene = Scene { unScene :: forall r.
+  r
+  -> (r -> r -> r)
+  -> (B.Bitmap -> GL.PrimitiveMode -> V.Vector Vertex -> r)
+  -> (VFX r -> r)
+  -> (M44 Float -> r -> r)
+  -> r
+  }
+
+data VFX r = SphericalAdd Bitmap r
+  | SphericalMultiply Bitmap r
+  | Diffuse RGBA r
+  deriving Functor
+  {-
+  | Opacity r
+  | Light RGBA Float (V3 Float) (V4 Float)
+  | Specular RGB
+  | Ambient RGB
+  -}
+
+instance Affine Scene where
+  type Vec Scene = V3 Float
+  type Normal Scene = V3 Float
+  rotateOn v = transformScene $ m33_to_m44 $ fromQuaternion $ axisAngle v (norm v)
+  scale (V3 x y z) = transformScene $ V4
+    (V4 x 0 0 0)
+    (V4 0 y 0 0)
+    (V4 0 0 z 0)
+    (V4 0 0 0 1)
+  translate v = transformScene $ translation .~ v $ eye4
+
+instance Figure Scene where
+  primitive m vs = Scene $ \_ _ f _ _ -> f Blank m (V.fromList $ map positionOnly vs)
+  color col (Scene s) = Scene $ \e a f b t -> b (Diffuse col (s e a f b t))
+  line = primitive GL.LineStrip
+  polygon = primitive GL.Polygon
+  polygonOutline = primitive GL.LineLoop
+  circle v = toward v $ circle $ norm v
+  circleOutline v = toward v $ circleOutline $ norm v
+
+unit_circle :: Int -> [V2 Float]
+unit_circle n = map angle [0,2*pi/fromIntegral n..2*pi]
+
+instance Monoid Scene where
+  mempty = Scene $ \e _ _ _ _ -> e
+  mappend (Scene x) (Scene y) = Scene $ \e a f b t -> a (x e a f b t) (y e a f b t)
+
+v2ToV3 :: Num a => V2 a -> V3 a
+v2ToV3 (V2 x y) = V3 x y 0
+
+vertices :: B.Bitmap -> GL.PrimitiveMode -> V.Vector Vertex -> Scene
+vertices b m v = Scene $ \_ _ f _ _ -> f b m v
+
+transformScene :: M44 Float -> Scene -> Scene
+transformScene m (Scene pic) = Scene $ \e a f b t -> t m (pic e a f b t)
+
+applyVFX :: VFX Scene -> Scene
+applyVFX vf = Scene $ \e a f b t -> b $ fmap (\(Scene s) -> s e a f b t) vf
+
+newtype Picture = Picture { unPicture :: Scene } deriving Monoid
+
+instance Affine Picture where
+  type Vec Picture = V2 Float
+  type Normal Picture = Float
+  rotateOn t (Picture s) = Picture (transformScene m s) where
+    m = V4 (V4 (cos t) (-sin t) 0 0) (V4 (sin t) (cos t) 0 0) (V4 0 0 1 0) (V4 0 0 0 1)
+  translate (V2 x y) (Picture s) = Picture $ transformScene (translation .~ V3 x y 0 $ eye4) s
+  scale (V2 x y) (Picture s) = Picture (transformScene m s) where
+    m = V4 (V4 x 0 0 0) (V4 0 y 0 0) (V4 0 0 1 0) (V4 0 0 0 1)
+
+instance Figure Picture where
+  primitive m v = Picture $ primitive m $ map v2ToV3 v
+  color col (Picture s) = Picture (color col s)
+  line = primitive GL.LineStrip
+  polygon = primitive GL.Polygon
+  polygonOutline = primitive GL.LineLoop
+  circle r = polygon $ map (^*r) $ unit_circle 33
+  circleOutline r = polygonOutline $ map (^*r) $ unit_circle 33
+
+newtype Sight = Sight { unSight
+  :: forall r. 
+  X.Box V2 Float
+  -> r
+  -> (r -> r -> r)
+  -> (X.Box V2 Float -> M44 Float -> Bool -> Scene -> r)
+  -> r
+  }
+
+instance Monoid Sight where
+  mempty = Sight $ \_ e _ _ -> e
+  mappend (Sight x) (Sight y) = Sight $ \b e a f -> a (x b e a f) (y b e a f)
+
+viewPicture :: Picture -> Sight
+viewPicture (Picture s) = Sight $ \box@(X.Box (V2 x0 y0) (V2 x1 y1)) _ _ f -> f box (ortho x0 x1 y1 y0 (-1) 1) False s
+
+viewScene :: Float -- ^ FOV
+  -> Float -- ^ Near plane
+  -> Float -- ^ Far plane
+  -> Scene -- ^ The scene
+  -> Sight
+viewScene fov near far = fromPerspective $ \box -> perspective fov (let V2 w h = box ^. X.size 0 in w/h) near far
+
+fromPerspective :: (X.Box V2 Float -> M44 Float) -> Scene -> Sight
+fromPerspective mat s = Sight $ \box _ _ f -> f box (mat box) True s
diff --git a/src/Call/System.hs b/src/Call/System.hs
--- a/src/Call/System.hs
+++ b/src/Call/System.hs
@@ -9,11 +9,14 @@
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE GADTs #-}
 {-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 -----------------------------------------------------------------------------
@@ -27,42 +30,89 @@
 -- Portability :  non-portable
 --
 -----------------------------------------------------------------------------
-module Call.System (System, runSystem, MonadSystem(..), forkSystem) where
+module Call.System (
+  -- * The system
+  System
+  , runSystem
+  , forkSystem
+  -- * Time
+  , stand
+  , wait
+  , getTime
+  , setFPS
+  -- * Raw input
+  , keyPress
+  , mousePosition
+  , mouseButton
+  , enableCursor
+  , hideCursor
+  , disableCursor
+  , getGamepads
+  , gamepadButtons
+  , gamepadAxes
+  -- * Component
+  , linkGraphic
+  , linkPicture
+  , linkAudio
+  , linkKeyboard
+  , linkMouse
+  , linkGamepad
+  -- * Others
+  , setTitle
+  , clearColor
+  , getBoundingBox
+  , setBoundingBox
+  , takeScreenshot
+  ) where
 
-import Call.Component
 import Call.Data.Bitmap
-import Call.Picture
+import Call.Sight
 import Call.Types
 import Control.Applicative
 import Control.Concurrent
 import Control.Exception
-import Control.Monad.IO.Class
+import Control.Elevator
+import Control.Lens
+import Control.Monad.Objective
 import Control.Monad.Reader
 import Control.Object
-import Control.Monad.Objective
+import Data.BoundingBox (Box(..))
+import Data.Color
+import Data.OpenUnion1.Clean
 import Data.IORef
-import Data.Reflection
+import Data.Maybe
+import Data.Monoid
+import Foreign (castPtr, sizeOf, with)
+import Graphics.Rendering.OpenGL.GL.StateVar
 import Linear
 import qualified Call.Internal.GLFW as G
+import qualified Call.Internal.PortAudio as PA
+import qualified Codec.Picture as C
 import qualified Data.IntMap.Strict as IM
+import qualified Data.Vector.Storable as V
+import qualified Graphics.Rendering.OpenGL.GL as GL
+import qualified Graphics.Rendering.OpenGL.Raw as GL
 import qualified Graphics.UI.GLFW as GLFW
-import qualified Call.Internal.PortAudio as PA
 import Unsafe.Coerce
 
-class (MonadIO m, MonadObjective m) => MonadSystem m where
-  linkMouse :: Mouse e => Address e m -> m ()
-  linkKeyboard :: Keyboard e => Address e m -> m ()
-  linkGraphic :: Graphic e => Address e m -> m ()
-  linkAudio :: Audio e => Address e m -> m ()
-  unlinkMouse :: Address e m -> m ()
-  unlinkKeyboard :: Address e m -> m ()
-  unlinkGraphic :: Address e m -> m ()
-  unlinkAudio :: Address e m -> m ()
-  stand :: m ()
-  wait :: Double -> m ()
+setFPS :: Float -> System s ()
+setFPS f = mkSystem $ \fo -> writeIORef (targetFPS fo) f
 
 newtype System s a = System (ReaderT (Foundation s) IO a) deriving (Functor, Applicative, Monad)
 
+instance MonadObjective (System s) where
+  data Instance e m (System s) = InstanceS (MVar (Object e m))
+  InstanceS m `invoke` e = do
+    c <- liftIO $ takeMVar m
+    return $ do
+      (a, c') <- runObject c e
+      return (liftIO (putMVar m c') >> return a)
+  new v = liftIO $ InstanceS `fmap` newMVar v
+
+instance Tower (System s) where
+  type Floors (System s) = IO :> Empty
+  toLoft = liftIO ||> exhaust
+
 unSystem :: Foundation s -> System s a -> IO a
 unSystem f m = unsafeCoerce m f
 
@@ -72,162 +122,307 @@
 forkSystem :: System s () -> System s ThreadId
 forkSystem m = mkSystem $ \fo -> forkIO (unSystem fo m)
 
-runSystem :: WindowMode -> BoundingBox2 -> (forall s. System s a) -> IO (Maybe a)
-runSystem mode box m = do
-    sys <- G.beginGLFW mode box
-    f <- Foundation
-        <$> newMVar 0
-        <*> pure 44100 -- FIX THIS
-        <*> newIORef IM.empty
-        <*> newIORef IM.empty
-        <*> newIORef IM.empty
-        <*> newIORef IM.empty
-        <*> newMVar 0
-        <*> pure sys
-        <*> newIORef 60
-        <*> newIORef IM.empty
-        <*> newEmptyMVar
-    let win = G.theWindow sys
-    GLFW.setKeyCallback win $ Just $ keyCallback f
-    GLFW.setMouseButtonCallback win $ Just $ mouseButtonCallback f
-    GLFW.setCursorPosCallback win $ Just $ cursorPosCallback f
-    GLFW.setScrollCallback win $ Just $ scrollCallback f
-    ref <- newEmptyMVar
-    _ <- flip forkFinally (either throwIO (putMVar ref)) $ unSystem f m
-    PA.with 44100 512 (audioProcess f) $ liftIO $ do
-        GLFW.setTime 0
-        runGraphic f 0
-    G.endGLFW sys
-    tryTakeMVar ref
+linkGraphic :: (Time -> System s Sight) -> System s ()
+linkGraphic f = mkSystem $ \fo -> do
+  g <- readIORef $ coreGraphic fo
+  writeIORef (coreGraphic fo) $ \dt -> liftA2 (<>) (f dt) (g dt)
 
-data Member c s = forall e. c e => Member (MVar (Object e (System s)))
+linkPicture :: (Time -> System s Picture) -> System s ()
+linkPicture f = linkGraphic (fmap viewPicture . f)
 
+linkAudio :: (Time -> Int -> System s (V.Vector Stereo)) -> System s ()
+linkAudio f = mkSystem $ \fo -> do
+  g <- readIORef $ coreAudio fo
+  writeIORef (coreAudio fo) $ \dt n -> liftA2 (V.zipWith (+)) (f dt n) (g dt n)
+
+linkKeyboard :: (Chatter Key -> System s ()) -> System s ()
+linkKeyboard f = mkSystem $ \fo -> do
+  g <- readIORef $ coreKeyboard fo
+  writeIORef (coreKeyboard fo) $ \k -> f k >> g k
+
+linkMouse :: (MouseEvent -> System s ()) -> System s ()
+linkMouse f = mkSystem $ \fo -> do
+  g <- readIORef $ coreMouse fo
+  writeIORef (coreMouse fo) $ \k -> f k >> g k
+
+linkGamepad :: (GamepadEvent -> System s ()) -> System s ()
+linkGamepad f = mkSystem $ \fo -> do
+  g <- readIORef $ coreJoypad fo
+  writeIORef (coreJoypad fo) $ \k -> f k >> g k
+
 data Foundation s = Foundation
-    { newObjectId :: MVar Int
-    , sampleRate :: Double
-    , coreGraphic :: IORef (IM.IntMap (Member Graphic s))
-    , coreAudio :: IORef (IM.IntMap (Member Audio s))
-    , coreKeyboard :: IORef (IM.IntMap (Member Keyboard s))
-    , coreMouse :: IORef (IM.IntMap (Member Mouse s))
-    , theTime :: MVar Double
-    , theSystem :: G.System
-    , targetFPS :: IORef Double
-    , textures :: IORef (IM.IntMap G.Texture)
-    , theEnd :: MVar ()
-    }
+  { sampleRate :: Float
+  , coreGraphic :: IORef (Time -> System s Sight)
+  , coreAudio :: IORef (Time -> Int -> System s (V.Vector (V2 Float)))
+  , coreKeyboard :: IORef (Chatter Key -> System s ())
+  , coreMouse :: IORef (MouseEvent -> System s ())
+  , coreJoypad :: IORef (GamepadEvent -> System s ())
+  , theTime :: MVar Time
+  , theSystem :: G.System
+  , targetFPS :: IORef Float
+  , textures :: IORef (IM.IntMap G.Texture)
+  , theEnd :: MVar ()
+  , theGamepadButtons :: IORef (IM.IntMap (String, IM.IntMap Bool))
+  }
 
+runSystem :: WindowMode -> Box V2 Float -> (forall s. System s a) -> IO (Maybe a)
+runSystem mode box m = do
+  sys <- G.beginGLFW mode box
+  f <- Foundation
+    <$> pure 44100 -- FIX THIS
+    <*> newIORef (const $ return mempty)
+    <*> newIORef (\_ n -> return $ V.replicate n zero)
+    <*> newIORef (const $ return ())
+    <*> newIORef (const $ return ())
+    <*> newIORef (const $ return ())
+    <*> newMVar 0
+    <*> pure sys
+    <*> newIORef 60
+    <*> newIORef IM.empty
+    <*> newEmptyMVar
+    <*> newIORef IM.empty
+  let win = G.theWindow sys
+  GLFW.setKeyCallback win $ Just $ keyCallback f
+  GLFW.setMouseButtonCallback win $ Just $ mouseButtonCallback f
+  GLFW.setCursorPosCallback win $ Just $ cursorPosCallback f
+  GLFW.setScrollCallback win $ Just $ scrollCallback f
+  GL.UniformLocation loc <- GL.get $ GL.uniformLocation (G.theProgram sys) "color"
+  with (V4 1 1 1 1 :: V4 Float) $ \ptr -> GL.glUniform4fv loc 1 (castPtr ptr)
+
+  print =<< GLFW.getWindowClientAPI win
+  putStr "OpenGL Version: "
+  cv0 <- GLFW.getWindowContextVersionMajor    win
+  cv1 <- GLFW.getWindowContextVersionMinor    win
+  cv2 <- GLFW.getWindowContextVersionRevision win
+  putStrLn $ show cv0 ++ "." ++ show cv1 ++ "." ++ show cv2 
+  print =<< GLFW.getWindowContextRobustness win
+  putStr "Forward compat: "
+  print =<< GLFW.getWindowOpenGLForwardCompat win
+  putStr "Debug context: "
+  print =<< GLFW.getWindowOpenGLDebugContext win
+  print =<< GLFW.getWindowOpenGLProfile win
+  
+  ref <- newEmptyMVar
+  _ <- flip forkFinally (either throwIO (putMVar ref)) $ unSystem f m
+  PA.with 44100 512 (audioProcess f) $ liftIO $ do
+    GLFW.setTime 0
+    runGraphic f 0
+  G.endGLFW sys
+  tryTakeMVar ref
+
+stand :: System s ()
+stand = mkSystem $ \fo -> takeMVar (theEnd fo)
+
+wait :: Time -> System s ()
+wait dt = mkSystem $ \fo -> do
+  t0 <- takeMVar (theTime fo)
+  Just t <- GLFW.getTime
+  threadDelay $ floor $ (t0 - realToFrac t + dt) * 1000 * 1000
+  putMVar (theTime fo) $ t0 + dt
+
+getTime :: System s Time
+getTime = mkSystem $ \fo -> readMVar (theTime fo)
+
+keyPress :: Key -> System s Bool
+keyPress k = mkSystem $ \fo -> fmap (/=GLFW.KeyState'Released)
+  $ GLFW.getKey (G.theWindow $ theSystem fo) (toEnum . fromEnum $ k)
+
+mousePosition :: System s (V2 Float)
+mousePosition = mkSystem $ \fo -> do
+  (x, y) <- GLFW.getCursorPos (G.theWindow $ theSystem fo)
+  return $ V2 (realToFrac x) (realToFrac y)
+
+hideCursor :: System s ()
+hideCursor = mkSystem $ \fo -> GLFW.setCursorInputMode (G.theWindow $ theSystem fo) GLFW.CursorInputMode'Hidden
+
+disableCursor :: System s ()
+disableCursor = mkSystem $ \fo -> GLFW.setCursorInputMode (G.theWindow $ theSystem fo) GLFW.CursorInputMode'Disabled
+
+enableCursor :: System s ()
+enableCursor = mkSystem $ \fo -> GLFW.setCursorInputMode (G.theWindow $ theSystem fo) GLFW.CursorInputMode'Normal
+
+mouseButton :: Int -> System s Bool
+mouseButton b = mkSystem $ \fo -> fmap (/=GLFW.MouseButtonState'Released)
+  $ GLFW.getMouseButton (G.theWindow $ theSystem fo) (toEnum b)
+
+getGamepads :: System s [Gamepad]
+getGamepads = mkSystem $ const $ fmap catMaybes $ forM [(GLFW.Joystick'1)..]
+  $ \j -> fmap (Gamepad (fromEnum j)) <$> GLFW.getJoystickName j
+
+gamepadAxes :: Gamepad -> System s [Float]
+gamepadAxes (Gamepad i _) = mkSystem $ const $ maybe [] (map realToFrac) <$> GLFW.getJoystickAxes (toEnum i)
+
+gamepadButtons :: Gamepad -> System s [Bool]
+gamepadButtons (Gamepad i _) = mkSystem $ const
+  $ maybe [] (map (==GLFW.JoystickButtonState'Pressed)) <$> GLFW.getJoystickButtons (toEnum i)
+
+clearColor :: RGBA -> System s ()
+clearColor col = liftIO $ GL.clearColor $= unsafeCoerce col
+
+setBoundingBox :: Box V2 Float -> System s ()
+setBoundingBox box@(Box (V2 x0 y0) (V2 x1 y1)) = mkSystem $ \fo -> do
+  GLFW.setWindowSize (G.theWindow $ theSystem fo) (floor (x1 - x0)) (floor (y1 - y0))
+  writeIORef (G.refRegion $ theSystem fo) box
+
+getBoundingBox :: System s (Box V2 Float)
+getBoundingBox = mkSystem $ \fo -> readIORef (G.refRegion $ theSystem fo)
+
+takeScreenshot :: System s Bitmap
+takeScreenshot = mkSystem $ \fo -> G.screenshot (theSystem fo) >>= liftImage'
+
+setTitle :: String -> System s ()
+setTitle str = mkSystem $ \fo -> GLFW.setWindowTitle (G.theWindow $ theSystem fo) str
+    
 instance MonadIO (System s) where
-    liftIO m = mkSystem $ const m
-    {-# INLINE liftIO #-}
+  liftIO m = mkSystem $ const m
+  {-# INLINE liftIO #-}
 
-instance MonadObjective (System s) where
-    type Residence (System s) = System s
-    data Address e (System s) = Control　Int (MVar (Object e (System s)))
-    Control _ m .- e = mkSystem $ \fo -> push fo m e
-    new c = mkSystem $ \fo -> do
-        n <- takeMVar $ newObjectId fo
-        mc <- newMVar c
-        putMVar (newObjectId fo) (n + 1)
-        return (Control n mc)
+pollGamepad :: Foundation s -> IO ()
+pollGamepad fo = do
+  m <- readIORef (coreJoypad fo)
+  ps <- IM.fromList <$> map (\p@(Gamepad i _) -> (i, p)) <$> unSystem fo getGamepads
+  bs0 <- readIORef (theGamepadButtons fo)
 
-instance MonadSystem (System s) where
-    linkGraphic (Control i mc) = mkSystem $ \fo -> modifyIORef (coreGraphic fo) $ IM.insert i (Member mc)
-    linkAudio (Control i mc) = mkSystem $ \fo -> modifyIORef (coreAudio fo) $ IM.insert i (Member mc)
-    linkKeyboard (Control i mc) = mkSystem $ \fo -> modifyIORef (coreKeyboard fo) $ IM.insert i (Member mc)
-    linkMouse (Control i mc) = mkSystem $ \fo -> modifyIORef (coreMouse fo) $ IM.insert i (Member mc)
-    unlinkGraphic (Control i _) = mkSystem $ \fo -> modifyIORef (coreGraphic fo) $ IM.delete i
-    unlinkAudio (Control i _) = mkSystem $ \fo -> modifyIORef (coreAudio fo) $ IM.delete i
-    unlinkMouse (Control i _) = mkSystem $ \fo -> modifyIORef (coreMouse fo) $ IM.delete i
-    unlinkKeyboard (Control i _) = mkSystem $ \fo -> modifyIORef (coreKeyboard fo) $ IM.delete i
+  bs0' <- forM (IM.toList $ ps IM.\\ bs0) $ \(i, p@(Gamepad _ s)) -> do
+    unSystem fo $ m $ PadConnection $ Up p
+    return (i, (s, IM.empty))
 
-    wait dt = mkSystem $ \fo -> do
-        t0 <- takeMVar (theTime fo)
-        Just t <- GLFW.getTime
-        threadDelay $ floor $ (t0 - t + dt) * 1000 * 1000
-        putMVar (theTime fo) $ t0 + dt
-    stand = mkSystem $ \fo -> takeMVar (theEnd fo)
+  bs0_ <- forM (IM.toList $ bs0 IM.\\ ps) $ \(i, (s, _)) -> do
+    unSystem fo $ m $ PadConnection $ Down $ Gamepad i s
+    return (i, ())
 
-runGraphic :: Foundation s -> Double -> IO ()
+  let bs1 = bs0 `IM.union` IM.fromList bs0' IM.\\ IM.fromList bs0_
+
+  ls <- forM (IM.toList ps) $ \(j, p@(Gamepad _ s)) -> do
+    bs <- zip [0..] <$> unSystem fo (gamepadButtons p)
+    forM_ bs $ \(i, v) -> case (v, maybe False id (bs1 ^? ix j . _2 . ix i)) of
+        (False, True) -> unSystem fo $ m $ PadButton p (Up i)
+        (True, False) -> unSystem fo $ m $ PadButton p (Down i)
+        _ -> return ()
+    return (j, (s, IM.fromList bs))
+
+  writeIORef (theGamepadButtons fo) $ foldr (uncurry IM.insert) bs1 ls
+
+runGraphic :: Foundation s -> Time -> IO ()
 runGraphic fo t0 = do
-    fps <- readIORef (targetFPS fo)
-    let t1 = t0 + 1/fps
-    G.beginFrame (theSystem fo)
-    ms <- readIORef (coreGraphic fo)
-    pics <- forM (IM.elems ms) $ \(Member m) -> push fo m $ pullGraphic (1/fps) -- is it appropriate?
-    give (TextureStorage (textures fo)) $ mapM_ runPicture pics
-    b <- G.endFrame (theSystem fo)
-    
-    Just t' <- GLFW.getTime
-    threadDelay $ floor $ (t1 - t') * 1000 * 1000
+  pollGamepad fo
+  fps <- readIORef (targetFPS fo)
+  let t1 = t0 + 1/fps
+  G.beginFrame (theSystem fo)
+  m <- readIORef (coreGraphic fo)
+  pic <- unSystem fo $ m (1/fps) -- is it appropriate?
+  drawSight fo pic
+  b <- G.endFrame (theSystem fo)
+  
+  Just t' <- GLFW.getTime
+  threadDelay $ floor $ (t1 - realToFrac t') * 1000 * 1000
 
-    tryTakeMVar (theEnd fo) >>= \case
-        Just _ -> return ()
-        _ | b -> putMVar (theEnd fo) ()
-          | otherwise -> runGraphic fo t1
+  tryTakeMVar (theEnd fo) >>= \case
+      Just _ -> return ()
+      _ | b -> putMVar (theEnd fo) ()
+        | otherwise -> runGraphic fo t1
 
-audioProcess :: Foundation s -> Int -> IO [V2 Float]
+audioProcess :: Foundation s -> Int -> IO (V.Vector Stereo)
 audioProcess fo n = do
-    let dt = fromIntegral n / sampleRate fo
-    ms <- readIORef (coreAudio fo)
-    ws <- forM (IM.elems ms) $ \(Member m) -> push fo m $ pullAudio dt n
-    return $ foldr (zipWith (+)) (replicate n zero) ws
-
-push :: Foundation s -> MVar (Object e (System s)) -> e a -> IO a
-push fo mc e = do
-    c0 <- takeMVar mc
-    (a, c) <- unSystem fo $ runObject c0 e
-    putMVar mc c
-    return a
+  let dt = fromIntegral n / sampleRate fo
+  m <- readIORef (coreAudio fo)
+  unSystem fo $ m dt n
 
 keyCallback :: Foundation s -> GLFW.KeyCallback
 keyCallback fo _ k _ st _ = do
-    ms <- readIORef (coreKeyboard fo)
-    forM_ (IM.elems ms) $ \(Member m) -> push fo m
-        $ keyEvent (toEnum . fromEnum $ k :: Key) (GLFW.KeyState'Released /= st)
+  m <- readIORef (coreKeyboard fo)
+  unSystem fo $ m $ case st of
+    GLFW.KeyState'Released -> Up (toEnum . fromEnum $ k :: Key)
+    _ -> Down (toEnum . fromEnum $ k :: Key)
 
 mouseButtonCallback :: Foundation s -> GLFW.MouseButtonCallback
 mouseButtonCallback fo _ btn st _ = do
-    ms <- readIORef (coreMouse fo)
-    forM_ (IM.elems ms) $ \(Member m) -> push fo m
-        $ mouseButtonEvent (fromEnum btn) (GLFW.MouseButtonState'Released /= st)
+  m <- readIORef (coreMouse fo)
+  unSystem fo $ m $ case st of
+    GLFW.MouseButtonState'Released -> Button $ Up (fromEnum btn)
+    _ -> Button $ Down (fromEnum btn)
 
 cursorPosCallback :: Foundation s -> GLFW.CursorPosCallback
 cursorPosCallback fo _ x y = do
-    ms <- readIORef (coreMouse fo)
-    forM_ (IM.elems ms) $ \(Member m) -> push fo m $ cursorEvent (V2 x y)
+  m <- readIORef (coreMouse fo)
+  unSystem fo $ m $ Cursor $ fmap realToFrac $ V2 x y
 
 scrollCallback :: Foundation s -> GLFW.ScrollCallback
 scrollCallback fo _ x y = do
-    ms <- readIORef (coreMouse fo)
-    forM_ (IM.elems ms) $ \(Member m) -> push fo m $ scrollEvent (V2 x y)
+  m <- readIORef (coreMouse fo)
+  unSystem fo $ m $ Scroll $ fmap realToFrac $ V2 x y
 
-newtype TextureStorage = TextureStorage { getTextureStorage :: IORef (IM.IntMap G.Texture) }
+fetchTexture :: Foundation s -> C.Image C.PixelRGBA8 -> Int -> IO G.Texture
+fetchTexture fo bmp h = do
+  st <- readIORef (textures fo)
+  case IM.lookup h st of
+    Just t -> return t
+    Nothing -> do
+      t <- G.installTexture bmp
+      writeIORef (textures fo) $ IM.insert h t st
+      return t
 
-instance Affine IO where
-    translate = G.translate
-    rotateD = G.rotateD
-    rotateR t = let t' = t / pi * 180 in G.rotateD t'
-    scale = G.scale
+drawScene :: Foundation s -> Box V2 Float -> M44 Float -> Bool -> Scene -> IO ()
+drawScene fo (fmap round -> Box (V2 x0 y0) (V2 x1 y1)) proj _ (Scene s) = do
+  GL.viewport $= (GL.Position x0 y0, GL.Size (x1 - x0) (y1 - y0))
 
-instance (Given TextureStorage) => Picture2D IO where
-    bitmap (Bitmap bmp h) = do
-        m <- readIORef (getTextureStorage given)
-        case IM.lookup h m of
-            Just t -> G.drawTexture t
-            Nothing -> do
-                t <- G.installTexture bmp
-                writeIORef (getTextureStorage given) $ IM.insert h t m
-                G.drawTexture t
-    bitmapOnce (Bitmap bmp _) = do
-        t <- G.installTexture bmp
-        G.drawTexture t
-        G.releaseTexture t
+  GL.currentProgram $= Just shaderProg
+  GL.UniformLocation loc <- GL.get (GL.uniformLocation shaderProg "projection")
+  with proj $ \ptr -> GL.glUniformMatrix4fv loc 1 1 $ castPtr ptr
+  GL.UniformLocation locT <- GL.get $ GL.uniformLocation shaderProg "useTexture"
+  s (pure $ return ()) (liftA2 (>>)) (prim locT) fx trans (RGBA 1 1 1 1, 0)
+  where
+    shaderProg = G.theProgram $ theSystem fo
+    prim locT Blank mode vs _ = do
+      GL.glUniform1i locT 0
+      V.unsafeWith vs $ \v -> GL.bufferData GL.ArrayBuffer $=
+        (fromIntegral $ V.length vs * sizeOf (undefined :: Vertex), v, GL.StaticDraw)
+      GL.drawArrays mode 0 $ fromIntegral $ V.length vs
+    prim locT (Bitmap bmp _ h) mode vs _ = do
+      GL.glUniform1i locT 1
+      (tex, _, _) <- fetchTexture fo bmp h
+      GL.activeTexture $= GL.TextureUnit 0
+      GL.textureFilter GL.Texture2D $= ((GL.Linear', Nothing), GL.Linear')
+      GL.textureBinding GL.Texture2D $= Just tex
+      V.unsafeWith vs $ \v -> GL.bufferData GL.ArrayBuffer $=
+        (fromIntegral $ V.length vs * sizeOf (undefined :: Vertex), v, GL.StaticDraw)
+      GL.drawArrays mode 0 $ fromIntegral $ V.length vs
+    trans f m (color0, n) = do
+      GL.UniformLocation loc <- GL.get $ GL.uniformLocation shaderProg "matrices"
+      GL.UniformLocation locN <- GL.get $ GL.uniformLocation shaderProg "level" 
+      with f $ \ptr -> GL.glUniformMatrix4fv (loc+n) 1 1 (castPtr ptr)
+      GL.glUniform1i locN (unsafeCoerce $ n + 1)
+      m (color0, n + 1)
+      GL.glUniform1i locN (unsafeCoerce n)
+    fx (Diffuse col m) (color0, n) = do
+      GL.UniformLocation loc <- GL.get $ GL.uniformLocation shaderProg "color"
+      let c = multRGBA col color0
+      with c $ \ptr -> GL.glUniform4fv loc 1 (castPtr ptr)
+      m (c, n)
+      with color0 $ \ptr -> GL.glUniform4fv loc 1 (castPtr ptr)
+    fx (SphericalAdd (Bitmap bmp _ h) m) c = do
+      GL.UniformLocation loc <- GL.get $ GL.uniformLocation shaderProg "useEnv"
+      GL.glUniform1i loc 1
+      (tex, _, _) <- fetchTexture fo bmp h
+      GL.activeTexture $= GL.TextureUnit 1
+      GL.textureFilter GL.Texture2D $= ((GL.Linear', Nothing), GL.Linear')
+      GL.textureBinding GL.Texture2D $= Just tex
+      m c
+      GL.glUniform1i loc 0
+    fx (SphericalAdd Blank m) c = m c
+    fx (SphericalMultiply (Bitmap bmp _ h) m) c = do
+      GL.UniformLocation loc <- GL.get $ GL.uniformLocation shaderProg "useEnv"
+      GL.glUniform1i loc 2
+      (tex, _, _) <- fetchTexture fo bmp h
 
-    circle = G.circle
-    circleOutline = G.circleOutline
-    polygon = G.polygon
-    polygonOutline = G.polygonOutline
-    line = G.line
-    thickness = G.thickness
-    color = G.color
-    blendMode = G.blendMode
+      GL.activeTexture $= GL.TextureUnit 1
+      GL.textureFilter GL.Texture2D $= ((GL.Linear', Nothing), GL.Linear')
+      GL.textureBinding GL.Texture2D $= Just tex
+      m c
+      GL.glUniform1i loc 0
+    fx (SphericalMultiply Blank m) c = m c
+
+drawSight :: Foundation s -> Sight -> IO ()
+drawSight fo (Sight s) = do
+  b <- readIORef $ G.refRegion $ theSystem fo
+  s b (return ()) (>>) (drawScene fo)
diff --git a/src/Call/TH.hs b/src/Call/TH.hs
--- a/src/Call/TH.hs
+++ b/src/Call/TH.hs
@@ -19,7 +19,7 @@
 import Control.Applicative
 import Control.Monad
 import Data.Char
-import Call.Data.Bitmap
+import qualified Call.Data.Bitmap as Bitmap
 import Language.Haskell.TH
 import System.Directory
 import System.FilePath
@@ -35,7 +35,7 @@
     sequence $ do
         p <- paths
         let name = pathToName p
-        [ return $ SigD (mkName name) (ConT ''Bitmap)
+        [ return $ SigD (mkName name) (ConT ''Bitmap.Bitmap)
             , funD (mkName name) [clause [] (normalB $ load name $ loc </> p) []]
             ]
     where
@@ -44,7 +44,7 @@
 
             appE (varE 'unsafePerformIO) $ uInfixE (appE getFullPath $ litE $ StringL fp)
                 (varE '(>>=))
-                (varE 'readBitmap)
+                (varE 'Bitmap.readFile)
 
 -- | Load and define all pictures in the specified directory.
 -- On base >= 4.6, file paths to actually load will be respect to the directory of the executable. Otherwise it will be based on the current directory.
diff --git a/src/Call/Types.hs b/src/Call/Types.hs
--- a/src/Call/Types.hs
+++ b/src/Call/Types.hs
@@ -13,26 +13,44 @@
 module Call.Types (
     Time
     , Vec2
+    , Vec3
+    , Stereo
     , WindowMode(..)
-    , BoundingBox2
+    , MouseEvent(..)
+    , Gamepad(..)
+    , GamepadEvent(..)
+    , Chatter(..)
     , Key(..)
     , charToKey
     , BlendMode(..)
+    , Vertex(..)
+    , positionUV
+    , positionOnly
+    , Bitmap(..)
     ) where
 
+import Control.Applicative
 import Linear
 import Data.Typeable
-import Data.BoundingBox
 import Data.Char
+import Foreign.Storable
+import Foreign.Ptr
+import Call.Data.Bitmap
 
-type Time = Double
+type Time = Float
+type Stereo = V2 Float
+type Vec2 = V2 Float
+type Vec3 = V3 Float
+data WindowMode = Windowed | Resizable | FullScreen deriving (Show, Eq, Ord, Read, Typeable)
 
-data WindowMode = Windowed | Resizable | FullScreen deriving (Show, Eq, Ord, Read)
+data Chatter a = Up a | Down a deriving (Show, Eq, Ord, Read, Typeable)
 
-type Vec2 = V2 Double
+data MouseEvent = Button (Chatter Int) | Cursor Vec2 | Scroll Vec2 deriving (Show, Eq, Ord, Read, Typeable)
 
-type BoundingBox2 = Box V2 Double
+data Gamepad = Gamepad Int String deriving (Show, Eq, Ord, Read, Typeable)
 
+data GamepadEvent = PadButton Gamepad (Chatter Int) | PadConnection (Chatter Gamepad) deriving (Show, Eq, Ord, Read, Typeable)
+
 data Key =
       KeyUnknown
     | KeySpace
@@ -183,4 +201,33 @@
     | Add
     | Multiply
     | Screen
-    deriving (Enum, Eq, Ord, Read, Show, Typeable)
+    deriving (Enum, Eq, Ord, Read, Show, Typeable)
+
+data Vertex = Vertex { vPos :: {-# UNPACK #-} !Vec3
+  , vUV :: {-# UNPACK #-} !Vec2
+  , vNormal :: {-# UNPACK #-} !Vec3 }
+  deriving (Show, Eq, Ord, Read, Typeable)
+
+align1 :: Int
+align1 = sizeOf (vPos undefined)
+
+align2 :: Int
+align2 = align1 + sizeOf (vUV undefined)
+
+instance Storable Vertex where
+  sizeOf _ = sizeOf (undefined :: Vec3) + sizeOf (undefined :: Vec2) + sizeOf (undefined :: Vec3)
+  alignment _ = 0
+  peek ptr = Vertex
+    <$> peek (castPtr ptr)
+    <*> peek (castPtr $ ptr `plusPtr` align1)
+    <*> peek (castPtr $ ptr `plusPtr` align2)
+  poke ptr (Vertex v t n) = do
+    poke (castPtr ptr) v
+    poke (castPtr ptr `plusPtr` align1) t
+    poke (castPtr ptr `plusPtr` align2) n
+
+positionUV :: Vec3 -> Vec2 -> Vertex
+positionUV v p = Vertex v p zero
+
+positionOnly :: Vec3 -> Vertex
+positionOnly v = Vertex v zero zero
diff --git a/src/Call/Util.hs b/src/Call/Util.hs
--- a/src/Call/Util.hs
+++ b/src/Call/Util.hs
@@ -1,28 +1,21 @@
+{-# LANGUAGE FlexibleContexts, GADTs #-}
 module Call.Util where
-import Control.Monad.Objective.Class
 import Control.Object
-import Call.Component
-import Call.Component.Deck
-import Call.System
 import Call.Types
-import Call.Data.Wave
-import Call.Picture
-import Control.Lens
+import Call.Sight
+import Control.Monad.State
+import qualified Call.Data.Bitmap as Bitmap
+import Data.Functor.Request
 
-animate :: (Time -> System s (Picture ())) -> System s (Address PullGraphic (System s))
-animate f = do
-  p <- new (go 0)
-  linkGraphic p
-  return p
-  where
-    go t = Object $ \(PullGraphic dt cont) -> f t >>= \p -> return (cont p, go (t + dt))
+readBitmap :: MonadIO m => FilePath -> m Bitmap.Bitmap
+readBitmap = Bitmap.readFile
 
-withSound :: Source Stereo -> System s a -> System s a
-withSound src m = do
-  deck <- new emptyDeck
-  deck .& source ?= src
-  deck .& playing .= True
-  linkAudio deck
-  r <- m
-  unlinkAudio deck
-  return r
+animate :: Monad m => (Time -> Sight) -> Object (Request Time Sight) m
+animate f = go (0 :: Float) where
+  go t = Object $ \(Request dt cont) -> return (cont $ f t, go (t + dt))
+
+transit :: MonadPlus m => Time -> (Time -> Sight) -> Object (Request Time Sight) m
+transit len f = go 0 where
+  go t
+    | t >= len = Object $ const mzero
+    | otherwise = Object $ \(Request dt cont) -> return (cont $ f (t / len), go (t + dt))
diff --git a/src/Call/Util/Deck.hs b/src/Call/Util/Deck.hs
new file mode 100644
--- /dev/null
+++ b/src/Call/Util/Deck.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE TypeOperators #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Call.Util.Deck
+-- Copyright   :  (c) Fumiaki Kinoshita 2014
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- The deck for a single stream
+--
+-----------------------------------------------------------------------------
+module Call.Util.Deck (Deck(..), empty, source, pos, playing, playback) where
+import Control.Lens
+import Control.Monad.State.Class
+import Call.Data.Wave
+import Call.Types
+import qualified Data.Vector.Storable as V
+
+data Deck = Deck
+  { _src :: Source Stereo
+  , _pos :: !Time
+  , _playing :: !Bool }
+
+empty :: Deck
+empty = Deck (Source $ const 0) 0 False
+
+source :: Lens' Deck (Source Stereo)
+source f s = f (_src s) <&> \a -> s { _src = a }
+
+pos :: Lens' Deck Time
+pos f s = f (_pos s) <&> \a -> s { _pos = a }
+
+playing :: Lens' Deck Bool
+playing f s = f (_playing s) <&> \a -> s { _playing = a }
+
+playback :: MonadState Deck m => Time -> Int -> m (V.Vector Stereo)
+playback dt n = do
+  Source s <- use source
+  pl <- use playing
+  t0 <- use pos
+  if pl
+    then do
+      pos += dt
+      return $ V.fromList $ take n $ map s [t0,t0 + dt / fromIntegral n..]
+    else return $ V.replicate n 0
diff --git a/src/Call/Util/Sampler.hs b/src/Call/Util/Sampler.hs
new file mode 100644
--- /dev/null
+++ b/src/Call/Util/Sampler.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE FlexibleContexts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Call.Util.Deck
+-- Copyright   :  (c) Fumiaki Kinoshita 2014
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Polyphonic sampler
+--
+-----------------------------------------------------------------------------
+module Call.Util.Sampler where
+import qualified Data.Vector.Storable as V
+import qualified Data.Vector.Storable.Mutable as MV
+import Control.Monad.ST
+import Control.Monad.State.Class
+import Call.Types
+import Call.Data.Wave
+import Control.Monad
+
+data Sampler = Sampler [(Sample Stereo, Time)]
+
+empty :: Sampler
+empty = Sampler []
+
+playback :: MonadState Sampler m => Time -> Int -> m (V.Vector Stereo) 
+playback dt n = do
+  Sampler vs <- get
+  let (vs'', r) = runST $ do
+        v <- MV.new n
+        vs' <- forM vs $ \(s0@(Sample d (Source s)), t0) -> do
+          if d > t0 then return []
+            else do
+              forM_ [0..n-1] $ \i -> do
+                z <- MV.unsafeRead v i
+                MV.unsafeWrite v i $ z + s (t0 + f * fromIntegral i)
+              return [(s0, t0 + dt)]
+        v' <- V.unsafeFreeze v
+        return (vs', v')
+  put $ Sampler $ concat vs''
+  return r
+  where
+    f = dt / fromIntegral n
+
+play :: MonadState Sampler m => Sample Stereo -> m ()
+play s = modify $ \(Sampler xs) -> Sampler $ (s, 0) : xs
