diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,20 @@
+2009.07.02
+---------------------------------------------
+Cabalized
+
+
+2009.06.28.
+---------------------------------------------
+- bigger resolution textures
+- background added
+- jerky move fixed
+- key handling with list
+- IORef-s removed from State
+- cube state update simplified
+- finally a game with levels
+- fade in, fade out
+
+
+2009.06.18.
+---------------------------------------------
+First demo version
diff --git a/Cubezor.hs b/Cubezor.hs
new file mode 100644
--- /dev/null
+++ b/Cubezor.hs
@@ -0,0 +1,260 @@
+module Cubezor where
+
+import Graphics.Rendering.OpenGL
+import Etc
+import Maps
+import Quaternion
+
+
+-- Cube types
+data CubePos = CubePos {
+  x :: Int,
+  y :: Int
+} deriving Show
+
+data CubeOrientation = Standing | Horizontal | Vertical deriving Eq
+
+data CubeRolling = CrNo | CrUp | CrDown | CrRight | CrLeft | CrFalling | CrWinning deriving (Eq, Show)
+
+data Cube = Cube { pos1      :: CubePos
+                 , pos2      :: CubePos
+                 , angle     :: GLfloat
+                 , rolling   :: CubeRolling
+                 , quat      :: Quaternion
+                 , rotOffset :: Vector3 GLfloat
+                 , rotAxis   :: Vector3 GLfloat
+                 , fallOffset :: GLfloat
+                 } deriving Show
+
+
+cubeRollingSpeed :: GLfloat
+cubeRollingSpeed = 360.0
+
+
+newCube :: Maps.Level -> Cube
+newCube level = Cube {
+    pos1  = p,
+    pos2  = p,
+    angle = 0.0,
+    rolling = CrNo,
+    quat = quatIdentity,
+    rotOffset = (Vector3 0.0 0.0 0.0 :: Vector3 GLfloat),
+    rotAxis = (Vector3 0.0 0.0 0.0 :: Vector3 GLfloat),
+    fallOffset = 0.0
+  } where
+    (x,y) = lStartPos level
+    p = CubePos {x = x, y = y}
+
+
+renderCube :: Cube -> IO ()
+renderCube cubex = preservingMatrix $ do
+  let xx = fromIntegral ((x $ pos1 cubex) + (x $ pos2 cubex))
+  let yy = fromIntegral ((y $ pos1 cubex) + (y $ pos2 cubex))
+  let zz = if orientation cubex == Standing then 2.0 else 1.0
+
+  if (rolling cubex == CrFalling) || (rolling cubex == CrWinning)
+    then translate (Vector3 0 (fallOffset cubex) 0 :: Vector3 GLfloat)
+    else return ()
+
+  translate $ (Vector3 xx 0 yy :: Vector3 GLfloat)
+  if rolling cubex /= CrNo
+    then do
+      translate $ vecNeg $ rotOffset cubex
+      rotate (angle cubex) (rotAxis cubex)
+      translate $ rotOffset cubex
+    else
+      return ()
+
+  translate $ (Vector3 0.0 zz 0.0 :: Vector3 GLfloat)
+  m <- quat2Matrix $ quat cubex
+  multMatrix m
+  scale (1.0 :: GLfloat) 2.0 1.0
+  cube
+
+
+upCube :: Cube -> Cube
+upCube cube =
+  if rolling cube == CrNo
+    then 
+      cube { rolling = CrUp
+           , rotAxis = Vector3 (-1.0) 0.0 0.0
+           , rotOffset = Vector3 0.0 0.0 ro
+           }
+    else
+      cube
+    where
+      ro = if orientation cube == Vertical
+             then 2.0
+             else 1.0
+
+
+downCube :: Cube -> Cube
+downCube cube =
+  if rolling cube == CrNo
+    then
+      cube { rolling = CrDown
+           , rotAxis = Vector3 1.0 0.0 0.0
+           , rotOffset = Vector3 0.0 0.0 ro
+           }
+    else
+      cube
+  where
+    ro = if orientation cube == Vertical
+           then (-2.0)
+           else (-1.0)
+
+
+leftCube :: Cube -> Cube
+leftCube cube =
+  if rolling cube == CrNo
+    then
+      cube { rolling = CrLeft
+           , rotAxis = Vector3 0.0 0.0 1.0
+           , rotOffset = Vector3 ro 0.0 0.0
+           }
+    else
+      cube
+  where
+    ro = if orientation cube == Horizontal
+           then 2.0
+           else 1.0
+
+
+rightCube :: Cube -> Cube
+rightCube cube =
+  if rolling cube == CrNo
+    then
+      cube { rolling = CrRight
+           , rotAxis = Vector3 0.0 0.0 (-1.0)
+           , rotOffset = Vector3 ro 0.0 0.0
+           }
+    else
+      cube
+  where
+    ro = if orientation cube == Horizontal
+           then (-2.0)
+           else (-1.0)
+
+
+fallCube :: Cube -> Cube
+fallCube cube = cube { rolling = CrFalling
+                     , fallOffset = 0.0
+                     }
+
+
+winCube :: Cube -> Cube
+winCube cube = cube { rolling = CrWinning
+                    , fallOffset = 0.0
+                    }
+
+
+orientation :: Cube -> CubeOrientation
+orientation cube =
+  if x1 == x2 && y1 == y2
+    then Standing
+    else
+      if x1 < x2 && y1 == y2
+        then Horizontal
+        else Vertical
+  where
+    x1 = x $ pos1 cube
+    y1 = y $ pos1 cube
+    x2 = x $ pos2 cube
+    y2 = y $ pos2 cube
+
+
+updateCube :: GLfloat -> Cube -> Cube
+updateCube dt cube =
+  if (angle cube > 90.0) && (rolling cube /= CrFalling) && (rolling cube /= CrWinning)
+    then
+      cube { pos1 = p1
+           , pos2 = p2
+           , quat = q
+           , angle = 0
+           , rolling = CrNo
+           }
+    else
+      if rolling cube /= CrNo
+        then cube { angle = a
+                  , fallOffset = fo 
+                  }
+        else cube
+  where
+    (p1,p2,q) = updatePosition cube
+    fo = if (rolling cube == CrFalling) || (rolling cube == CrWinning)
+           then fallOffset cube - 10.0 * dt
+           else 0.0
+    a = if rolling cube == CrWinning
+          then 0.0
+          else angle cube + cubeRollingSpeed * dt
+
+
+updatePosition :: Cube -> (CubePos, CubePos, Quaternion)
+updatePosition cube =
+  case rolling cube of
+    CrUp -> case orientation cube of
+            Standing   -> ( CubePos  xx      (yy - 2)
+                          , CubePos  xx      (yy - 1)
+                          , quatMul q qq
+                          )
+            Horizontal -> ( CubePos  xx      (yy - 1)
+                          , CubePos (xx + 1) (yy - 1)
+                          , quatMul q qq
+                          )
+            Vertical   -> ( CubePos  xx      (yy - 1)
+                          , CubePos  xx      (yy - 1)
+                          , quatMul q qq
+                          )
+            where q = quatFromAngleAxis piPer2 (-1.0) 0.0 0.0
+    CrDown -> case orientation cube of
+            Standing   -> ( CubePos  xx      (yy + 1)
+                          , CubePos  xx      (yy + 2)
+                          , quatMul q qq
+                          )
+            Horizontal -> ( CubePos  xx      (yy + 1)
+                          , CubePos (xx + 1) (yy + 1)
+                          , quatMul q qq
+                          )
+            Vertical   -> ( CubePos  xx      (yy + 2)
+                          , CubePos  xx      (yy + 2)
+                          , quatMul q qq
+                          )
+            where q = quatFromAngleAxis piPer2 1.0 0.0 0.0
+    CrLeft -> case orientation cube of
+            Standing   -> ( CubePos (xx - 2)  yy
+                          , CubePos (xx - 1)  yy
+                          , quatMul q qq
+                          )
+            Horizontal -> ( CubePos (xx - 1)  yy
+                          , CubePos (xx - 1)  yy
+                          , quatMul q qq
+                          )
+            Vertical   -> ( CubePos (xx - 1)  yy
+                          , CubePos (xx - 1) (yy + 1)
+                          , quatMul q qq
+                          )
+            where q = quatFromAngleAxis piPer2 0.0 0.0 1.0
+    CrRight -> case orientation cube of
+            Standing   -> ( CubePos (xx + 1)  yy
+                          , CubePos (xx + 2)  yy
+                          , quatMul q qq
+                          )
+            Horizontal -> ( CubePos (xx + 2)  yy
+                          , CubePos (xx + 2)  yy
+                          , quatMul q qq
+                          )
+            Vertical   -> ( CubePos (xx + 1)  yy
+                          , CubePos (xx + 1) (yy + 1)
+                          , quatMul q qq
+                          )
+            where q = quatFromAngleAxis piPer2 0.0 0.0 (-1.0)
+    -- otherwise just return the old value
+    _ -> (pos1 cube, pos2 cube, quat cube)
+  where
+    xx = x $ pos1 cube
+    yy = y $ pos1 cube
+    qq = quat cube
+
+
+isCubeUpdated :: Cube -> Cube -> Bool
+isCubeUpdated cube0 cube1 = (angle cube0 > 90.0) && (angle cube1 == 0.0)
diff --git a/Etc.hs b/Etc.hs
new file mode 100644
--- /dev/null
+++ b/Etc.hs
@@ -0,0 +1,82 @@
+module Etc where
+
+import Graphics.Rendering.OpenGL.GL as GL
+import Graphics.UI.GLFW as GLFW
+import Graphics.Rendering.OpenGL (($=))
+
+import Paths_bloxorz (getDataFileName)
+
+
+double2float :: Double -> Float
+--double2float = fromRational . toRational
+double2float = realToFrac
+
+
+piPer2 :: Float
+piPer2 = pi / 2.0
+
+
+vecNeg :: Vector3 GLfloat -> Vector3 GLfloat
+vecNeg (Vector3 x y z) = Vector3 (-x) (-y) (-z)
+
+cube :: IO ()
+cube = renderPrimitive Quads $ do
+    -- back
+    n 0 0 (-1)
+    t 0 1 >> v (-1) (-1) (-1)
+    t 1 1 >> v   1  (-1) (-1)
+    t 1 0 >> v   1    1  (-1)
+    t 0 0 >> v (-1)   1  (-1)
+    -- front
+    n 0 0 1
+    t 0 1 >> v   1  (-1)   1
+    t 1 1 >> v (-1) (-1)   1
+    t 1 0 >> v (-1)   1    1
+    t 0 0 >> v   1    1    1
+    -- left
+    n (-1) 0 0
+    t 0 1 >> v (-1) (-1)   1
+    t 1 1 >> v (-1) (-1) (-1)
+    t 1 0 >> v (-1)   1  (-1)
+    t 0 0 >> v (-1)   1    1
+    -- right
+    n 1 0 0
+    t 0 1 >> v   1  (-1) (-1)
+    t 1 1 >> v   1  (-1)   1
+    t 1 0 >> v   1    1    1
+    t 0 0 >> v   1    1  (-1)
+    -- top
+    n 0 1 0
+    t 0 1 >> v   1    1  (-1)
+    t 1 1 >> v   1    1    1
+    t 1 0 >> v (-1)   1    1
+    t 0 0 >> v (-1)   1  (-1)
+    -- bottom
+    n 0 (-1) 0
+    t 0 1 >> v   1  (-1)   1
+    t 1 1 >> v   1  (-1) (-1)
+    t 1 0 >> v (-1) (-1) (-1)
+    t 0 0 >> v (-1) (-1)   1
+    where v x y z = GL.vertex (GL.Vertex3 x y z :: GL.Vertex3 GLfloat)
+          n x y z = GL.normal (GL.Normal3 x y z :: GL.Normal3 GLfloat)
+          t u v   = GL.texCoord (GL.TexCoord2 u v :: GL.TexCoord2 GLfloat)
+
+
+quad :: GLfloat -> IO ()
+quad z = renderPrimitive Quads $ do
+    t 0 1 >> v (-1)   1    z
+    t 1 1 >> v   1    1    z
+    t 1 0 >> v   1  (-1)   z
+    t 0 0 >> v (-1) (-1)   z
+    where v x y z = GL.vertex (GL.Vertex3 x y z :: GL.Vertex3 GLfloat)
+          t u v   = GL.texCoord (GL.TexCoord2 u v :: GL.TexCoord2 GLfloat)
+
+
+loadTexture :: String -> IO GL.TextureObject
+loadTexture filename = do
+  dataFileName <- getDataFileName filename
+  [texName] <- GL.genObjectNames 1
+  GL.textureBinding Texture2D $= Just texName
+  GLFW.loadTexture2D dataFileName [GLFW.BuildMipMaps]
+  GL.textureFilter Texture2D $= ((GL.Linear', Just GL.Linear'), GL.Linear') -- trilinear filtering
+  return texName
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,293 @@
+module Main (
+    main
+) where
+
+import Graphics.Rendering.OpenGL.GL as GL
+import Graphics.Rendering.OpenGL.GLU as GLU
+import Graphics.UI.GLFW as GLFW
+import Graphics.Rendering.OpenGL (($=))
+import Control.Monad
+
+-- Bloxorz stuff
+import Maps
+import Etc
+import Cubezor
+
+
+data GameState = GsStarting | GsGame | GsFalling | GsWinning deriving (Eq,Show)
+
+data GameGlobal = GameGlobal { gamestate :: GameState
+                             , fade :: GLfloat
+                             , levelindex :: Int
+                             } deriving Show
+
+-- UberState
+data State = State { level :: Maps.Level
+                   , cubex :: Cube
+                   , global :: GameGlobal
+                   }
+
+
+makeState :: State
+makeState = State { level = l
+                  , cubex = newCube l
+                  , global = GameGlobal { gamestate = GsStarting
+                                        , fade = 1.0
+                                        , levelindex = 0
+                                        }
+                  }
+  where
+    l = Maps.maps !! 0
+
+
+nextLevel :: State -> Maybe State
+nextLevel state =
+  if li < length Maps.maps
+    then Just state { level = l
+                    , cubex = newCube l
+                    , global = GameGlobal { gamestate = GsStarting
+                                          , fade = 1.0
+                                          , levelindex = li
+                                          }
+                    }
+    else Nothing
+  where
+    li = (levelindex $ global state) + 1
+    l = Maps.maps !! li
+
+
+-- GL Stuff
+data GLStuff = GLStuff {
+  texCube  :: GL.TextureObject,
+  texFloor :: GL.TextureObject,
+  texBg    :: GL.TextureObject
+}
+
+initGL :: IO GLStuff
+initGL = do
+  GL.clearColor $= GL.Color4 0.0 0.0 0.0 1.0
+  GL.depthFunc $= Just GL.Lequal
+  GL.blendFunc $= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
+  GL.normalize $= GL.Enabled
+  GL.texture GL.Texture2D $= GL.Enabled
+  
+  -- reset matrixes
+  GL.matrixMode $= GL.Projection
+  GL.loadIdentity
+  GL.matrixMode $= GL.Modelview 0
+  GL.loadIdentity
+
+  -- load textures
+  texCube  <- loadTexture "data/cube.tga"
+  texFloor <- loadTexture "data/floor.tga"
+  texBg    <- loadTexture "data/bg.tga"
+
+  -- make stuff
+  return $ GLStuff {
+    texCube = texCube,
+    texFloor = texFloor,
+    texBg = texBg
+  }
+
+
+resize :: GLFW.WindowSizeCallback
+resize size@(Size w h) = do
+  let hh = if h < 0 then 1 else h
+  let aspect = (fromIntegral w) / (fromIntegral hh)
+  GL.viewport   $= (Position 0 0, size)
+  GL.matrixMode $= GL.Projection
+  GL.loadIdentity
+  GLU.perspective 30.0 aspect 1.0 200.0
+  GL.matrixMode $= GL.Modelview 0
+  return ()
+
+
+data CubeState = CsOk | CsFall | CsEnd
+
+check :: Maps.Level -> Cube -> CubeState
+check level cube =
+  if l1 == 'e' && l2 == 'e'
+    then CsEnd
+    else
+      if l1 == ' ' || l2 == ' '
+      then CsFall
+      else CsOk
+  where
+    l1 = Maps.getMap level x1 y1
+    l2 = Maps.getMap level x2 y2
+    x1 = x $ pos1 cube
+    y1 = y $ pos1 cube
+    x2 = x $ pos2 cube
+    y2 = y $ pos2 cube
+
+
+updateGame :: State -> (GLFW.KeyButtonState,
+                        GLFW.KeyButtonState,
+                        GLFW.KeyButtonState,
+                        GLFW.KeyButtonState) -> Float -> State
+updateGame state keys dt =
+  if isCubeUpdated cube0 cube1
+    then
+      state { cubex = cubeNew
+            , global = globalNew
+            }
+    else
+      state { cubex = cubeNew }
+  where
+    cube0 = cubex state
+    level0 = level state
+    global0 = global state
+
+    cube1 = updateCube dt $ processInput keys cube0
+    (cubeNew,globalNew) = case check level0 cube1 of
+                            CsOk -> (cube1, global0)
+                            CsEnd -> (winCube cube1, global0 { gamestate = GsWinning } )
+                            CsFall -> (fallCube cube1, global0 { gamestate = GsFalling } )
+              
+    processInput (u,d,l,r) cube = head $ [act | (GLFW.Press,act) <- [(u, upCube cube),
+                                                                     (d, downCube cube),
+                                                                     (l, leftCube cube),
+                                                                     (r, rightCube cube)]
+                                         ] ++ [cube] -- default: no change
+
+update :: State -> GLfloat -> IO State
+update state dt =
+  case gamestate global0 of
+    GsStarting -> if fade0 < 0.0
+                    then
+                      return state { global = global0 { gamestate = GsGame
+                                                      , fade = 0.0
+                                                      }
+                                   }
+                    else
+                      return state { global = global0 { fade = fade0 - 2.0*dt } }
+    GsGame -> do
+      u <- GLFW.getKey GLFW.UP
+      d <- GLFW.getKey GLFW.DOWN
+      l <- GLFW.getKey GLFW.LEFT
+      r <- GLFW.getKey GLFW.RIGHT
+      return $ updateGame state (u,d,l,r) dt
+    GsFalling -> if fade0 > 1.0
+                   then
+                     return state { global = global0 { gamestate = GsStarting
+                                                     , fade = 1.0
+                                                     }
+                                  , cubex = newCube level0
+                                  }
+                   else
+                     return state { global = global0 { fade = fade0 + 2.0*dt }
+                                  , cubex = updateCube dt cube0
+                                  }
+    GsWinning -> if fade0 > 1.0
+                   then
+                     case nextLevel state of
+                       Just newState -> return newState
+                       Nothing -> do
+                         GLFW.closeWindow
+                         return state
+                   else
+                     return state { global = global0 { fade = fade0 + 2.0*dt }
+                                  , cubex = updateCube dt cube0
+                                  }
+  where
+    global0 = global state
+    fade0 = fade global0
+    level0 = level state
+    cube0 = cubex state
+
+
+renderLevel :: Maps.Level -> IO ()
+renderLevel level = do
+  forM_ (zip (Maps.lMap level) [0..]) $ \(row,i) ->
+    forM_ (zip row [0..]) $ \(c,j) ->
+      case c of
+        'b' -> GL.preservingMatrix $ do
+                 GL.scale (1.0 :: GLfloat) 0.25 1.0
+                 GL.translate $ (GL.Vector3 (j*2) (-1) (i*2) :: GL.Vector3 GL.GLfloat)
+                 cube
+        _ -> return ()
+
+        
+render :: State -> GLStuff -> IO ()
+render state stuff = do
+  GL.clear [GL.ColorBuffer, GL.DepthBuffer]
+  GL.loadIdentity
+
+  GLU.lookAt (GL.Vertex3 12.5 30.0 40.0) (GL.Vertex3 15.0 0.0 10.0) (GL.Vector3 0.0 1.0 0.0)
+
+  -- level
+  GL.textureBinding GL.Texture2D $= Just (texFloor stuff)
+  renderLevel $ level state
+
+  -- cube
+  GL.textureBinding GL.Texture2D $= Just (texCube stuff)
+  renderCube $ cubex state
+
+  -- 2d
+  GL.loadIdentity -- modelview
+  GL.matrixMode $= GL.Projection
+  GL.preservingMatrix $ do
+    -- background
+    GL.loadIdentity -- projection
+    GL.textureBinding GL.Texture2D $= Just (texBg stuff)
+    quad 1.0
+
+    -- fade
+    if (gamestate $ global state) /= GsGame
+      then do
+        GL.texture GL.Texture2D $= GL.Disabled
+        GL.blend $= GL.Enabled
+        GL.currentColor $= (GL.Color4 0 0 0 (fade $ global state) :: GL.Color4 GL.GLfloat)
+        quad 0.0
+        GL.currentColor $= (GL.Color4 1 1 1 1 :: Color4 GLfloat) 
+        GL.blend $= GL.Disabled
+        GL.texture GL.Texture2D $= GL.Enabled
+      else
+        return ()        
+
+  GL.matrixMode $= GL.Modelview 0
+
+  GLFW.swapBuffers
+
+
+loop :: State -> GLStuff -> Float -> IO ()
+loop state stuff lastTime = do
+  -- dt
+  nowD <- get time
+  let now = double2float nowD
+  let dt = now - lastTime
+
+  -- game
+  newState <- update state dt
+  render newState stuff
+
+  -- exit if window closed or Esc pressed
+  esc <- GLFW.getKey GLFW.ESC
+  q <- GLFW.getKey 'Q'
+  open <- get $ GLFW.windowParam GLFW.Opened
+  if open == 1 && esc /= GLFW.Press && q /= GLFW.Press
+    then loop newState stuff now
+    else return ()
+
+
+main :: IO ()
+main = do
+  -- initialize
+  GLFW.initialize
+  -- open window
+  GLFW.openWindow (GL.Size 700 400) [GLFW.DisplayRGBBits 8 8 8,
+                                     GLFW.DisplayAlphaBits 8,
+                                     GLFW.DisplayDepthBits 24] GLFW.Window
+  -- init
+  let state = makeState
+  stuff <- initGL
+  -- setup stuff
+  GLFW.swapInterval       $= 1 -- vsync
+  GLFW.windowTitle        $= "Bloxorz"
+  GLFW.windowSizeCallback $= resize
+  -- main loop
+  now <- get GLFW.time
+  loop state stuff (double2float now)
+  -- exit
+  GLFW.closeWindow
+  GLFW.terminate
diff --git a/Maps.hs b/Maps.hs
new file mode 100644
--- /dev/null
+++ b/Maps.hs
@@ -0,0 +1,69 @@
+module Maps (
+  Level(..),
+  getMap,
+  maps
+) where
+
+
+data Level = Level { lMap      :: [String]
+                   , lStartPos :: (Int,Int)
+                   } deriving Show
+
+
+maps = [{-Level { lMap = ["bbbbbbbbbbbbbbb",
+                        "bbbbbbbbbbbbbbb",
+                        "bbbbbbbbbbbbbbb",
+                        "bbbbbbbbbbbbbbb",
+                        "bbbbbbbbbbbbbbb",
+                        "bbbbbbbebbbbbbb",
+                        "bbbbbbbbbbbbbbb",
+                        "bbbbbbbbbbbbbbb",
+                        "bbbbbbbbbbbbbbb",
+                        "bbbbbbbbbbbbbbb"]
+                , lStartPos = (0,0)
+              },-}
+        Level { lMap = ["               ",
+                        "               ",
+                        "  bbb          ",
+                        "  bbbbbb       ",
+                        "  bbbbbbbbb    ",
+                        "   bbbbbbbbb   ",
+                        "       bbebb   ",
+                        "        bbb    ",
+                        "               ",
+                        "               "]
+              , lStartPos = (3,3)
+              },
+        Level { lMap = ["               ",
+                        "               ",
+                        "      bbbbbbb  ",
+                        "bbbb  bbb  bb  ",
+                        "bbbbbbbbb  bbbb",
+                        "bbbb       bbeb",
+                        "bbbb       bbbb",
+                        "            bbb",
+                        "               ",
+                        "               "]
+              , lStartPos = (1,5)
+              },
+        Level { lMap = ["     bbbbbb    ",
+                        "     b  bbb    ",
+                        "     b  bbbbb  ",
+                        "bbbbbb     bbbb",
+                        "    bbb    bbeb",
+                        "    bbb     bbb",
+                        "      b  bb    ",
+                        "      bbbbb    ",
+                        "      bbbbb    ",
+                        "       bbb     "]
+              , lStartPos = (0,3)
+              }
+
+       ]
+
+
+getMap level x y =
+  if 0 <= x && x <= 14 &&
+     0 <= y && y <= 9
+    then (lMap level !! y) !! x
+    else ' '
diff --git a/Quaternion.hs b/Quaternion.hs
new file mode 100644
--- /dev/null
+++ b/Quaternion.hs
@@ -0,0 +1,57 @@
+module Quaternion
+where
+
+import Graphics.Rendering.OpenGL.GL
+
+
+type Quaternion = (Float, Float, Float, Float) -- w x y z
+
+quatIdentity :: Quaternion
+quatIdentity = (1.0, 0.0, 0.0, 0.0)
+
+quatFromAngleAxis :: Float -> Float -> Float -> Float -> Quaternion
+quatFromAngleAxis angle ax ay az = (w, x, y, z)
+  where
+    w = cos half
+    x = hsin * ax
+    y = hsin * ay
+    z = hsin * az
+    half = angle / 2.0
+    hsin = sin half
+
+
+quatMul :: Quaternion -> Quaternion -> Quaternion
+quatMul (w1,x1,y1,z1) (w2,x2,y2,z2) = (ww,xx,yy,zz)
+  where
+    ww = w1*w2 - x1*x2 - y1*y2 - z1*z2
+    xx = w1*x2 + x1*w2 + y1*z2 - z1*y2
+    yy = w1*y2 + y1*w2 + z1*x2 - x1*z2
+    zz = w1*z2 + z1*w2 + x1*y2 - y1*x2
+
+
+quat2Matrix :: Quaternion -> IO (GLmatrix GLfloat)
+quat2Matrix (w,x,y,z) =
+  newMatrix ColumnMajor [(r00 :: GLfloat),r01,r02,r03,
+                         r10,r11,r12,r13,
+                         r20,r21,r22,r23,
+                         r30,r31,r32,r33]
+  where
+    r00 = 1.0 - 2.0*y*y - 2.0*z*z
+    r01 = 2.0*x*y + 2.0*w*z
+    r02 = 2.0*x*z - 2.0*w*y
+    r03 = 0.0
+
+    r10 = 2.0*x*y - 2.0*w*z
+    r11 = 1.0 - 2.0*x*x - 2.0*z*z
+    r12 = 2.0*y*z + 2.0*w*x
+    r13 = 0.0
+
+    r20 = 2.0*x*z + 2.0*w*y
+    r21 = 2.0*y*z - 2.0*w*x
+    r22 = 1.0 - 2.0*x*x - 2.0*y*y
+    r23 = 0.0
+
+    r30 = 0.0
+    r31 = 0.0
+    r32 = 0.0
+    r33 = 1.0
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,17 @@
+Bloxorz Lite
+  by Viktor Devecseri (devi86@gmail.com)
+
+This is a simplified version of Bloxorz:
+http://www.miniclip.com/games/bloxorz/
+The aim is to roll the block on the board to
+the end hole.
+
+It is my first Haskell program, and it was
+written as a homework.
+
+Building:
+  ghc --make -O2 -o bloxorz Main.hs
+
+Controls:
+  Esc, q - Quit
+  arrows - Move block
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/TODO b/TODO
new file mode 100644
--- /dev/null
+++ b/TODO
@@ -0,0 +1,9 @@
+2009.06.28.
+---------------------------------------------
+[ ] camera rotation with mouse
+[ ] refactor cube falling
+[ ] lighting, GLSL
+[ ] OpenGL immediate mode -> Vertex Array or VBO
+[ ] support other fields, more levels
+[ ] menu, tutorial
+[ ] OpenGL 3
diff --git a/bloxorz.cabal b/bloxorz.cabal
new file mode 100644
--- /dev/null
+++ b/bloxorz.cabal
@@ -0,0 +1,19 @@
+Name:                bloxorz
+Version:             0.1
+Synopsis:	     OpenGL Logic Game
+Description:	     Roll the block on the board to the end hole.
+License:             GPL
+Author:              Viktor Devecseri
+Maintainer:	     Viktor Devecseri <devi86@gmail.com>
+Category:            Game
+Build-Type:          Simple
+Cabal-Version:       >= 1.2
+Tested-with:         GHC==6.8.2
+Extra-Source-Files:  README, CHANGELOG, TODO, makefile
+Data-Files:	     data/bg.tga, data/cube.tga, data/floor.tga
+
+Executable bloxorz
+  Executable:          bloxorz
+  Main-is:             Main.hs
+  Build-Depends:       base > 3 && < 4, OpenGL, GLFW
+  Other-Modules:       Cubezor, Etc, Maps, Quaternion
diff --git a/data/bg.tga b/data/bg.tga
new file mode 100644
Binary files /dev/null and b/data/bg.tga differ
diff --git a/data/cube.tga b/data/cube.tga
new file mode 100644
Binary files /dev/null and b/data/cube.tga differ
diff --git a/data/floor.tga b/data/floor.tga
new file mode 100644
Binary files /dev/null and b/data/floor.tga differ
diff --git a/makefile b/makefile
new file mode 100644
--- /dev/null
+++ b/makefile
@@ -0,0 +1,15 @@
+PROGRAM = bloxorz
+OBJS = Quaternion.o Maps.o Paths_Bloxorz.o Etc.o Cubezor.o Main.o
+
+all: build
+
+clean:
+	rm -f ${PROGRAM} ${OBJS} ${patsubst %.o,%.hi,${OBJS}}
+
+build: ${PROGRAM}
+
+${PROGRAM}: ${OBJS}
+	ghc -o ${PROGRAM} -package OpenGL -package GLFW -O2 ${OBJS}
+
+%.o: %.hs
+	ghc -O2 -c -o $@ $<
