packages feed

processing-for-haskell (empty) → 0.1.0.0

raw patch · 48 files changed

+2249/−0 lines, 48 filesdep +GLUTdep +NumInstancesdep +OpenGLsetup-changed

Dependencies added: GLUT, NumInstances, OpenGL, base, data-default, hsnoise, random, time, transformers, utf8-string, vector-space

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for processing-for-haskell
+
+## 0.1.0.0  -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2016, Anton Kholomiov
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Anton Kholomiov nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple
+main = defaultMain
+ processing-for-haskell.cabal view
@@ -0,0 +1,138 @@+-- Initial processing-for-haskell.cabal generated by cabal init.  For 
+-- further documentation, see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                processing-for-haskell
+
+-- The package version.  See the Haskell package versioning policy (PVP) 
+-- for standards guiding when and how versions should be incremented.
+-- https://wiki.haskell.org/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis:           Computer graphics for kids and artists with Processing implemented in Haskell. 
+
+-- A longer description of the package.
+description:        The library implements the Processing language (see <https://processing.org/>). It's an imperative EDSL for graphics and animation.
+                    It's very easy and fun to use. There are many books on processing and community is fairly active. 
+                    We can find the quick start guide and lots of examples in the project repository 
+                    on github <https://github.com/anton-k/processing-for-haskell> (see the directory @examples@). 
+                    There is a tutorial at the project homepage at github: <https://github.com/anton-k/processing-for-haskell>.
+
+-- The license under which the package is released.
+license:             BSD3
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Anton Kholomiov
+
+-- An email address to which users can send suggestions, bug reports, and 
+-- patches.
+maintainer:          anton.kholomiov@gmail.com
+
+-- A copyright notice.
+-- copyright:           
+
+category:            Graphics
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a 
+-- README.
+extra-source-files:  ChangeLog.md
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.10
+
+
+library
+  -- Modules exported by the library.
+  exposed-modules:
+    Graphics.Proc       
+  
+  -- Modules included in this library but not exported.
+  other-modules:  
+    Graphics.Proc.Core
+    
+    Graphics.Proc.Core.PioRef    
+    Graphics.Proc.Core.Run
+    Graphics.Proc.Core.GLBridge
+    Graphics.Proc.Core.Vector
+
+    Graphics.Proc.Core.State
+    Graphics.Proc.Core.State.Pio 
+    Graphics.Proc.Core.State.Elements
+    Graphics.Proc.Core.State.Elements.Input
+    Graphics.Proc.Core.State.Elements.Rnd
+    Graphics.Proc.Core.State.Elements.Draw
+    Graphics.Proc.Core.State.Elements.Font
+    Graphics.Proc.Core.State.Elements.Frame
+    Graphics.Proc.Core.State.Elements.Time
+
+    Graphics.Proc.Lib
+
+    Graphics.Proc.Lib.Environment
+
+    Graphics.Proc.Lib.Data
+    Graphics.Proc.Lib.Data.Conversion
+
+    Graphics.Proc.Lib.Control
+
+    Graphics.Proc.Lib.Shape
+    Graphics.Proc.Lib.Shape.Primitive2D
+    Graphics.Proc.Lib.Shape.Curve    
+    Graphics.Proc.Lib.Shape.Attribute
+
+    Graphics.Proc.Lib.Input
+    Graphics.Proc.Lib.Input.Mouse
+    Graphics.Proc.Lib.Input.Keyboard
+    Graphics.Proc.Lib.Input.Time
+
+    Graphics.Proc.Lib.Output
+    Graphics.Proc.Lib.Output.TextArea
+
+    Graphics.Proc.Lib.Transform
+
+    Graphics.Proc.Lib.Lights
+
+    Graphics.Proc.Lib.Camera
+
+    Graphics.Proc.Lib.Color
+
+    Graphics.Proc.Lib.Image
+
+    Graphics.Proc.Lib.Typography
+    Graphics.Proc.Lib.Typography.Display
+    Graphics.Proc.Lib.Typography.Attributes
+    Graphics.Proc.Lib.Typography.Metrics
+
+    Graphics.Proc.Lib.Math 
+    Graphics.Proc.Lib.Math.Calculation
+    Graphics.Proc.Lib.Math.Trigonometry
+    Graphics.Proc.Lib.Math.Random
+
+    Graphics.Proc.Lib.Misc
+
+  -- LANGUAGE extensions used by modules in this package.
+  other-extensions: DeriveFunctor, GeneralizedNewtypeDeriving
+  
+  -- Other library packages from which modules are imported.
+  build-depends:       
+    base >=4.7 && <7, 
+    data-default, transformers, random, time, hsnoise, 
+    OpenGL, GLUT, 
+    -- FTGL, 
+    utf8-string,
+    vector-space, NumInstances
+  
+  -- Directories containing source files.
+  hs-source-dirs:      src
+  
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+  
+ src/Graphics/Proc.hs view
@@ -0,0 +1,196 @@+-- | Imperative EDSL for graphics and animation. The libary implements a Processing in Haskell.
+--
+-- An example:
+--
+-- > import Graphics.Proc
+-- > 
+-- > main = runProc $ def { procSetup = setup, procDraw = draw, procUpdate = update }
+-- > 
+-- > setup = do
+-- > 	size (300, 300)
+-- > 	return 0
+-- > 
+-- > draw x = do	
+-- > 	background (grey 255)
+-- > 	fill (rgb 0 255 0)
+-- > 	circle 20 (150 + 50 * sin x, 150)
+-- > 
+-- > update x = return (x + 0.1)
+-- > 
+-- We can find the quickstart guide and lots of examples in the project repository on github <https://github.com/anton-k/processing-for-haskell> (see the directory @examples@).
+module Graphics.Proc(
+	-- * Structure
+	Proc(..), runProc,
+	
+	-- * Types
+	Pio, Draw, Update, TimeInterval, Col(..), P2, P3,
+
+	-- * Environment
+	winSize, winWidth, winHeight,
+	size,
+	smooth, noSmooth, frameCount, frameRate,
+	loop, noLoop, redraw,
+
+	-- * Data
+	-- | We can use ordinary Haskell datatypes primitive and composite ones.
+
+	-- ** Conversion
+	float, int,
+	
+	-- ** String Functions
+	-- | We can use standard Haskell string functions.
+
+	-- ** Array Functions
+	--  | We can use Haskell arrays.
+	
+	-- * Control
+	-- | We can use plain old Bool datatype.
+
+	
+	-- * Shape
+
+	-- ** 2D Primitives
+
+	triangle, rect, quad, ellipse, circle, line, linePath, point, pointPath, polygon,
+
+	-- ** Curves
+	bezier,
+
+	-- ** 3D Primitives
+
+	-- ** Attributes
+	EllipseMode, RectMode, DrawMode(..), ellipseMode, rectMode,
+	strokeWeight,
+
+	-- ** Vertex
+
+	-- ** Loading & Displaying
+
+	-- * Input
+
+	-- ** Mouse
+	mouse, mouseX, mouseY, 
+	relMouse, relMouseX, relMouseY,
+	MouseButton(..),
+	mouseButton,
+
+	-- ** Keyboard
+	Key(..), SpecialKey(..), key, Modifiers(..), modifiers, 
+
+	-- ** Files
+
+	-- ** Time & Date
+	year, month, day, hour, minute, second, millis, utcHour,
+
+	-- * Output	
+
+	-- ** Text Area
+	println,
+
+	-- ** Image
+	
+	-- ** Files
+	
+	-- * Transform
+	translate, 
+	rotate, rotateX, rotateY, rotateZ, 
+	scale, 
+	resetMatrix, local, 
+	applyMatrix, 
+	shearX, shearY,
+
+	-- * Lights
+	
+	-- * Camera
+
+	-- ** Coordinates
+
+    -- ** Material Properties  
+	
+	-- * Color		
+    fill, noFill, stroke, noStroke, strokeFill,
+    rgb, rgba, grey, greya, setAlpha,
+	background, clear,
+
+	white, black, navy, blue, aqua, teal, olive, green,
+	lime, yellow, orange, red, maroon, fushsia, purple,
+	gray, silver,
+
+
+	-- * Image	
+
+	-- ** Loading & Displaying
+
+	-- ** Textures
+
+	-- ** Pixels
+
+	-- ** Rendering
+
+	-- ** Shaders
+
+	-- * Typography
+
+	-- ** Loading & Displaying
+	-- Font, loadFont, text, textFont,
+
+	-- ** Attributes
+	-- textSize,
+	
+	-- ** Metrics
+
+	-- * Math
+
+	-- ** Operators
+	
+	-- ** Bitwise Operators
+	
+	-- ** Calculation
+	remap, FloatInterval,
+	constrain, constrain2,
+
+	-- ** Trigonometry
+	radians, degrees, e, erad,
+
+	-- ** Random
+	randomSeed, random, random2, randomP2, randomCol, randomCola,
+	randomGaussian,
+
+	-- *** Perlin noise
+	-- | Returns the Perlin noise value at specified coordinates. Perlin noise is a random sequence generator producing a more natural, harmonic succession of numbers than that of the standard random() function. It was developed by Ken Perlin in the 1980s and has been used in graphical applications to generate procedural textures, shapes, terrains, and other seemingly organic forms.
+  	--
+  	-- processing docs: <https://processing.org/reference/noise_.html>
+	NoiseDetail(..), noiseDetail, noiseOctaves, noiseSeed, noise1, noise2, noise3,
+	
+	-- * Misc
+	onCircle, onLine, uon,
+
+	-- * Pio mutable values
+	PioRef, newPioRef, readPioRef, writePioRef, modifyPioRef,
+
+	-- | Useful standard functions
+	module Data.VectorSpace,
+	module Data.AffineSpace,
+	module Data.Cross,	
+    module Data.NumInstances,
+	module Data.Default,
+	module Data.Monoid,
+	module Control.Monad,
+	module Control.Monad.IO.Class,
+	module Control.Applicative	
+) where
+
+import Data.Default
+import Data.Monoid
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Applicative
+
+import Data.VectorSpace hiding (Sum(..))
+import Data.NumInstances
+import Data.AffineSpace
+import Data.Cross
+
+import Graphics.Proc.Core
+import Graphics.Proc.Lib
+
+ src/Graphics/Proc/Core.hs view
@@ -0,0 +1,28 @@+module Graphics.Proc.Core(
+
+	module Graphics.Proc.Core.State,
+	module Graphics.Proc.Core.PioRef,
+	module Graphics.Proc.Core.Run,
+	module Graphics.Proc.Core.Vector,
+	module Graphics.Proc.Core.GLBridge,
+
+	-- | Common reexports
+	module Data.Default,
+	module Control.Monad,
+	module Control.Applicative,
+	module Control.Monad.IO.Class
+
+) where
+
+
+import Data.Default
+import Control.Monad
+import Control.Applicative
+import Control.Monad.IO.Class
+
+import Graphics.Proc.Core.State
+import Graphics.Proc.Core.PioRef
+import Graphics.Proc.Core.Run
+import Graphics.Proc.Core.Vector
+import Graphics.Proc.Core.GLBridge
+
+ src/Graphics/Proc/Core/GLBridge.hs view
@@ -0,0 +1,74 @@+module Graphics.Proc.Core.GLBridge(
+  MouseButton(..), Modifiers(..), Key(..), KeyState(..), Position(..), SpecialKey(..),
+  -- Font,
+  Col(..), glCol,
+  f2d, v2, p2v,
+  glSize, setupWindow, getWindowSize  
+) where
+
+import Graphics.Rendering.OpenGL hiding (scale, translate, rotate, rect, height, width)
+import qualified Graphics.Rendering.OpenGL as G
+import Graphics.UI.GLUT hiding (scale, translate, rotate, rect, rgba, Font)
+-- import Graphics.Rendering.FTGL
+
+import Data.Default
+import Control.Monad.IO.Class
+import GHC.Float
+
+-- | Color datatype. It contains values for three components of the color and transparency.
+-- All values range in the interval from 0 to 1.
+data Col = Col Float Float Float Float
+    deriving (Show)
+
+instance Default Col where
+  def = black
+    where black = Col 0 0 0 1
+
+glCol (Col r g b a) = Color4 r g b a
+
+-----------------------------------------
+-- init window
+
+setupWindow :: IO ()
+setupWindow = do
+  getArgsAndInitialize  
+  initialDisplayMode $= [DoubleBuffered]    
+  createWindow ""
+  multisample $= Enabled
+  blend $= Enabled
+  blendFunc $= (SrcAlpha, OneMinusSrcAlpha)
+  glSize (100, 100)
+  clearColor $= Color4 1 1 1 1
+  G.clear [ColorBuffer]  
+
+glSize :: (Float, Float) -> IO ()
+glSize p@(w, h) = do
+  windowSize $= fromPoint p
+  projection2 0 w h 0
+  where
+    fromPoint (x, y) = Size (f x) (f y)
+    f = toEnum . floor
+
+projection2 xl xu yl yu = do
+  matrixMode $= Projection
+  loadIdentity
+  ortho (f2d xl) (f2d xu) (f2d yl) (f2d yu) zl zu 
+  matrixMode $= Modelview 0
+  where
+    zl = -5
+    zu = 5
+
+--------------------------------------------
+
+getWindowSize :: IO (Int, Int)
+getWindowSize = do
+  Size w h <- G.get windowSize 
+  return (fromEnum w, fromEnum h)
+
+--------------------------------------------
+-- converters
+
+f2d = float2Double     
+
+v2 (x, y) = vertex $ Vertex3 (f2d x) (f2d y) 0
+p2v (x, y)= Vector3 (f2d x) (f2d y) 0
+ src/Graphics/Proc/Core/PioRef.hs view
@@ -0,0 +1,31 @@+module Graphics.Proc.Core.PioRef(
+	PioRef, newPioRef, readPioRef, writePioRef, modifyPioRef
+) where
+
+import Data.IORef
+
+import Control.Monad.IO.Class
+
+import Graphics.Proc.Core.State
+
+-- | Datatyp for mutable variables. We can create a reference
+-- and then manipulate the value with functions @readPioRef@ and @writePioRef@.
+-- The API is the same as in the case of @IORef@s. It's standard way to work with mutables in haskell.
+newtype PioRef a = PioRef { unPioRef :: IORef a }
+	deriving (Eq)
+
+-- | Creates a reference for a mutable value. The argument is an initial value assigned to the variable.
+newPioRef :: a -> Pio (PioRef a)
+newPioRef a = liftIO $ fmap PioRef $ newIORef a
+
+-- | Reads the value from the reference.
+readPioRef :: PioRef a -> Pio a
+readPioRef (PioRef ref) = liftIO $ readIORef ref
+
+-- | Writes the value to reference.
+writePioRef :: PioRef a -> a -> Pio ()
+writePioRef (PioRef ref) value = liftIO $ writeIORef ref value
+
+-- | Modifies a value iside the reference with a function.
+modifyPioRef :: PioRef a -> (a -> a) -> Pio ()
+modifyPioRef (PioRef ref) f = liftIO $ modifyIORef ref f
+ src/Graphics/Proc/Core/Run.hs view
@@ -0,0 +1,173 @@+{-# Language FlexibleContexts #-}
+module Graphics.Proc.Core.Run(
+	Proc(..), runProc, Draw, Update, TimeInterval
+) where
+
+import Control.Monad.IO.Class
+
+import Data.Default
+import Data.IORef
+
+import qualified Graphics.Rendering.OpenGL as G
+import Graphics.Rendering.OpenGL
+import Graphics.UI.GLUT
+
+import Graphics.Proc.Core.State
+import Graphics.Proc.Core.GLBridge
+
+
+-- | A alias for value update inside processing IO-monad.
+type Update s = s -> Pio s
+
+-- | An alias for processing procedures.
+type Draw = Pio ()
+
+-- | It holds all processing standard callbacks. 
+-- With it we can set the setup, draw, and update functions.
+-- Here we can specify how to react on user-input.
+--
+-- All functions update the program state. They take it in as an argument and produce as result.
+-- In Haskell we can not manipulate global variables with such ease as Processing provides.
+-- So we have to find out another way to update the state. The natural way for Haskell is to keep
+-- the things as explicit as possible. That leads to the following decisions:
+--
+-- * @setup@ returns the initial state.
+--
+-- * @draw@ takes the state as an argument and draws it.
+--
+-- * @update@ should take in the current state and return back the next state.
+--
+-- * All input processing functions also manipulate the state explicitly by passing arguments.
+--
+-- Notice that the processing function draw is split on two functions: draw and update.
+-- The draw is only for drawing the program state and update is for state update.
+--
+-- There is a useful function procUpdateTime that provides a time interval that has passed since
+-- the previous update of the state. It can be useful for physics engines.
+data Proc s = Proc 
+    { procSetup :: Pio s
+    , procUpdate :: Update s
+    , procUpdateTime :: TimeInterval -> Update s 
+    , procDraw  :: s -> Draw
+
+    -- mouse callbacks
+    , procMousePressed  :: Update s    
+    , procMouseReleased :: Update s
+    , procMouseClicked  :: Update s
+    , procMouseDragged  :: Update s
+    , procMouseMoved    :: Update s
+
+    -- keyboard callbacks
+    , procKeyPressed   :: Update s
+    , procKeyReleased  :: Update s
+    , procKeyTyped     :: Update s
+    }
+
+instance Default (Proc s) where
+    def = Proc
+        { procSetup = return $ error "No setup is defined. Please define the procSetup value."
+        , procUpdate = return
+        , procUpdateTime = const return
+        , procDraw = const (return ()) 
+        -- mouse
+        , procMousePressed  = return
+        , procMouseReleased = return
+        , procMouseClicked  = return
+        , procMouseDragged  = return
+        , procMouseMoved    = return
+        -- keyboard
+        , procKeyPressed    = return
+        , procKeyReleased   = return
+        , procKeyTyped      = return
+        }
+
+data St s = St
+  { stUser   :: s
+  , stGlobal :: GlobalState }
+
+initSt :: Proc s -> IO (St s)
+initSt p = do
+  (user, global) <- runPio (procSetup p) =<< defGlobalState
+  return $ St user global
+
+updateSt :: IORef (St s) -> Update s -> IO ()
+updateSt ref f = do
+  st <- get ref
+  (user, global) <- runPio (f (stUser st)) (stGlobal st)
+  ref $= St user global
+
+passSt :: IORef (St s) -> Pio () -> IO ()
+passSt ref p = updateSt ref $ \s -> p >> return s
+
+-- | The main function for rendering processing actions.
+-- It sets the scene and starts the rendering of animation.
+runProc :: Proc s -> IO ()
+runProc p = do
+  setupWindow
+  ref <- newIORef =<< initSt p
+
+  nextFrame ref
+  displayCallback       $= display ref  
+  keyboardMouseCallback $= Just (keyMouse ref)
+  motionCallback        $= Just (mouseMotion ref)
+  passiveMotionCallback $= Just (passiveMouseMotion ref)
+
+  mainLoop
+  where   
+    display ref = updateSt ref $ \s -> do      
+      liftIO $ loadIdentity
+      procDraw p s      
+      liftIO $ swapBuffers
+      updateFrameCount
+      return s
+
+    idle ref = do 
+      loopInfo <- getLoopInfo ref
+      case loopInfo of
+        Loop   -> updateLoopState ref      
+        NoLoop -> return ()
+        Redraw -> updateLoopState ref >> passSt ref (putLoopMode NoLoop)
+      nextFrame ref
+
+    updateLoopState ref =  updateSt ref $ \s -> do      
+        s1 <- procUpdate p s
+        dt <- getDuration
+        s2 <- procUpdateTime p dt s1
+        liftIO $ postRedisplay Nothing
+        return s2
+
+    nextFrame ref = do
+      timeOut <- getTimeoutInterval ref
+      addTimerCallback timeOut (idle ref)
+
+    keyMouse ref key keyState modifiers pos = updateSt ref $ \s -> do
+      putPosition pos
+      case keyState of 
+        Down -> do
+          case key of
+            MouseButton mb -> do
+              putMouseButton (Just mb)
+              procMousePressed p s
+            keyPress -> do
+              putKeyPress keyPress
+              procKeyPressed p s
+        Up   -> 
+          case key of
+            Char ch -> procKeyReleased p s
+            SpecialKey sk -> return s
+            MouseButton mb -> do
+              putMouseButton Nothing
+              procMouseReleased p s     
+
+    mouseMotion ref pos = passSt ref $ putPosition pos
+    passiveMouseMotion ref pos = passSt ref $ putPosition pos
+
+getTimeoutInterval ref = readRef getter ref
+  where getter = fmap (round . (1000 * ) . recip) getFrameRate
+
+getLoopInfo ref = readRef getLoopMode ref
+
+readRef getter ref = do
+  st <- fmap stGlobal $ get ref
+  fmap fst $ runPio getter st
+
+ src/Graphics/Proc/Core/State.hs view
@@ -0,0 +1,145 @@+module Graphics.Proc.Core.State(
+	Pio(..), runPio, 
+  	GlobalState(..), defGlobalState,
+
+	-- * Input
+	MouseButton(..), Modifiers(..), Key(..), KeyState(..),
+	putKeyPress, putMouseButton, putPosition,
+	getMousePosition, getMouseButton, getLastPressedKey, getPressedModifiers, 
+
+	-- * Random
+	NoiseDetail(..), Seed,
+	getRandomGen, getNoiseGen, getNoiseDetail, 
+	putRandomGen, putNoiseGen, putNoiseDetail,
+	putOctaves,
+
+	-- * Draw
+	DrawState(..),
+    EllipseMode, RectMode, DrawMode(..), 
+    StrokeCap(..), StrokeJoin(..),
+
+    getStroke, getFill, getEllipseMode, getRectMode,
+    putEllipseMode, putStroke, putFill, putRectMode,
+
+	-- * Font
+
+	-- * Frame
+	LoopMode(..), 
+    updateFrameCount, frameCount, 
+    getFrameRate, putFrameRate, 
+    getLoopMode, putLoopMode, 
+
+	-- * Time
+	initTimeState, TimeInterval, getDuration, getStartTime
+) where
+
+import Data.Time.Clock
+import Control.Monad.Trans.State.Strict
+
+import Graphics.Proc.Core.State.Pio
+import Graphics.Proc.Core.GLBridge
+import Graphics.Proc.Core.Vector
+import qualified Graphics.Proc.Core.State.Elements as E
+import Graphics.Proc.Core.State.Elements hiding (updateFrameCount, getDuration, frameCount)
+
+----------------------------------------
+-- input
+
+putKeyPress :: Key -> Pio ()
+putKeyPress key = onInput $ modify $ \x -> x { lastPressedKey = key }
+
+putMouseButton :: Maybe MouseButton -> Pio ()
+putMouseButton mb = onInput $ modify $ \x -> x { pressedButton = mb }
+
+putPosition :: Position -> Pio ()
+putPosition pos = onInput $ modify $ \x -> x { mousePosition = fromPosition pos }
+	where fromPosition (Position x y) = (fromEnum x, fromEnum y)
+
+getMousePosition :: Pio P2
+getMousePosition = onInput $ fmap ((\(x, y) -> (fromIntegral x, fromIntegral y)) . mousePosition) get
+
+getLastPressedKey :: Pio Key
+getLastPressedKey   = onInput $ fmap lastPressedKey get
+
+getPressedModifiers :: Pio Modifiers
+getPressedModifiers = onInput $ fmap pressedModifiers get
+
+getMouseButton :: Pio (Maybe MouseButton)
+getMouseButton = onInput $ fmap pressedButton get
+
+----------------------------------------
+-- random
+
+getRandomGen     = onRnd $ fmap rndRandomGen get
+getNoiseGen      = onRnd $ fmap rndNoiseGen  get
+getNoiseDetail   = onRnd $ fmap rndNoiseDetail get
+
+putRandomGen     v = onRnd $ modify $ \x -> x { rndRandomGen = v }
+putNoiseGen      v = onRnd $ modify $ \x -> x { rndNoiseGen = v }
+putNoiseDetail   v = onRnd $ modify $ \x -> x { rndNoiseDetail = v }
+
+putOctaves v = onRnd $ modify $ \x -> x { rndNoiseDetail = go (rndNoiseDetail x) v }
+	where go nd v = nd { noiseDetailsOctaves = v }
+
+----------------------------------------
+-- draw
+
+getStroke :: Pio (Maybe Col)
+getStroke = fmap drawStroke $ onDraw get
+
+getFill :: Pio (Maybe Col)
+getFill = fmap drawFill $ onDraw get
+
+getEllipseMode :: Pio EllipseMode
+getEllipseMode = fmap drawEllipseMode $ onDraw get
+
+getRectMode :: Pio RectMode
+getRectMode = fmap drawRectMode $ onDraw get
+
+putEllipseMode :: EllipseMode -> Pio ()
+putEllipseMode value = onDraw $ modify $ \x -> x { drawEllipseMode = value }
+
+putRectMode :: RectMode -> Pio ()
+putRectMode value = onDraw $ modify $ \x -> x { drawRectMode = value }
+
+putStroke :: Maybe Col -> Pio ()
+putStroke value = onDraw $ modify $ \x -> x { drawStroke = value }
+
+putFill :: Maybe Col -> Pio ()
+putFill value = onDraw $ modify $ \x -> x { drawFill = value }
+
+----------------------------------------
+-- font
+
+----------------------------------------
+-- frame
+
+updateFrameCount :: Pio ()
+updateFrameCount = onFrame E.updateFrameCount
+
+-- | The system variable frameCount contains the number of frames that have been displayed since the program started. Inside setup() the value is 0, after the first iteration of draw it is 1, etc.
+-- 
+-- processing docs: <https://processing.org/reference/frameCount.html>
+frameCount :: Pio Int
+frameCount = onFrame $ fmap E.frameCount get
+
+getFrameRate :: Pio Float
+getFrameRate = onFrame $ fmap E.frameRate get
+
+putFrameRate :: Float -> Pio ()
+putFrameRate value = onFrame $ modify $ \x -> x { frameRate = value }
+
+getLoopMode :: Pio LoopMode
+getLoopMode = onFrame $ fmap frameLoop get
+
+putLoopMode :: LoopMode -> Pio ()
+putLoopMode value = onFrame $ modify $ \x -> x { frameLoop = value }
+
+----------------------------------------
+-- time
+
+getDuration :: Pio TimeInterval
+getDuration = onTimeIO E.getDuration
+
+getStartTime :: Pio UTCTime
+getStartTime = onTime $ fmap timeStart get
+ src/Graphics/Proc/Core/State/Elements.hs view
@@ -0,0 +1,16 @@+module Graphics.Proc.Core.State.Elements(
+	module Graphics.Proc.Core.State.Elements.Input,
+	module Graphics.Proc.Core.State.Elements.Rnd,
+	module Graphics.Proc.Core.State.Elements.Draw,
+	module Graphics.Proc.Core.State.Elements.Font,
+	module Graphics.Proc.Core.State.Elements.Frame,
+	module Graphics.Proc.Core.State.Elements.Time
+
+) where
+
+import Graphics.Proc.Core.State.Elements.Input
+import Graphics.Proc.Core.State.Elements.Rnd
+import Graphics.Proc.Core.State.Elements.Draw
+import Graphics.Proc.Core.State.Elements.Font
+import Graphics.Proc.Core.State.Elements.Frame
+import Graphics.Proc.Core.State.Elements.Time
+ src/Graphics/Proc/Core/State/Elements/Draw.hs view
@@ -0,0 +1,57 @@+module Graphics.Proc.Core.State.Elements.Draw(
+    DrawState(..),
+    EllipseMode, RectMode, DrawMode(..), 
+    StrokeCap(..), StrokeJoin(..)    
+) where
+
+import Control.Monad.Trans.State.Strict
+import Data.Default
+import Graphics.Proc.Core.GLBridge
+
+data DrawState = DrawState 
+  { drawEllipseMode   :: EllipseMode
+  , drawRectMode      :: RectMode
+  , drawStrokeCap     :: StrokeCap
+  , drawStrokeJoin    :: StrokeJoin
+  , drawStrokeWeight  :: Float
+  , drawFill          :: Maybe Col
+  , drawStroke        :: Maybe Col  
+  }
+
+instance Default DrawState where
+  def = DrawState 
+    { drawEllipseMode  = Center
+    , drawRectMode     = Corner
+    , drawStrokeCap    = Round
+    , drawStrokeJoin   = JoinMiter
+    , drawStrokeWeight = 1
+    , drawFill         = Just $ Col 0 0 0 1
+    , drawStroke       = Just $ Col 0 0 0 1
+    }
+
+-- | Modes for drawing of ellipse. See @ellipseMode@.
+type EllipseMode = DrawMode
+
+-- | Modes for drawing of rectangle. See @rectMode@.
+type RectMode = DrawMode
+
+-- | Modes for drawing of rectangle or ellipse.
+data DrawMode = Radius | Center | Corner | Corners
+  deriving (Show, Eq, Enum, Bounded)
+
+instance Default DrawMode where
+  def = Center
+
+data StrokeCap = Round | Square | Project
+  deriving (Show, Eq, Enum, Bounded)
+
+instance Default StrokeCap where
+  def = Round
+
+data StrokeJoin = JoinMiter | JoinBevel | JoinRound
+  deriving (Show, Eq, Enum, Bounded)
+
+instance Default StrokeJoin where  
+  def = JoinMiter
+
+----------------------------------------------------------
+ src/Graphics/Proc/Core/State/Elements/Font.hs view
@@ -0,0 +1,16 @@+module Graphics.Proc.Core.State.Elements.Font(
+    FontState(..)
+) where
+
+import Data.Default
+
+data FontState = FontState
+  { fontCurrent   :: Maybe Font
+  , fontInitSize  :: Int
+  , fontSize      :: Int
+  }
+
+type Font = String
+
+instance Default FontState where
+  def = FontState Nothing 12 12
+ src/Graphics/Proc/Core/State/Elements/Frame.hs view
@@ -0,0 +1,25 @@+module Graphics.Proc.Core.State.Elements.Frame(
+    FrameState(..), LoopMode(..),
+    updateFrameCount
+) where
+
+import Control.Monad.Trans.State.Strict
+import Data.Default 
+
+data FrameState = FrameState 
+  { frameCount :: Int
+  , frameRate  :: Float
+  , frameLoop  :: LoopMode
+  }
+
+instance Default FrameState where
+  def = FrameState 0 60 Loop
+
+data LoopMode = Loop | NoLoop | Redraw
+  deriving (Show, Eq, Enum, Bounded)
+
+instance Default LoopMode where
+    def = Loop  
+
+updateFrameCount :: State FrameState ()
+updateFrameCount = modify $ \x -> x { frameCount = succ (frameCount x) }
+ src/Graphics/Proc/Core/State/Elements/Input.hs view
@@ -0,0 +1,26 @@+module Graphics.Proc.Core.State.Elements.Input(
+    InputState(..), MouseButton(..), Modifiers(..), Key(..), KeyState(..)   
+) where
+
+import Data.Default 
+import Control.Monad.Trans.State.Strict
+
+import Graphics.Proc.Core.GLBridge
+
+data InputState = InputState 
+  { lastPressedKey   :: Key
+  , pressedModifiers :: Modifiers
+  , mousePosition    :: (Int, Int)
+  , pressedButton    :: Maybe MouseButton
+  }
+
+instance Default Modifiers where
+  def = Modifiers Up Up Up
+
+instance Default InputState where
+  def  = InputState 
+    { lastPressedKey = Char ' '
+    , pressedModifiers = def 
+    , mousePosition   = (0, 0)
+    , pressedButton   = Nothing
+    }
+ src/Graphics/Proc/Core/State/Elements/Rnd.hs view
@@ -0,0 +1,27 @@+module Graphics.Proc.Core.State.Elements.Rnd(
+    RndState(..),
+    NoiseDetail(..), Seed
+) where
+
+import Data.Default 
+import System.Random
+
+data RndState = RndState 
+  { rndRandomGen     :: Maybe StdGen
+  , rndNoiseGen      :: Maybe Int
+  , rndNoiseDetail   :: NoiseDetail
+  }
+
+instance Default RndState where
+  def = RndState def def def  
+
+type Seed = Maybe Int
+
+-- | Parameters for perlin noise. See docs for function @noiseDetail@.
+data NoiseDetail = NoiseDetail 
+  { noiseDetailsOctaves :: Int
+  , noiseDetailsFalloff :: Float
+  }
+
+instance Default NoiseDetail where
+  def = NoiseDetail 4 0.5
+ src/Graphics/Proc/Core/State/Elements/Time.hs view
@@ -0,0 +1,24 @@+module Graphics.Proc.Core.State.Elements.Time(
+    TimeState(..), initTimeState, TimeInterval, getDuration
+) where
+
+import Data.Time.Clock
+import Control.Monad.Trans.State.Strict
+
+-- | Time duration in seconds.
+type TimeInterval = Float
+
+data TimeState = TimeState 
+  { timeLast      :: UTCTime
+  , timeStart     :: UTCTime }
+
+initTimeState = fmap (\x -> TimeState x x) getCurrentTime   
+
+------------------------------------------
+
+getDuration :: StateT TimeState IO TimeInterval
+getDuration = StateT $ \s -> do
+    let prevTime = timeLast s
+    now <- getCurrentTime
+    let dt = fromRational $ toRational $ diffUTCTime now prevTime
+    return (dt, s { timeLast = now })
+ src/Graphics/Proc/Core/State/Pio.hs view
@@ -0,0 +1,90 @@+{-# Language DeriveFunctor, GeneralizedNewtypeDeriving #-}
+-- | The Processing IO-monad.
+module Graphics.Proc.Core.State.Pio(
+  Pio(..), runPio, 
+  GlobalState(..), defGlobalState,
+
+  onInput, onRnd, onDraw, onFont, onFrame, onTime, onTimeIO
+) where
+
+import Data.Default
+import Data.IORef
+import Control.Monad.IO.Class
+import Control.Monad.Trans.State.Strict
+
+import Graphics.Proc.Core.State.Elements
+
+-- | Processing IO-monad. It has the same meaning as the Haskell IO-monad but
+-- it's augmented with Processing library functions.
+--
+-- We can use @liftIO@ to execute ordinary Haskell IO-actions.
+-- The Pio has instance for class @MonadIO@.
+--
+-- > text <- liftIO $ readFile filename
+newtype Pio a = Pio { unPio :: StateT GlobalState IO a }
+  deriving (Functor, Applicative, Monad, MonadIO)
+
+runPio :: Pio a -> GlobalState -> IO (a, GlobalState)
+runPio (Pio x) st = runStateT x st
+
+readPio :: (InputState -> a) -> Pio a
+readPio selector = readStatePio (selector . globalInputState)
+
+readStatePio :: (GlobalState -> a) -> Pio a
+readStatePio selector = Pio $ do
+  st <- get  
+  return $ selector st
+
+modifyStatePio :: (GlobalState -> GlobalState) -> Pio ()
+modifyStatePio update = Pio $ do
+  st <- get
+  put $ update st
+
+data GlobalState = GlobalState 
+  { globalInputState    :: InputState
+  , globalRndState      :: RndState
+  , globalDrawState     :: DrawState  
+  , globalFontState     :: FontState
+  , globalTimeState     :: TimeState
+  , globalFrameState    :: FrameState
+  }
+
+defGlobalState :: IO GlobalState
+defGlobalState = fmap (\timeSt -> GlobalState def def def def timeSt def) initTimeState
+
+onInput :: State InputState a -> Pio a
+onInput = onState globalInputState (\x a -> x { globalInputState = a })
+
+onRnd :: State RndState a -> Pio a
+onRnd = onState globalRndState (\x a -> x { globalRndState = a })
+
+onDraw :: State DrawState a -> Pio a
+onDraw = onState globalDrawState (\x a -> x { globalDrawState = a })
+
+onFont :: State FontState a -> Pio a
+onFont = onState globalFontState (\x a -> x { globalFontState = a })
+
+onFrame :: State FrameState a -> Pio a
+onFrame = onState globalFrameState (\x a -> x { globalFrameState = a })
+
+onTime :: State TimeState a -> Pio a
+onTime = onState globalTimeState (\x a -> x { globalTimeState = a })
+
+onTimeIO :: StateT TimeState IO a -> Pio a
+onTimeIO = onStateIO globalTimeState (\x a -> x { globalTimeState = a })
+
+--------------------------------------------------
+
+onState :: (GlobalState -> a) -> (GlobalState -> a -> GlobalState) -> State a b -> Pio b
+onState getter setter act = Pio $ do
+  st <- get
+  let (b, a) = runState act (getter st)
+  put $ setter st a
+  return b
+
+onStateIO :: (GlobalState -> a) -> (GlobalState -> a -> GlobalState) -> StateT a IO b -> Pio b
+onStateIO getter setter act = Pio $ do
+  st <- get
+  (b, a) <- liftIO $ runStateT act (getter st)
+  put $ setter st a
+  return b
+ src/Graphics/Proc/Core/Vector.hs view
@@ -0,0 +1,16 @@+module Graphics.Proc.Core.Vector(
+	P2, P3,
+
+	module Data.VectorSpace,
+	module Data.NumInstances
+
+) where
+
+import Data.VectorSpace
+import Data.NumInstances
+
+-- | 2D vector.
+type P2 = (Float, Float)
+
+-- | 3D vector.
+type P3 = (Float, Float, Float)
+ src/Graphics/Proc/Lib.hs view
@@ -0,0 +1,33 @@+module Graphics.Proc.Lib(
+
+	module Graphics.Proc.Lib.Environment,
+	module Graphics.Proc.Lib.Data,
+	module Graphics.Proc.Lib.Control,
+	module Graphics.Proc.Lib.Shape,
+	module Graphics.Proc.Lib.Input,
+	module Graphics.Proc.Lib.Output,
+	module Graphics.Proc.Lib.Transform,
+	module Graphics.Proc.Lib.Lights,
+	module Graphics.Proc.Lib.Camera,
+	module Graphics.Proc.Lib.Color,
+	module Graphics.Proc.Lib.Image,
+	module Graphics.Proc.Lib.Typography,
+	module Graphics.Proc.Lib.Math,
+	module Graphics.Proc.Lib.Misc
+
+) where
+
+import Graphics.Proc.Lib.Environment
+import Graphics.Proc.Lib.Data
+import Graphics.Proc.Lib.Control
+import Graphics.Proc.Lib.Shape
+import Graphics.Proc.Lib.Input
+import Graphics.Proc.Lib.Output
+import Graphics.Proc.Lib.Transform
+import Graphics.Proc.Lib.Lights
+import Graphics.Proc.Lib.Camera
+import Graphics.Proc.Lib.Color
+import Graphics.Proc.Lib.Image
+import Graphics.Proc.Lib.Typography
+import Graphics.Proc.Lib.Math
+import Graphics.Proc.Lib.Misc
+ src/Graphics/Proc/Lib/Camera.hs view
@@ -0,0 +1,2 @@+module Graphics.Proc.Lib.Camera(
+) where
+ src/Graphics/Proc/Lib/Color.hs view
@@ -0,0 +1,157 @@+module Graphics.Proc.Lib.Color(
+	stroke, noStroke,
+	fill, noFill,
+	background, clear,
+	strokeFill,
+
+	rgb, grey, rgba, greya, setAlpha,
+
+	white, black, navy, blue, aqua, teal, olive, green,
+	lime, yellow, orange, red, maroon, fushsia, purple,
+	gray, silver
+) where
+
+import Control.Monad.Trans.State.Strict
+import Graphics.Rendering.OpenGL hiding(clear)
+import qualified Graphics.Rendering.OpenGL as G
+
+import Graphics.Proc.Core
+
+-- | Sets the color used to draw lines and borders around shapes. 
+--
+-- processing docs: <https://processing.org/reference/stroke_.html>	
+stroke :: Col -> Draw
+stroke = putStroke . Just
+
+-- | Disables drawing the stroke (outline). If both noStroke() and noFill() are called, nothing will be drawn to the screen
+-- 
+-- processing docs: <https://processing.org/reference/noStroke_.html>	
+noStroke :: Draw
+noStroke = putStroke Nothing
+
+-- | Sets the color used to fill shapes. For example, if you run @fill (rgb 204 102 0)@, all subsequent shapes will be filled with orange. 
+--
+-- processing docs: <https://processing.org/reference/fill_.html>	
+fill :: Col -> Draw
+fill = putFill . Just
+
+-- | Disables filling geometry. If both noStroke() and noFill() are called, nothing will be drawn to the screen. 
+-- 
+-- processing docs: <https://processing.org/reference/noFill_.html>	
+noFill :: Draw
+noFill = putFill Nothing
+
+-- | Sets stroke and fill to the same color.
+strokeFill :: Col -> Draw
+strokeFill col = do
+    stroke col 
+    fill col
+
+------------------------------------------------------
+
+-- | The background() function sets the color used for the background of the Processing window. The default background is light gray. This function is typically used within draw() to clear the display window at the beginning of each frame, but it can be used inside setup() to set the background on the first frame of animation or if the backgound need only be set once. 
+--
+-- processing docs: <https://processing.org/reference/background_.html>	
+background :: Col -> Draw
+background x = liftIO $ do
+  clearColor $= glCol x
+  G.clear [ColorBuffer]      
+
+-- | Clears the pixels within a buffer.
+--
+-- processing docs: <https://processing.org/reference/clear_.html>	
+
+clear :: Draw
+clear = liftIO $ do
+	G.clear [ColorBuffer]      
+
+------------------------------------------------------
+
+-- | Creates an RGB-color from three values. The values are from 0 to 255.
+rgb :: Float -> Float -> Float -> Col
+rgb r g b = rgba r g b 255
+
+-- | Creates a grey value out of single float value. The value is from 0 to 255.
+grey :: Float -> Col
+grey g = rgb g g g
+
+-- | Creates an RGB-color with transparency.
+rgba :: Float -> Float -> Float -> Float -> Col
+rgba r g b a = Col (r / 255) (g / 255) (b / 255) (a / 255)
+
+-- | Creates an grey-color with transparency.
+greya :: Float -> Float -> Col
+greya g a = rgba g g g a
+
+------------------------------------------------------
+
+setAlpha :: Float -> Col -> Col
+setAlpha x (Col r g b _) = Col r g b (x)
+
+-- | White color.
+white :: Col
+white = Col 1 1 1 1
+
+-- | Black color.
+black :: Col
+black = Col 0 0 0 1
+
+-- | Nave color.
+navy :: Col
+navy = rgb 0 31 63
+
+-- | Blue color.
+blue :: Col
+blue = rgb 0 116 217
+
+-- | Aqua color.
+aqua :: Col
+aqua = rgb 127 219 255
+
+-- | Teal color.
+teal :: Col
+teal = rgb 57 204 204
+
+-- | Olive color.
+olive :: Col
+olive = rgb 61 153 112
+
+-- | Green color.
+green :: Col
+green = rgb 46 204 64
+
+-- | Lime color.
+lime :: Col
+lime = rgb 1 255 112
+
+-- | Yellow color.
+yellow :: Col
+yellow = rgb 255 220 0
+
+-- | Orange color
+orange :: Col 
+orange = rgb 255 33 27
+
+-- | Red color
+red :: Col
+red = rgb 255 65 54
+
+-- | Maroon color.
+maroon :: Col
+maroon = rgb 133 20 75
+
+-- | Fuchsia color.
+fushsia :: Col
+fushsia = rgb 240 18 190
+
+-- | Purple color
+purple :: Col
+purple = rgb 177 13 201
+
+-- | Gray color.
+gray :: Col
+gray = grey 170
+
+-- | Silver color.
+silver :: Col
+silver = grey 221
+ src/Graphics/Proc/Lib/Control.hs view
@@ -0,0 +1,2 @@+module Graphics.Proc.Lib.Control(
+) where
+ src/Graphics/Proc/Lib/Data.hs view
@@ -0,0 +1,8 @@+-- | We can use ordinary Haskell data types, like floats, booleans and strings.
+module Graphics.Proc.Lib.Data(
+	module Graphics.Proc.Lib.Data.Conversion
+) where
+
+import Graphics.Proc.Lib.Data.Conversion	
+
+
+ src/Graphics/Proc/Lib/Data/Conversion.hs view
@@ -0,0 +1,11 @@+module Graphics.Proc.Lib.Data.Conversion(
+	float, int
+) where
+
+-- | Converts ints to floats.
+float :: Int -> Float
+float = fromIntegral
+
+-- | Converts floats to ints.
+int :: Float -> Int 
+int = floor
+ src/Graphics/Proc/Lib/Environment.hs view
@@ -0,0 +1,106 @@+module Graphics.Proc.Lib.Environment(
+	winSize, winWidth, winHeight,
+	size,
+	smooth, noSmooth, 
+    frameCount, frameRate,
+    redraw, loop, noLoop
+) where
+
+import qualified Control.Monad.Trans.State.Strict as S
+import Graphics.Rendering.OpenGL
+
+import Graphics.Proc.Core
+
+-- | Return the pair of width and height as a 2D vector.
+winSize :: Pio P2
+winSize = liftA2 (,) winWidth winHeight
+
+-- | System variable that stores the width of the display window. 
+-- This value is set by the first parameter of the @size()@ function. 
+-- For example, the function call @size(320, 240)@ sets the width 
+-- variable to the value 320. The value of width defaults to 100 
+-- if @size()@ is not used in a program.
+--
+-- processing docs: <https://processing.org/reference/width.html>
+winWidth :: Pio Float
+winWidth  = liftIO $ fmap (fromIntegral . fst) getWindowSize
+
+-- | System variable that stores the height of the display window. 
+-- This value is set by the second parameter of the @winSize()@ function. 
+-- For example, the function call @winSize(320, 240)@ sets the height 
+-- variable to the value 240. The value of height defaults to 100 
+-- if @winSize()@ is not used in a program. 
+--
+-- processing docs: <https://processing.org/reference/height.html>
+winHeight :: Pio Float
+winHeight = liftIO $ fmap (fromIntegral . snd) getWindowSize
+
+--------------------------------------------
+
+-- | Defines the dimension of the display window width and height 
+-- in units of pixels. In a program that has the setup() function, 
+-- the size() function must be the first line of code inside setup().
+--
+-- processing docs: <https://processing.org/reference/size_.html>
+size :: P2 -> Draw
+size = liftIO . glSize
+
+--------------------------------------------
+
+-- | Draws all geometry with smooth (anti-aliased) edges. This behavior is 
+-- the default, so @smooth()@ only needs to be used when a program needs to set 
+-- the smoothing in a different way. The level parameter increases the level 
+-- of smoothness. This is the level of over sampling applied to the graphics buffer.
+--
+-- processing docs: <https://processing.org/reference/smooth_.html>
+smooth :: Draw
+smooth = liftIO $ pointSmooth $= Enabled
+
+-- | Draws all geometry and fonts with jagged (aliased) edges and images 
+-- when hard edges between the pixels when enlarged rather than interpoloating pixels. 
+-- Note that smooth() is active by default, so it is necessary to call noSmooth() 
+-- to disable smoothing of geometry, fonts, and images. 
+--
+-- processing docs: <https://processing.org/reference/noSmooth_.html>
+noSmooth :: Pio ()
+noSmooth = liftIO $ pointSmooth $= Disabled
+
+-- | Specifies the number of frames to be displayed every second. 
+-- For example, the function call frameRate(30) will attempt to 
+-- refresh 30 times a second. If the processor is not fast enough to
+-- maintain the specified rate, the frame rate will not be achieved. 
+-- Setting the frame rate within setup() is recommended. 
+-- The default rate is 60 frames per second. 
+--
+-- processing docs: <https://processing.org/reference/frameRate_.html>
+frameRate :: Float -> Pio ()
+frameRate = putFrameRate
+
+
+-- | Executes the code within draw() one time. This functions allows the program 
+-- to update the display window only when necessary, for example when an event 
+-- registered by mousePressed() or keyPressed() occurs.
+--
+-- In structuring a program, it only makes sense to call redraw() within events 
+-- such as mousePressed(). This is because redraw() does not run draw() immediately 
+-- (it only sets a flag that indicates an update is needed). 
+--
+-- processing docs: <https://processing.org/reference/redraw_.html>
+redraw :: Draw
+redraw = putLoopMode Redraw
+
+-- | By default, Processing loops through draw() continuously, executing the code 
+-- within it. However, the draw() loop may be stopped by calling noLoop(). 
+-- In that case, the draw() loop can be resumed with loop().
+-- 
+-- processing docs: <https://processing.org/reference/loop_.html>
+loop :: Draw
+loop = putLoopMode Loop
+
+-- | Stops Processing from continuously executing the code within draw(). 
+-- If loop() is called, the code in draw() begins to run continuously again. 
+-- If using noLoop() in setup(), it should be the last line inside the block.
+--
+-- processing docs: <https://processing.org/reference/noLoop_.html>
+noLoop :: Draw
+noLoop = putLoopMode NoLoop
+ src/Graphics/Proc/Lib/Image.hs view
@@ -0,0 +1,2 @@+module Graphics.Proc.Lib.Image(
+) where
+ src/Graphics/Proc/Lib/Input.hs view
@@ -0,0 +1,9 @@+module Graphics.Proc.Lib.Input(
+	module Graphics.Proc.Lib.Input.Mouse,
+	module Graphics.Proc.Lib.Input.Keyboard,
+	module Graphics.Proc.Lib.Input.Time
+) where
+
+import Graphics.Proc.Lib.Input.Mouse
+import Graphics.Proc.Lib.Input.Keyboard
+import Graphics.Proc.Lib.Input.Time
+ src/Graphics/Proc/Lib/Input/Keyboard.hs view
@@ -0,0 +1,15 @@+module Graphics.Proc.Lib.Input.Keyboard(
+	key, modifiers
+) where
+
+import Graphics.Proc.Core	
+
+-- | Returns last pressed key.
+--
+-- processing docs: <https://processing.org/reference/key.html>
+key :: Pio Key
+key = getLastPressedKey
+
+-- | Returns last pressed key modifier.
+modifiers :: Pio Modifiers
+modifiers = getPressedModifiers
+ src/Graphics/Proc/Lib/Input/Mouse.hs view
@@ -0,0 +1,45 @@+module Graphics.Proc.Lib.Input.Mouse(
+	mouse, mouseX, mouseY, 
+	relMouse, relMouseX, relMouseY,
+	mouseButton
+) where
+
+import Graphics.Proc.Core
+import Graphics.Proc.Lib.Environment
+
+-- | Contains coordinates of the mouse as a vector.
+mouse :: Pio P2
+mouse = getMousePosition
+
+-- | The system variable mouseX always contains the current horizontal coordinate of the mouse. 
+--
+-- processing docs: <https://processing.org/reference/mouseX.html>
+mouseX :: Pio Float
+mouseX = fmap fst mouse
+
+-- | The system variable mouseX always contains the current vertical coordinate of the mouse. 
+--
+-- processing docs: <https://processing.org/reference/mouseY.html>
+mouseY :: Pio Float
+mouseY = fmap snd mouse
+
+relMouseX, relMouseY :: Pio Float 
+
+-- | Contains relative @mouseX@ coordinates of the mouse (scaled to the interval [0, 1]).
+relMouseX = do
+  mx <- mouseX
+  w  <- winWidth
+  return $ mx / w
+
+-- | Contains relative @mouseY@ coordinates of the mouse (scaled to the interval [0, 1]).
+relMouseY = do
+  my <- mouseY
+  h  <- winHeight
+  return $ my / h
+
+-- | Contains relative coordinates of the mouse as a vector.
+relMouse :: Pio P2
+relMouse = liftA2 (,) relMouseX relMouseY
+
+mouseButton :: Pio (Maybe MouseButton)
+mouseButton = getMouseButton
+ src/Graphics/Proc/Lib/Input/Time.hs view
@@ -0,0 +1,75 @@+module Graphics.Proc.Lib.Input.Time(
+	year, month, day, utcHour, hour, minute, second, millis	
+) where
+
+import Control.Monad.Trans.State.Strict
+import Data.Time.Clock
+import Data.Time.LocalTime
+import Data.Time.Calendar
+
+import Graphics.Proc.Core
+
+import Data.Fixed
+
+date :: IO (Integer,Int,Int) -- :: (year,month,day)
+date = getCurrentTime >>= return . toGregorian . utctDay
+
+-- | The year() function returns the current year as an integer (2003, 2004, 2005, etc). 
+--
+-- processing docs: <https://processing.org/reference/year_.html>
+year :: Pio Int
+year = liftIO $ fmap (\(y, _, _) -> fromInteger y) date
+
+-- | The month() function returns the current month as a value from 1 - 12. 
+--
+-- processing docs: <https://processing.org/reference/month_.html>
+month :: Pio Int
+month = liftIO $ fmap (\(_, m, _) -> m) date
+
+-- | The day() function returns the current day as a value from 1 - 31. 
+--
+-- processing docs: <https://processing.org/reference/day_.html>
+day :: Pio Int
+day = liftIO $ fmap (\(_, _, d) -> d) date
+
+-- getTime = liftIO $ fmap (\(UTCTime _ time) -> time) getCurrentTime
+getTime = liftIO $ do
+  fmap (localTimeOfDay  . zonedTimeToLocalTime) getZonedTime  
+
+getUtcTime = liftIO $ fmap utctDayTime getCurrentTime
+
+-- | Returens univeral hour.
+utcHour :: Pio Int
+utcHour = fmap toHour getUtcTime
+  where
+    toHour x = (floor x) `div` (60 * 60)  
+
+-- | The hour() function returns the current hour as a value from 0 - 23. 
+--
+-- processing docs: <https://processing.org/reference/hour_.html>
+hour :: Pio Int
+hour = fmap todHour getTime
+
+-- |  The minute() function returns the current minute as a value from 0 - 59. 
+--
+-- processing docs: <https://processing.org/reference/minute_.html>
+minute :: Pio Int
+minute = fmap todMin getTime
+
+-- | The second() function returns the current second as a value from 0 - 59. 
+-- 
+-- processing docs: <https://processing.org/reference/second_.html>
+second :: Pio Int
+second = liftIO $ fmap toSecond $ getCurrentTime >>= return . fromRational . toRational . utctDayTime
+  where 
+    toSecond x = (floor x) `mod` 60
+
+-- | Returns the number of milliseconds (thousandths of a second) since starting the program. This information is often used for timing events and animation sequences. 
+--
+--  processing docs: <https://processing.org/reference/millis_.html>
+millis :: Pio Int 
+millis = do
+  start <- getStartTime
+  now   <- liftIO $ getCurrentTime
+  return $ floor $ (* 1000) $ diffUTCTime now start
+
+ src/Graphics/Proc/Lib/Lights.hs view
@@ -0,0 +1,2 @@+module Graphics.Proc.Lib.Lights(
+) where
+ src/Graphics/Proc/Lib/Math.hs view
@@ -0,0 +1,10 @@+module Graphics.Proc.Lib.Math(
+	module Graphics.Proc.Lib.Math.Random,
+	module Graphics.Proc.Lib.Math.Calculation,
+	module Graphics.Proc.Lib.Math.Trigonometry
+) where
+
+import Graphics.Proc.Lib.Math.Random
+import Graphics.Proc.Lib.Math.Calculation
+import Graphics.Proc.Lib.Math.Trigonometry
+
+ src/Graphics/Proc/Lib/Math/Calculation.hs view
@@ -0,0 +1,24 @@+module Graphics.Proc.Lib.Math.Calculation(	
+	remap, FloatInterval, constrain, constrain2
+) where
+
+import Graphics.Proc.Core
+
+-- | Interval for float value @(minValue, maxValue)@. 
+type FloatInterval = (Float, Float)
+
+-- | Re-maps a number from one range to another. Originally called map in the Processing, but in Haskell this name is already taken.
+--
+-- processing docs: <https://processing.org/reference/map_.html>
+remap :: FloatInterval -> FloatInterval -> Float -> Float
+remap (a, b) (a1, b1) x =  a1 + (b1 - a1) * (x - a) / (b - a)	
+
+-- | The @constrian@ that is defined on vectors.
+constrain2 :: (P2, P2) -> P2 -> P2
+constrain2 ((xmin, ymin), (xmax, ymax)) (x, y) = (constrain (xmin, xmax) x, constrain (ymin, ymax) y)
+
+-- | Constrains a value to not exceed a maximum and minimum value. 
+--
+-- processing docs: <https://processing.org/reference/constrain_.html>
+constrain :: (Float, Float) -> Float -> Float
+constrain (xmin, xmax) x = min xmax (max xmin x)
+ src/Graphics/Proc/Lib/Math/Random.hs view
@@ -0,0 +1,135 @@+module Graphics.Proc.Lib.Math.Random(	
+	randomSeed, random, random2, randomP2, randomCol, randomCola,
+  -- * Perlin noise
+  -- | Returns the Perlin noise value at specified coordinates. Perlin noise is a random sequence generator producing a more natural, harmonic succession of numbers than that of the standard random() function. It was developed by Ken Perlin in the 1980s and has been used in graphical applications to generate procedural textures, shapes, terrains, and other seemingly organic forms.
+  --
+  -- processing docs: <https://processing.org/reference/noise_.html>
+	NoiseDetail(..), noiseDetail, noiseOctaves, noiseSeed, 
+  noise1, noise2, noise3,
+	randomGaussian
+) where
+
+import qualified Control.Arrow as Arr(first, second)
+import qualified Control.Monad.Trans.State.Strict as S
+
+import GHC.Float
+
+import qualified System.Random as S
+import System.Random hiding (random)
+import qualified Numeric.Noise.Perlin as Perlin
+import qualified Numeric.Noise as Perlin
+
+import Graphics.Proc.Core
+import Graphics.Proc.Lib.Environment
+
+onRandom :: (Maybe StdGen -> IO (a, Maybe StdGen)) -> Pio a
+onRandom f = do
+  gen <- getRandomGen
+  (res, gen1) <- liftIO $ f gen
+  putRandomGen gen1
+  return res
+
+onNoise :: (NoiseDetail -> Maybe Perlin.Seed -> IO (a, Maybe Perlin.Seed)) -> Pio a
+onNoise f = do
+  noiseDetail <- getNoiseDetail
+  gen <- getNoiseGen  
+  (res, gen1) <- liftIO $ f noiseDetail gen
+  putNoiseGen gen1  
+  return res
+
+-- | Sets the seed value for random(). By default, random() produces different results each time the program is run. Set the seed parameter to a constant to return the same pseudo-random numbers each time the software is run. 
+--
+-- processing docs: <https://processing.org/reference/randomSeed_.html>
+randomSeed :: Int -> Pio ()
+randomSeed n = onRandom $ const $ return ((), Just (mkStdGen n))
+
+-- | Generates random numbers. Each time the random() function is called, it returns an unexpected value within the specified range. If only one parameter is passed to the function, it will return a float between zero and the value of the high parameter. For example, random(5) returns values between 0 and 5 (starting at zero, and up to, but not including, 5).
+--
+-- processing docs: <https://processing.org/reference/random_.html>
+random :: Float -> Pio Float
+random maxVal= random2 (0, maxVal)
+
+-- | Genrates random numbers within the given range.
+random2 :: (Float, Float) -> Pio Float
+random2 (minVal, maxVal) = onRandom $ \mg -> 
+  case mg of 
+    Just g  -> return $ Arr.second Just $ randomR (minVal, maxVal) g
+    Nothing -> do
+      res <- randomRIO (minVal, maxVal)
+      return (res, Nothing)
+
+-- | Creates random point within the ranges of the size of the screen.
+randomP2 :: Pio P2
+randomP2 = do
+  x <- random =<< winWidth
+  y <- random =<< winHeight
+  return (x, y)
+
+-- | Creates random color.
+randomCol :: Pio Col
+randomCol = liftA3 (\r g b -> Col r g b 1) (random 1) (random 1) (random 1)
+
+-- | Creates random color with transparency.
+randomCola :: Pio Col
+randomCola = liftA4 Col (random 1) (random 1) (random 1) (random 1)
+  where liftA4 f a b c d = f <$> a <*> b <*> c <*> d
+
+-- | Returns a float from a random series of numbers having a mean of 0 and standard deviation of 1. Each time the randomGaussian() function is called, it returns a number fitting a Gaussian, or normal, distribution. There is theoretically no minimum or maximum value that randomGaussian() might return. Rather, there is just a very low probability that values far from the mean will be returned; and a higher probability that numbers near the mean will be returned.
+--
+-- processing docs: <https://processing.org/reference/randomGaussian_.html>
+randomGaussian :: Pio Float
+randomGaussian = do
+  r1 <- random 1
+  r2 <- random 1
+  return $ boxMuller 0 1 (r1, r2)
+
+-- | BoxMuller algorythm for creation of Gaussian random values out of two uniform number r1, r2.
+-- r1, r2 should belong to the interval [0, 1]
+boxMuller :: Floating a => a -> a -> (a, a) -> a
+boxMuller mu sigma (r1,r2) =  mu + sigma * sqrt (-2 * log r1) * cos (2 * pi * r2)
+
+-- | Sets the seed value for noise(). By default, noise() produces different results each time the program is run. Set the seed parameter to a constant to return the same pseudo-random numbers each time the software is run. 
+--
+-- processing docs: <https://processing.org/reference/noiseSeed_.html>
+noiseSeed :: Int -> Pio ()
+noiseSeed n = onNoise $ const $ const $ return ((), Just n)
+
+-- | Sets the number of octaves for perlin noise.
+noiseOctaves :: Int -> Pio ()
+noiseOctaves octaves = putOctaves octaves
+
+-- | Adjusts the character and level of detail produced by the Perlin noise function. Similar to harmonics in physics, noise is computed over several octaves. Lower octaves contribute more to the output signal and as such define the overal intensity of the noise, whereas higher octaves create finer-grained details in the noise sequence.
+-- 
+-- By default, noise is computed over 4 octaves with each octave contributing exactly half than its predecessor, starting at 50% strength for the first octave. This falloff amount can be changed by adding an additional function parameter. For example, a falloff factor of 0.75 means each octave will now have 75% impact (25% less) of the previous lower octave. While any number between 0.0 and 1.0 is valid, note that values greater than 0.5 may result in noise() returning values greater than 1.0.
+-- 
+-- By changing these parameters, the signal created by the noise() function can be adapted to fit very specific needs and characteristics. 
+-- 
+-- processing docs: <https://processing.org/reference/noiseDetail_.html>
+noiseDetail :: Int -> Float -> Pio ()
+noiseDetail octaves fallOff = putNoiseDetail $ NoiseDetail octaves fallOff
+
+-- | Returns 1D Perlin noise.
+noise1 :: Float -> Pio Float
+noise1 x = noise3 (x, 0, 0)
+
+-- | Returns 2D Perlin noise.
+noise2 :: P2 -> Pio Float
+noise2 (x, y) = noise3 (x, y, 0) 
+
+-- | Returns 3D Perlin noise.
+noise3 :: P3 -> Pio Float
+noise3 p = onNoise $ \details mseed -> case mseed of
+  Just g  -> return $ (noiseValue g details p, mseed)
+  Nothing -> do
+    seed <- randomIO 
+    return $ (noiseValue seed details p, mseed)
+  where
+    noiseValue seed (NoiseDetail octaves fallOff) p = 
+      double2Float $ rescale $ Perlin.noiseValue (Perlin.perlin seed octaves scale persistance) (toDoublePoint p)
+      where
+        scale = 1
+        persistance = f2d fallOff    
+        toDoublePoint (x, y, z) = (f2d x, f2d y, f2d z)
+
+        -- from [-1,1] to [0,1]
+        rescale x = 0.5 * (x + 1)
+ src/Graphics/Proc/Lib/Math/Trigonometry.hs view
@@ -0,0 +1,23 @@+-- | We can use all functions defined in Haskell
+module Graphics.Proc.Lib.Math.Trigonometry(	
+	radians, degrees, e, erad
+) where
+
+import Graphics.Proc.Core
+import Graphics.Proc.Lib.Math.Calculation
+
+-- | Converts degrees to radians.
+radians :: Float -> Float
+radians = remap (0, 360) (0, 2 * pi)
+
+-- | Converts rdians to degrees.
+degrees :: Float -> Float
+degrees = remap (0, 2 * pi) (0, 360)
+
+-- | Converts angle in taus to unit vector rotated by given angle.
+e :: Float -> P2
+e x = (cos (2 * pi * x), sin (2 * pi * x))
+
+-- | The function e in radians.
+erad :: Float -> P2
+erad x = (cos x, sin x)
+ src/Graphics/Proc/Lib/Misc.hs view
@@ -0,0 +1,21 @@+module Graphics.Proc.Lib.Misc(
+    onCircle, onLine, uon
+) where
+
+import Graphics.Proc.Core
+
+-- | Maps values from interval (0, 1) to the points on the circle.
+--
+-- > onCircle radius center value
+onCircle :: Float -> P2 -> Float -> P2
+onCircle rad center x = center + rad *^ (cos (2 * pi * x), sin (2 * pi * x)) 
+
+-- | Maps values from interval (0, 1) to the points on the line segment.
+-- 
+-- > onLine point1 point2 value
+onLine :: P2 -> P2 -> Float -> P2
+onLine p1 p2 x = p1 + x *^ (p2 - p1)
+
+-- | Rescales the unipolar scale (0, 1) to the given range.
+uon :: (Float, Float) -> Float -> Float
+uon (a, b) x = a + (b - a) * x
+ src/Graphics/Proc/Lib/Output.hs view
@@ -0,0 +1,5 @@+module Graphics.Proc.Lib.Output(
+	module Graphics.Proc.Lib.Output.TextArea
+) where
+
+import Graphics.Proc.Lib.Output.TextArea
+ src/Graphics/Proc/Lib/Output/TextArea.hs view
@@ -0,0 +1,9 @@+module Graphics.Proc.Lib.Output.TextArea(
+	println
+) where
+
+import Graphics.Proc.Core
+
+-- | Prints values on the console.
+println :: Show a => a -> Pio ()
+println = liftIO . print
+ src/Graphics/Proc/Lib/Shape.hs view
@@ -0,0 +1,9 @@+module Graphics.Proc.Lib.Shape(
+	module Graphics.Proc.Lib.Shape.Primitive2D,
+	module Graphics.Proc.Lib.Shape.Curve,
+	module Graphics.Proc.Lib.Shape.Attribute
+) where
+
+import Graphics.Proc.Lib.Shape.Primitive2D
+import Graphics.Proc.Lib.Shape.Curve
+import Graphics.Proc.Lib.Shape.Attribute
+ src/Graphics/Proc/Lib/Shape/Attribute.hs view
@@ -0,0 +1,43 @@+module Graphics.Proc.Lib.Shape.Attribute(
+	EllipseMode(..), ellipseMode, rectMode,
+	strokeWeight
+) where
+
+import Control.Monad.Trans.State.Strict
+import Graphics.Rendering.OpenGL
+
+import Graphics.Proc.Core
+
+-- | Modifies the location from which ellipses are drawn by changing the way in which parameters given to ellipse() are intepreted.
+-- 
+-- The default mode is @ellipseMode Center@, which interprets the first two parameters of ellipse() as the shape's center point, while the third and fourth parameters are its width and height.
+-- 
+-- @ellipseMode Radius@ also uses the first two parameters of ellipse() as the shape's center point, but uses the third and fourth parameters to specify half of the shapes's width and height.
+-- 
+-- @ellipseMode Corner@ interprets the first two parameters of ellipse() as the upper-left corner of the shape, while the third and fourth parameters are its width and height.
+-- 
+-- @ellipseMode Corners@ interprets the first two parameters of ellipse() as the location of one corner of the ellipse's bounding box, and the third and fourth parameters as the location of the opposite corner.
+ellipseMode :: EllipseMode -> Draw
+ellipseMode = putEllipseMode
+
+-- | Modifies the location from which rectangles are drawn by changing the way in which parameters given to rect() are intepreted.
+-- 
+-- The default mode is @rectMode Corner@, which interprets the first two parameters of rect() as the upper-left corner of the shape, while the third and fourth parameters are its width and height.
+-- 
+-- @rectMode Corners@ interprets the first two parameters of rect() as the location of one corner, and the third and fourth parameters as the location of the opposite corner.
+-- 
+-- @rectMode Center@ interprets the first two parameters of rect() as the shape's center point, while the third and fourth parameters are its width and height.
+--
+-- @rectMode Radius@ also uses the first two parameters of rect() as the shape's center point, but uses the third and fourth parameters to specify half of the shapes's width and height.
+--
+-- processing docs: <https://processing.org/reference/rectMode_.html>
+rectMode :: RectMode -> Draw
+rectMode = putRectMode
+
+-- | Sets the width of the stroke used for lines, points, and the border around shapes. All widths are set in units of pixels. 
+--
+-- processing docs: <https://processing.org/reference/strokeWelight_.html>
+strokeWeight :: Float -> Draw
+strokeWeight x = liftIO $ lineWidth $= x
+
+
+ src/Graphics/Proc/Lib/Shape/Curve.hs view
@@ -0,0 +1,21 @@+module Graphics.Proc.Lib.Shape.Curve(
+	bezier	
+) where
+
+import Graphics.Proc.Core
+import Graphics.Proc.Lib.Shape.Primitive2D
+
+bezierPointsNum = 35
+
+-- | Draws a Bezier curve on the screen. These curves are defined by a series 
+-- of anchor and control points. The first two parameters specify the first 
+-- anchor point and the last two parameters specify the other anchor point. 
+-- The middle parameters specify the control points which define the shape of the curve. 
+-- Bezier curves were developed by French engineer Pierre Bezier. 
+--
+-- processing docs: <https://processing.org/reference/bezier_.html>
+bezier :: P2 -> P2 -> P2 -> P2 -> Draw
+bezier p1 p2 p3 p4 = linePath (map phi ts)
+    where
+        ts = [0, 1 / bezierPointsNum .. 1]
+        phi t = ((1 - t) ** 3) *^ p1 + (3 * t * ((1 - t) ** 2)) *^ p2 + (3 * (t ** 2) * (1 - t)) *^ p3 + (t ** 3) *^ p4
+ src/Graphics/Proc/Lib/Shape/Primitive2D.hs view
@@ -0,0 +1,163 @@+module Graphics.Proc.Lib.Shape.Primitive2D(	
+	triangle, rect, quad, ellipse, 
+	circle, line, linePath,
+	point, pointPath, polygon,
+) where
+
+import Control.Monad.Trans.State.Strict
+import Graphics.Proc.Core
+import Graphics.Rendering.OpenGL hiding (get, rect)
+
+-- | A triangle is a plane created by connecting three points. 
+--
+-- processing docs: <https://processing.org/reference/triangle_.html>
+triangle :: P2 -> P2 -> P2 -> Draw
+triangle p1 p2 p3 = drawProcP2 (Triangles, LineLoop) [p1, p2, p3]    
+
+-- | Draws a rectangle to the screen. A rectangle is a four-sided shape 
+-- with every angle at ninety degrees. By default, the first two parameters 
+-- set the location of the upper-left corner, the third sets the width, 
+-- and the fourth sets the height. The way these parameters are interpreted, 
+-- however, may be changed with the rectMode() function.
+--
+-- processing docs: <https://processing.org/reference/rect_.html>
+rect :: P2 -> P2 -> Draw
+rect a b = uncurry cornerRect =<< fmap (\mode -> modeRectPoints mode a b) getRectMode
+
+cornerRect :: P2 -> P2 -> Draw
+cornerRect (x, y) (w, h) = drawProcP2 (Polygon, LineLoop) [(x, y), (x, y + h), (x + w, y + h), (x + w, y)]
+
+modeRectPoints mode (a, b) (c, d) = case mode of
+  Corner  -> ((a, b), (c, d))
+  Corners -> ((a, b), (c - a, d - b))
+  Radius  -> 
+      let rx = c
+          ry = d
+          cx = a
+          cy = b
+      in ((cx - rx, cy - ry), (2 * rx, 2 * ry))
+  Center ->
+      let dx = c
+          dy = d
+          rx = dx / 2
+          ry = dy / 2
+          cx = a
+          cy = b
+      in ((cx - rx, cy - ry), (dx, dy))
+
+-- | A quad is a quadrilateral, a four sided polygon. It is similar to a rectangle,
+-- but the angles between its edges are not constrained to ninety degrees. The first 
+-- pair of parameters (x1,y1) sets the first vertex and the subsequent pairs should 
+-- proceed clockwise or counter-clockwise around the defined shape. 
+-- 
+-- processing docs: <https://processing.org/reference/quad_.html>
+quad :: P2 -> P2 -> P2 -> P2 -> Draw
+quad p1 p2 p3 p4 = drawProcP2 (Polygon, LineLoop) [p1, p2, p3, p4]
+
+-- | Draws a polygon.
+polygon :: [P2] -> Draw
+polygon ps = drawProcP2 (Polygon, LineLoop) ps
+
+-- | Draws a point, a coordinate in space at the dimension of one pixel. 
+--
+-- processing docs: <https://processing.org/reference/point_.html>
+point :: P2 -> Draw
+point p = do
+  setStrokeColor
+  drawP2 Points [p]
+
+-- | Draws a sequence of points.
+pointPath :: [P2] -> Draw
+pointPath ps = do
+  setStrokeColor
+  drawP2 Points ps
+
+setStrokeColor :: Pio ()
+setStrokeColor = setCol . maybe black id =<< getStroke
+
+black = Col 0 0 0 1  
+
+-- | Draws a line (a direct path between two points) to the screen.
+--
+-- processing docs: <https://processing.org/reference/line_.html>
+line :: P2 -> P2 -> Draw
+line p1 p2 = do
+  setStrokeColor
+  drawP2 Lines [p1, p2]
+
+-- | Draws a line-path (sequence of line segments).
+linePath :: [P2] -> Draw
+linePath ps = do
+  setStrokeColor
+  drawP2 LineStrip ps
+
+-- | Draws an ellipse (oval) to the screen. An ellipse with equal 
+-- width and height is a circle. By default, the first two parameters 
+-- set the location, and the third and fourth parameters set the shape's 
+-- width and height. The origin may be changed with the @ellipseMode()@ function. 
+-- 
+-- processing docs: <https://processing.org/reference/ellipse_.html>
+ellipse :: P2 -> P2 -> Draw
+ellipse center rad = do
+  mode <- getEllipseMode
+  drawProcP2 (Polygon, LineLoop) (modeEllipsePoints mode 150 rad center) 
+
+-- | Draws a circle with a given radius and center.
+--
+-- > circle radius center
+circle :: Float -> P2 -> Draw
+circle rad center = drawProcP2 (Polygon, LineLoop) (modeEllipsePoints Radius 150 (rad, rad) center) 
+
+modeEllipsePoints mode number (a, b) (c, d) = (uncurry $ ellipsePoints number) $ case mode of
+  Center  -> 
+    let width = a
+        height = b
+        cx = c
+        cy = d
+    in ((width / 2, height / 2), (cx, cy))
+  Radius  ->
+    let radx = a
+        rady = b
+        cx = c
+        cy = d
+    in ((radx, rady), (cx, cy))
+  Corner  -> 
+    let width = a
+        height = b
+        px = c
+        py = d
+        rx = width / 2
+        ry = width / 2
+    in ((rx, ry), (px + rx, py + ry))
+  Corners ->
+    let p1x = a
+        p1y = b
+        p2x = c
+        p2y = d
+    in ((abs (p1x - p2x) / 2, abs (p1y - p2y) / 2), ((p1x + p2x) / 2, (p1y + p2y) / 2))
+
+ellipsePoints number (radx, rady) (cx, cy) = 
+    [ let alpha = twoPi * i /number
+      in (cx + radx * (cos (alpha)), cy + rady * (sin (alpha)))
+    | i <- [1,2..number]]
+    where
+        twoPi = 2*pi
+
+
+---------------------------------------------------
+
+drawP2 primType ps = do   
+  liftIO $ renderPrimitive primType $ mapM_ v2 ps
+
+drawProcP2 (onFill, onStroke) ps = do    
+    go onFill   =<< getFill    
+    go onStroke =<< getStroke
+    where        
+        go shapeType mcol = case mcol of
+          Just col -> do            
+            setCol col
+            drawP2 shapeType ps
+          Nothing -> return ()
+
+setCol :: Col -> Draw
+setCol col = liftIO $ currentColor $= glCol col
+ src/Graphics/Proc/Lib/Transform.hs view
@@ -0,0 +1,106 @@+module Graphics.Proc.Lib.Transform(
+	translate, 
+	rotate, rotateX, rotateY, rotateZ, 
+	scale, 
+	resetMatrix, 
+	local, 
+	applyMatrix, 
+	shearX, shearY
+) where
+
+import Control.Monad.Trans.State.Strict	
+
+import Graphics.Rendering.OpenGL hiding (scale, translate, rotate)
+import qualified Graphics.Rendering.OpenGL as G
+
+import Graphics.Proc.Core
+
+-- | Specifies an amount to displace objects within the display window. The x parameter specifies left/right translation, the y parameter specifies up/down translation
+--
+-- processing docs: <https://processing.org/reference/translate_.html>
+translate :: P2 -> Draw 
+translate p = liftIO $ G.translate $ p2v p
+
+-- | Rotates around given 3D vector.
+rotateBy :: Vector3 GLfloat -> Float -> Draw
+rotateBy v x = liftIO $ G.rotate (x * 360) v 
+
+-- | Rotates the amount specified by the angle parameter. Angles must be specified in taus (values from 0 to 1)
+--
+-- processing docs: <https://processing.org/reference/rotate_.html>
+rotate :: Float -> Draw
+rotate = rotateZ
+
+-- | Rotates around X-axis.
+rotateX :: Float -> Draw
+rotateX = rotateBy $ Vector3 (1 :: GLfloat) 0 0
+
+-- | Rotates around Y-axis.
+rotateY :: Float -> Draw
+rotateY = rotateBy $ Vector3 0 (1 :: GLfloat) 0
+
+-- | Rotates around Z-axis.
+rotateZ :: Float -> Draw
+rotateZ = rotateBy $ Vector3 0 0 (1 :: GLfloat)
+
+-- | Increases or decreases the size of a shape by expanding and contracting vertices. Objects always scale from their relative origin to the coordinate system. Scale values are specified as decimal percentages. For example, the function call scale(2.0) increases the dimension of a shape by 200%.
+--
+-- processing docs: <https://processing.org/reference/scale_.html>
+scale :: P2 -> Draw
+scale (x, y) = liftIO $ G.scale x y 1
+
+-- | Replaces the current matrix with the identity matrix. The equivalent function in OpenGL is glLoadIdentity(). 
+--
+-- processing docs: <https://processing.org/reference/resetMatrix_.html>
+resetMatrix :: Draw
+resetMatrix = liftIO $ loadIdentity
+
+-- | Applies local transformation. Substitutes the pair of pushMatrix and popMatrix.
+-- It can be used like this:
+--
+-- > local $ do
+-- >   rotate angle
+-- >   translate p1
+-- >   drawShape params
+-- 
+-- see <https://processing.org/reference/pushMatrix_.html> and <https://processing.org/reference/popMatrix_.html>
+local :: Draw -> Draw
+local (Pio a) = Pio $ StateT $ \s -> do
+    preservingMatrix $ do
+        runStateT a s
+
+-- | Multiplies the current matrix by the one specified through the parameters. This is very slow because it will try to calculate the inverse of the transform, so avoid it whenever possible. The equivalent function in OpenGL is glMultMatrix(). 
+--
+-- processing docs: <https://processing.org/reference/applyMatrix_.html> 
+applyMatrix :: [Float] -> Draw
+applyMatrix as@[a11, a12, a21, a22] = 
+    applyMatrix 
+        [ a11, a12,   0, 0
+        , a21, a22,   0, 0
+        ,   0,   0,   1, 0
+        ,   0,   0,   0, 1]
+applyMatrix as@[a11, a12, a13, a21, a22, a23, a31, a32, a33] = 
+    applyMatrix 
+        [ a11, a12, a13, 0
+        , a21, a22, a23, 0
+        , a31, a32, a33, 0
+        ,   0,   0,   0, 1]
+applyMatrix as@[a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44] = liftIO $ do
+    m <- newMatrix RowMajor (fmap f2d as)
+    multMatrix (m :: GLmatrix GLdouble)
+applyMatrix _ = error "Wrong matrix size. The list should contain 4, 9 or 16 elements"
+
+-- | Shears a shape around the x-axis the amount specified by the angle parameter. A
+--
+-- processing docs: <https://processing.org/reference/shearX_.html>
+shearX :: Float -> Draw
+shearX x = applyMatrix [1, x, 0, 1]
+
+-- | Shears a shape around the y-axis the amount specified by the angle parameter. A
+-- 
+-- processing docs: <https://processing.org/reference/shearY_.html>
+shearY :: Float -> Draw
+shearY x = applyMatrix [1, 0, x, 1]
+
+printMatrix :: Draw
+printMatrix = undefined	
+ src/Graphics/Proc/Lib/Typography.hs view
@@ -0,0 +1,9 @@+module Graphics.Proc.Lib.Typography(
+	module Graphics.Proc.Lib.Typography.Display,
+	module Graphics.Proc.Lib.Typography.Attributes,
+	module Graphics.Proc.Lib.Typography.Metrics
+) where
+
+import Graphics.Proc.Lib.Typography.Display
+import Graphics.Proc.Lib.Typography.Attributes
+import Graphics.Proc.Lib.Typography.Metrics
+ src/Graphics/Proc/Lib/Typography/Attributes.hs view
@@ -0,0 +1,24 @@+module Graphics.Proc.Lib.Typography.Attributes(
+--	textSize
+) where
+
+{-
+import Graphics.Rendering.FTGL
+import Graphics.Proc.Core
+
+import Graphics.Proc.Lib.Typography.Display
+
+textSize :: Int -> Pio ()
+textSize size = onFont $ \font -> setFontSize font size
+
+
+-- consider using these types for alignment
+data TextAlignX = AlignLeft | AlignRight | AlignCenterX
+data TextAlignY = AlignTop | AlignBottom | AlignCenterY | AlignBaseline
+
+textAlignX :: TextAlignX -> Draw
+textAlignX tx = undefined
+
+textAlign :: TextAlignX -> TextAlignY -> Draw
+textAlign tx ty = undefined
+-}
+ src/Graphics/Proc/Lib/Typography/Display.hs view
@@ -0,0 +1,57 @@+module Graphics.Proc.Lib.Typography.Display(
+{-
+	loadFont, text, textFont,
+	getCurrentFont, onFont, setFontSize
+-}
+) where
+
+{-
+import Graphics.Rendering.FTGL
+import Codec.Binary.UTF8.String
+
+import Graphics.Proc.Core
+import Graphics.Proc.Lib.Transform
+
+loadFont :: String -> Pio Font
+loadFont fontName = liftIO $ do
+	font <- createTextureFont fontName
+	fsetFontCharMap font (marshalCharMap EncodingUnicode)    
+	return font
+
+text :: String -> P2 -> Pio ()
+text str p = do
+	onFont $ \fontSpec -> 
+				local $ do				
+					translate p
+					local $ do
+						scale (fontSizeFactor fontSpec *^ (1, -1))					
+						liftIO $ renderFont (fontCurrent fontSpec) (encodeString str) Side                        
+
+fontSizeFactor fontSpec = fromIntegral (fontSize fontSpec) / fromIntegral (fontInitSize fontSpec)
+
+textFont :: Font -> Int -> Pio ()
+textFont font size = do
+    modifyStatePio $ \st -> st { globalFont = Just (FontSpec font size size) }
+    onFont $ \fontSpec -> liftIO $ do
+        _ <- setFontFaceSize (fontCurrent fontSpec) size size
+        return ()
+
+-----------------------------------------------
+-- Raw Fonts
+
+getCurrentFont :: Pio (Maybe FontSpec)
+getCurrentFont = readStatePio globalFont
+
+onFont :: (FontSpec -> Pio ()) -> Pio ()
+onFont act = do
+	mfont <- getCurrentFont
+	case mfont of
+		Just font -> act font
+		Nothing -> liftIO $ print "Font is not set"
+
+setFontSize :: FontSpec -> Int -> Pio ()
+setFontSize fontSpec size = modifyStatePio $ \st -> 
+    	let font = globalFont st
+            font' = fmap (\x -> x { fontSize = size }) font
+        in  st { globalFont = font' }
+-}
+ src/Graphics/Proc/Lib/Typography/Metrics.hs view
@@ -0,0 +1,4 @@+module Graphics.Proc.Lib.Typography.Metrics(
+) where
+
+import Graphics.Proc.Core