packages feed

Rasterific 0.7.3 → 0.7.4

raw patch · 12 files changed

+1240/−1195 lines, 12 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Graphics.Rasterific.Transformations: instance Data.Semigroup.Semigroup Graphics.Rasterific.Transformations.Transformation
+ Graphics.Rasterific: renderDrawingsAtDpiToPDF :: Int -> Int -> Dpi -> [Drawing PixelRGBA8 ()] -> ByteString
+ Graphics.Rasterific.Transformations: instance GHC.Base.Semigroup Graphics.Rasterific.Transformations.Transformation
- Graphics.Rasterific: newtype PointSize :: *
+ Graphics.Rasterific: newtype PointSize

Files

Rasterific.cabal view
@@ -1,7 +1,7 @@ -- Initial Rasterific.cabal generated by cabal init.  For further 
 -- documentation, see http://haskell.org/cabal/users-guide/
 name:                Rasterific
-version:             0.7.3
+version:             0.7.4
 synopsis:            A pure haskell drawing engine.
 -- A longer description of the package.
 description:
@@ -38,7 +38,7 @@ Source-Repository this
     Type:      git
     Location:  git://github.com/Twinside/Rasterific.git
-    Tag:       v0.7.3
+    Tag:       v0.7.4
 
 flag embed_linear
   description: Embed a reduced version of Linear avoiding a (huge) dep
changelog view
@@ -1,6 +1,13 @@ Change log
 ==========
 
+v0.7.4 August 2018
+------------------
+
+ * Fix: Rendering bug with self-closing cubic bezier curve
+ * Fix: dashed stroking of tiny features
+ * Adding: multiple page pdf rendering (jprider63)
+
 v0.7.3
 ------
 
− docimages/linear_gradient_rotated.png

binary file changed (5693 → absent bytes)

docimages/sampled_texture_reflect.png view

binary file changed (64929 → 64849 bytes)

docimages/strokize_dashed_path.png view

binary file changed (10031 → 10032 bytes)

src/Graphics/Rasterific.hs view
@@ -68,6 +68,7 @@     , renderDrawing
     , renderDrawingAtDpi
     , renderDrawingAtDpiToPDF
+    , renderDrawingsAtDpiToPDF
     , renderOrdersAtDpiToPdf 
     , pathToPrimitives
 
@@ -439,8 +440,16 @@     -> Dpi -- ^ Current DPI used for text rendering.
     -> Drawing PixelRGBA8 () -- ^ Rendering action
     -> LB.ByteString
-renderDrawingAtDpiToPDF w h dpi =
-  renderDrawingToPdf renderer w h dpi
+renderDrawingAtDpiToPDF w h dpi d = renderDrawingsAtDpiToPDF w h dpi [d]
+
+renderDrawingsAtDpiToPDF
+    :: Int -- ^ Rendering width
+    -> Int -- ^ Rendering height
+    -> Dpi -- ^ Current DPI used for text rendering.
+    -> [Drawing PixelRGBA8 ()] -- ^ Rendering actions
+    -> LB.ByteString
+renderDrawingsAtDpiToPDF w h dpi =
+  renderDrawingsToPdf renderer w h dpi
     where
       renderer :: forall px . RenderablePixel px => Drawing px () -> [DrawOrder px]
       renderer = drawOrdersOfDrawing w h dpi emptyPx
src/Graphics/Rasterific/CubicBezier.hs view
@@ -270,6 +270,11 @@     abbcbccd = lerp val bccd abbc
 
 decomposeCubicBeziers :: CubicBezier -> Producer EdgeSample
+decomposeCubicBeziers cb@(CubicBezier a b c d)
+   -- handle case of self closed bezier curve
+  | not (a `isDistingableFrom` d) && ((a `isDistingableFrom` b) || (a `isDistingableFrom` c)) =
+    let (l, r) = cubicBezierBreakAt cb 0.5 in
+    decomposeCubicBeziers l . decomposeCubicBeziers r 
 decomposeCubicBeziers (CubicBezier (V2 aRx aRy) (V2 bRx bRy) (V2 cRx cRy) (V2 dRx dRy)) =
     go aRx aRy bRx bRy cRx cRy dRx dRy where
   go ax ay _bx _by _cx _cy dx dy cont | insideX && insideY =
src/Graphics/Rasterific/MeshPatch.hs view
@@ -1,604 +1,604 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE CPP #-}-#define SVG_2--- | Module defining the type of mesh patch grid.-module Graphics.Rasterific.MeshPatch-    ( -- * Types-      InterBezier( .. )-    , Derivatives( .. )-    , MeshPatch( .. )-    , CubicCoefficient( .. )--     -- * Functions-    , calculateMeshColorDerivative-    , verticeAt-    , generateLinearGrid-    , generateImageMesh--      -- * Extraction functions-      -- ** Simple-    , coonPatchAt-    , tensorPatchAt-    , coonImagePatchAt-    , tensorImagePatchAt-    , coonPatchAtWithDerivative-    , tensorPatchAtWithDerivative--      -- ** Multiple-    , coonPatchesOf-    , tensorPatchesOf-    , imagePatchesOf-    , tensorImagePatchesOf-    , cubicCoonPatchesOf-    , cubicTensorPatchesOf--      -- * Mutable mesh-    , MutableMesh-    , thawMesh-    , freezeMesh--     -- * Monadic mesh creation-    , withMesh-    , setVertice-    , getVertice-    , setHorizPoints-    , setVertPoints-    , setColor-    ) where--{-import Debug.Trace-}-{-import Text.Printf-}--import Data.Monoid( (<>) )-import Control.Monad.ST( runST )-import Control.Monad.Reader( runReaderT )-import Control.Monad.Reader.Class-import Control.Monad.Primitive( PrimMonad, PrimState )-import Data.Vector( (!) )-import qualified Data.Vector as V-import qualified Data.Vector.Mutable as MV-import qualified Data.Vector.Generic as VG--import Codec.Picture( Image( imageWidth, imageHeight ) )-import Graphics.Rasterific.Linear-import Graphics.Rasterific.MiniLens-import Graphics.Rasterific.Types-import Graphics.Rasterific.Compositor-import Graphics.Rasterific.Transformations-import Graphics.Rasterific.PatchTypes--#ifdef SVG_2-slopeOf :: (Additive h, Applicative h)-        => h Float -> h Float -> h Float-        -> Point -> Point -> Point-        -> h Float-slopeOf prevColor thisColor nextColor-        prevPoint thisPoint nextPoint -  | nearZero distPrev || nearZero distNext = zero-  | otherwise = slopeVal <$> slopePrev <*> slope <*> slopeNext-  where-    distPrev = thisPoint `distance` prevPoint-    distNext = thisPoint `distance` nextPoint--    slopePrev | nearZero distPrev = zero-              | otherwise = (thisColor ^-^ prevColor) ^/ distPrev-    slopeNext | nearZero distNext = zero-              | otherwise = (nextColor ^-^ thisColor) ^/ distNext-    slope = (slopePrev ^+^ slopeNext) ^* 0.5--    slopeVal :: Float -> Float -> Float -> Float-    slopeVal sp s sn-      | signum sp /= signum sn = 0-      | abs s > abs minSlope = minSlope-      | otherwise = s-      where-        minSlope-          | abs sp < abs sn = 3 * sp-          | otherwise = 3 * sn-#else-slopeBasic :: (Additive h)-           => h Float -> h Float-           -> Point -> Point-           -> h Float-slopeBasic prevColor nextColor prevPoint nextPoint -  | nearZero d = zero-  | otherwise = (nextColor ^-^ prevColor) ^/ d-  where-    d = prevPoint `distance` nextPoint-#endif---- | Prepare a gradient mesh to use cubic color interpolation, see--- renderCubicMesh documentation to see the global use of this function.-calculateMeshColorDerivative :: forall px. (InterpolablePixel px)-                             => MeshPatch px -> MeshPatch (Derivative px)-calculateMeshColorDerivative mesh = mesh { _meshColors = withEdgesDerivatives } where-  withEdgesDerivatives =-     colorDerivatives V.// (topDerivative <> bottomDerivative <> leftDerivative <> rightDerivative)-  colorDerivatives =-     V.fromListN (w * h) [interiorDerivative x y | y <- [0 .. h - 1], x <- [0 .. w - 1]]--  w = _meshPatchWidth mesh + 1-  h = _meshPatchHeight mesh + 1-  clampX = max 0 . min (w - 1)-  clampY = max 0 . min (h - 1)--  rawColorAt x y =_meshColors mesh V.! (y * w + x)-  atColor x y = toFloatPixel $ rawColorAt (clampX x) (clampY y)-#ifdef SVG_2-  isOnVerticalBorder x = x == 0 || x == w - 1 -  isOnHorizontalBorder y = y == 0 || y == h - 1-#endif--  pointAt x y = verticeAt mesh (clampX x) (clampY y)-  derivAt x y = colorDerivatives  V.! (y * w + x)---  topDerivative = -    [edgeDerivative yDerivative 0 1 x 0 | x <- [1 .. w - 2]]-  bottomDerivative = -    [edgeDerivative yDerivative 0 (-1) x (h - 1) | x <- [1 .. w - 2]]-  leftDerivative =-    [edgeDerivative xDerivative 1 0 0 y | y <- [1 .. h - 2]]-  rightDerivative = -    [edgeDerivative xDerivative (-1) 0 (w - 1) y | y <- [1 .. h - 2]]--  edgeDerivative :: Lens' (Derivative px) (Holder px Float) -> Int -> Int -> Int -> Int-                 -> (Int, Derivative px)-  edgeDerivative coord dx dy x y-    | nearZero d = (ix, oldDeriv)-    | otherwise = (ix, oldDeriv & coord .~ otherDeriv)-    where-      ix = y * w + x-      oldDeriv = derivAt x y-      derivs = oldDeriv .^ coord-      otherDeriv = (c ^/ d) ^-^ derivs-      c = (atColor (x+dx) (y+dy) ^-^ atColor x y) ^* 2-      d = pointAt (x+dx) (y+dy) `distance` pointAt x y--  -- General case-  interiorDerivative x y-#ifdef SVG_2-    | isOnHorizontalBorder y && isOnVerticalBorder x = Derivative thisColor zero zero zero-    | isOnHorizontalBorder y = Derivative thisColor dx zero zero-    | isOnVerticalBorder x = Derivative thisColor zero dy zero-#endif-    | otherwise = Derivative thisColor dx dy dxy-    where-#ifdef SVG_2-      dx = slopeOf-          cxPrev thisColor cxNext-          xPrev this xNext-      -      dy = slopeOf-          cyPrev thisColor cyNext-          yPrev this yNext-          -- -}-      -      dxy = zero-#else-      dx = slopeBasic cxPrev cxNext xPrev xNext-      dy = slopeBasic cyPrev cyNext yPrev yNext--      dxy | nearZero xyDist = zero-          | otherwise = (cxyNext ^-^ cyxPrev ^-^ cyxNext ^+^ cxyPrev) ^/ (xyDist)-      xyDist = (xNext `distance` xPrev) * (yNext `distance` yPrev)--      cxyPrev = atColor (x - 1) (y - 1)-      xyPrev = pointAt (x - 1) (y - 1)--      cxyNext = atColor (x + 1) (y + 1)-      xyNext = pointAt (x + 1) (y + 1)--      cyxPrev = atColor (x - 1) (y + 1)-      yxPrev = pointAt (x - 1) (y + 1)--      cyxNext = atColor (x + 1) (y - 1)-      yxNext = pointAt (x + 1) (y - 1)-#endif--      cxPrev = atColor (x - 1) y-      thisColor = atColor x y-      cxNext = atColor (x + 1) y-      -      cyPrev = atColor x (y - 1)-      cyNext = atColor x (y + 1)-      -      xPrev = pointAt (x - 1) y-      this  = pointAt x y-      xNext = pointAt (x + 1) y-      -      yPrev = pointAt x (y - 1)-      yNext = pointAt x (y + 1)---- | Mutable version of a MeshPatch-data MutableMesh s px = MutableMesh-  { _meshMutWidth :: !Int-  , _meshMutHeight :: !Int-  , _meshMutPrimaryVertices :: !(MV.MVector s Point)-  , _meshMutHorizSecondary :: !(MV.MVector s InterBezier)-  , _meshMutVertSecondary :: !(MV.MVector s InterBezier)-  , _meshMutColors :: !(MV.MVector s px)-  , _meshMutTensorDerivatives :: !(Maybe (MV.MVector s Derivatives))-  }---- | Normal mesh to mutable mesh-thawMesh :: PrimMonad m => MeshPatch px -> m (MutableMesh (PrimState m) px)-thawMesh MeshPatch { .. } = do-  let _meshMutWidth = _meshPatchWidth-      _meshMutHeight = _meshPatchHeight-  _meshMutPrimaryVertices <- V.thaw _meshPrimaryVertices -  _meshMutHorizSecondary <- V.thaw _meshHorizontalSecondary-  _meshMutVertSecondary <- V.thaw _meshVerticalSecondary-  _meshMutColors <- V.thaw _meshColors-  _meshMutTensorDerivatives <- case _meshTensorDerivatives of-      Nothing -> return Nothing-      Just v -> Just <$> V.thaw v-  return MutableMesh { .. }---- | Mutable mesh to freezed mesh.-freezeMesh :: PrimMonad m => MutableMesh (PrimState m) px -> m (MeshPatch px)-freezeMesh MutableMesh { .. } = do-  let _meshPatchWidth = _meshMutWidth-      _meshPatchHeight = _meshMutHeight-  _meshPrimaryVertices <- V.freeze _meshMutPrimaryVertices -  _meshHorizontalSecondary <- V.freeze _meshMutHorizSecondary-  _meshVerticalSecondary <- V.freeze _meshMutVertSecondary-  _meshTensorDerivatives <- case _meshMutTensorDerivatives of-        Nothing -> return Nothing-        Just v -> Just <$> V.freeze v-  _meshColors <- V.freeze _meshMutColors-  return MeshPatch { .. }---- | Retrieve a mesh primary vertice purely-verticeAt :: MeshPatch px-          -> Int -- ^ Between 0 and _meshPatchWidth + 1 (excluded)-          -> Int -- ^ Between 0 and _meshPatchHeight + 1 (excluded)-          -> Point-verticeAt m x y = _meshPrimaryVertices m ! idx where-    idx = y * (_meshPatchWidth m + 1) + x---- | Given an original MeshPatch, provide context to mutate it through--- modification functions.-withMesh :: MeshPatch px-         -> (forall m. (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m) =>-                        m a)-         -> (a, MeshPatch px)-withMesh mesh act = runST $ do-  mut <- thawMesh  mesh-  v <- runReaderT act mut-  final <- freezeMesh mut-  return (v, final)---- | Set the vertice of a mesh at a given coordinate-setVertice :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)-           => Int   -- ^ x coordinate in [0, w]-           -> Int   -- ^ y coordinate in [0, h]-           -> Point -- ^ new point value-           -> m ()-setVertice x y p = do-  MutableMesh { .. } <- ask-  let idx = y * (_meshMutWidth + 1) + x-  MV.write _meshMutPrimaryVertices idx p---- | Get the position of vertice-getVertice :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)-           => Int -> Int -> m Point-getVertice x y = do-  p <- ask-  let idx = y * (_meshMutWidth p + 1) + x-  MV.read (_meshMutPrimaryVertices p) idx---- | Set the two control bezier points horizontally-setHorizPoints :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)-               => Int -> Int -> InterBezier -> m ()-setHorizPoints x y p = do-  MutableMesh { .. } <- ask-  let idx = y * _meshMutWidth + x-  MV.write _meshMutHorizSecondary idx p---- | Set the two control bezier points vertically-setVertPoints :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)-              => Int -> Int -> InterBezier -> m ()-setVertPoints x y p = do-  MutableMesh { .. } <- ask-  let idx = y * (_meshMutWidth + 1) + x-  MV.write _meshMutVertSecondary idx p----- | Set the value associated to a vertex-setColor :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)-         => Int -> Int -> px -> m ()-setColor x y p = do-  MutableMesh { .. } <- ask-  let idx = y * (_meshMutWidth + 1) + x-  MV.write _meshMutColors idx p---- | Generate a meshpatch at the size given by the image and--- a number of cell in a mesh-generateImageMesh :: Int      -- ^ Horizontal cell count-                  -> Int      -- ^ Vertical cell count-                  -> Point    -- ^ Position of the corner upper left-                  -> Image px -- ^ Image to transform through a mesh-                  -> MeshPatch (ImageMesh px)-generateImageMesh w h base img = generateLinearGrid w h base (V2 dx dy) infos where-  dx = fromIntegral (imageWidth img) / fromIntegral w-  dy = fromIntegral (imageHeight img) / fromIntegral h-  infos = V.fromListN ((w + 1) * (h + 1))-    [ImageMesh img $ trans <> scaling-        | y <- [0 .. h]-        , x <- [0 .. w]-        , let fx = fromIntegral x-              fy = fromIntegral y-              trans = translate (V2 (fx * dx) (fy * dy))-              scaling = scale dx dy]----- | Generate a valid gradient with the shape of a simple grid--- using some simple information. You can use `thawMesh` and `freezeMesh`--- to mutate it.-generateLinearGrid :: Int           -- ^ Width in patch-                   -> Int           -- ^ Height in patch-                   -> Point         -- ^ Position of the upper left corner-                   -> V2 Float      -- ^ Size of each patch in x adn y-                   -> V.Vector px   -- ^ Vector of values, size must be (width + 1) * (height + 1)-                   -> MeshPatch px-generateLinearGrid w h base (V2 dx dy) colors = MeshPatch-  { _meshPatchWidth = w-  , _meshPatchHeight = h-  , _meshPrimaryVertices = vertices -  , _meshHorizontalSecondary = hSecondary -  , _meshVerticalSecondary = vSecondary-  , _meshTensorDerivatives = Nothing-  , _meshColors = colors-  }-  where-    vertexCount = (w + 1) * (h + 1)-    vertices =-      V.fromListN vertexCount [base ^+^ V2 (dx * fromIntegral x) (dy * fromIntegral y)-                                        | y <- [0 .. h], x <- [0 .. w]]-    at x y = vertices ! (y * (w + 1) + x)-    hSecondary = V.fromListN ((h + 1) * w)-        [InterBezier (p0 ^+^ delta ^* (1/3)) (p0 ^+^ delta ^* (2/3))-            | y <- [0 .. h], x <- [0 .. w - 1]-            , let p0 = at x y-                  p1 = at (x + 1) y-                  delta = p1 ^-^ p0-            ]--    vSecondary = V.fromListN ((w + 1) * h)-        [InterBezier (p0 ^+^ delta ^* (1/3)) (p0 ^+^ delta ^* (2/3))-            | y <- [0 .. h - 1], x <- [0 .. w]-            , let p0 = at x y-                  p1 = at x (y + 1)-                  delta = p1 ^-^ p0-            ]--type ColorPreparator px pxt = ParametricValues px -> pxt---- | Extract a coon patch at a given position.-coonPatchAt :: MeshPatch px-            -> Int -- ^ x-            -> Int -- ^ y-            -> CoonPatch (ParametricValues px)-coonPatchAt = coonPatchAt' id---- | Extract a tensor patch at a given position-tensorPatchAt :: MeshPatch px-              -> Int -- ^ x-              -> Int -- ^ y-              -> TensorPatch (ParametricValues px)-tensorPatchAt = tensorPatchAt' id---- | Extract an image patch out of a mesh at a given position.-coonImagePatchAt :: MeshPatch (ImageMesh px)-                 -> Int -- ^ x-                 -> Int -- ^ y-                 -> CoonPatch (ImageMesh px)-coonImagePatchAt = coonPatchAt' _northValue----- | Extract a tensor image patch out of a mesh at--- a given position.-tensorImagePatchAt :: MeshPatch (ImageMesh px)-                   -> Int -- ^ x-                   -> Int -- ^ y-                   -> TensorPatch (ImageMesh px)-tensorImagePatchAt = tensorPatchAt' _northValue---- | Extract a coon patch for cubic interpolation at a given position--- see `calculateMeshColorDerivative`-coonPatchAtWithDerivative :: (InterpolablePixel px)-                          => MeshPatch (Derivative px)-                          -> Int -- ^ x-                          -> Int -- ^ y-                          -> CoonPatch (CubicCoefficient px)-coonPatchAtWithDerivative = coonPatchAt' cubicPreparator---- | Extract a tensor patch for cubic interpolation at a given position--- see `calculateMeshColorDerivative`-tensorPatchAtWithDerivative :: (InterpolablePixel px)-                            => MeshPatch (Derivative px)-                            -> Int -- ^ x-                            -> Int -- ^ y-                            -> TensorPatch (CubicCoefficient px)-tensorPatchAtWithDerivative = tensorPatchAt' cubicPreparator--rawMatrix :: V.Vector (V.Vector Float)-rawMatrix = V.fromListN 16 $ V.fromListN 16 <$>-  [ [ 1, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]-  , [ 0, 0, 0, 0,  1, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]-  , [-3, 3, 0, 0, -2,-1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]-  , [ 2,-2, 0, 0,  1, 1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]-  , [ 0, 0, 0, 0,  0, 0, 0, 0,  1, 0, 0, 0,  0, 0, 0, 0 ]-  , [ 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  1, 0, 0, 0 ]-  , [ 0, 0, 0, 0,  0, 0, 0, 0, -3, 3, 0, 0, -2,-1, 0, 0 ]-  , [ 0, 0, 0, 0,  0, 0, 0, 0,  2,-2, 0, 0,  1, 1, 0, 0 ]-  , [-3, 0, 3, 0,  0, 0, 0, 0, -2, 0,-1, 0,  0, 0, 0, 0 ]-  , [ 0, 0, 0, 0, -3, 0, 3, 0,  0, 0, 0, 0, -2, 0,-1, 0 ]-  , [ 9,-9,-9, 9,  6, 3,-6,-3,  6,-6, 3,-3,  4, 2, 2, 1 ]-  , [-6, 6, 6,-6, -3,-3, 3, 3, -4, 4,-2, 2, -2,-2,-1,-1 ]-  , [ 2, 0,-2, 0,  0, 0, 0, 0,  1, 0, 1, 0,  0, 0, 0, 0 ]-  , [ 0, 0, 0, 0,  2, 0,-2, 0,  0, 0, 0, 0,  1, 0, 1, 0 ]-  , [-6, 6, 6,-6, -4,-2, 4, 2, -3, 3,-3, 3, -2,-1,-2,-1 ]-  , [ 4,-4,-4, 4,  2, 2,-2,-2,  2,-2, 2,-2,  1, 1, 1, 1 ]-  ]--cubicPreparator :: (InterpolablePixel px)-                => ParametricValues (Derivative px)-                -> CubicCoefficient px-cubicPreparator ParametricValues { .. } =-    CubicCoefficient $ ParametricValues (sliceAt 0) (sliceAt 4) (sliceAt 8) (sliceAt 12) where-  Derivative c00 fx00 fy00 fxy00 = _northValue-  Derivative c10 fx10 fy10 fxy10 = _eastValue-  Derivative c01 fx01 fy01 fxy01 = _westValue-  Derivative c11 fx11 fy11 fxy11 = _southValue--  resultVector = mulVec $ V.fromListN 16-    [  c00,   c10,   c01,   c11-    , fx00,  fx10,  fx01,  fx11 -    , fy00,  fy10,  fy01,  fy11 -    ,fxy00, fxy10, fxy01, fxy11-    ]--  mulVec vec = VG.foldl' (^+^) zero . VG.zipWith (^*) vec <$> rawMatrix--  sliceAt i = V4 -    (resultVector V.! i)-    (resultVector V.! (i + 1))-    (resultVector V.! (i + 2))-    (resultVector V.! (i + 3))--tensorPatchAt' :: ColorPreparator px pxt -> MeshPatch px -> Int -> Int-               -> TensorPatch pxt-tensorPatchAt' preparator mesh@MeshPatch { _meshTensorDerivatives = Nothing } x y =-    toTensorPatch $ coonPatchAt' preparator mesh x y-tensorPatchAt' preparator mesh x y = TensorPatch-  { _curve0 = CubicBezier p00 p01 p02 p03-  , _curve1 = CubicBezier p10 p11 p12 p13-  , _curve2 = CubicBezier p20 p21 p22 p23-  , _curve3 = CubicBezier p30 p31 p32 p33-  , _tensorValues = preparator $ ParametricValues-        { _northValue = c00-        , _eastValue  = c03-        , _southValue = c33-        , _westValue  = c30-        }-  }-  where-    w = _meshPatchWidth mesh-    vertices = _meshPrimaryVertices mesh-    colors = _meshColors mesh-    -    hInter = _meshHorizontalSecondary mesh-    vInter = _meshVerticalSecondary mesh-    -    baseIx = (w + 1) * y + x-    p00 = vertices ! baseIx-    c00 = colors   ! baseIx-    -    p03 = vertices ! (baseIx + 1)-    c03 = colors   ! (baseIx + 1)-    -    p30 = vertices ! (baseIx + w + 1)-    c30 = colors   ! (baseIx + w + 1)-    p33 = vertices ! (baseIx + w + 2)-    c33 = colors   ! (baseIx + w + 2)-    -    baseH = w * y + x-    InterBezier p01 p02 = hInter ! baseH-    InterBezier p31 p32 = hInter ! (baseH + w)--    baseV = (w + 1) * y + x-    InterBezier p10 p20 = vInter ! baseV-    InterBezier p13 p23 = vInter ! (baseV + 1)--    Derivatives p11 p12 p21 p22 = case _meshTensorDerivatives mesh of-      Nothing -> error "Not a tensor patch"-      Just v -> v ! (w * y + x)---coonPatchAt' :: ColorPreparator px pxt-             -> MeshPatch px -> Int -> Int -> CoonPatch pxt-coonPatchAt' preparator mesh x y = CoonPatch -    { _north = CubicBezier p00 p01 p02 p03-    , _east  = CubicBezier p03 p13 p23 p33-    , _south = CubicBezier p33 p32 p31 p30-    , _west  = CubicBezier p30 p20 p10 p00-    , _coonValues = preparator $ ParametricValues-        { _northValue = c00-        , _eastValue  = c03-        , _southValue = c33-        , _westValue  = c30-        }-    }-  where-    w = _meshPatchWidth mesh-    vertices = _meshPrimaryVertices mesh-    colors = _meshColors mesh-    -    hInter = _meshHorizontalSecondary mesh-    vInter = _meshVerticalSecondary mesh-    -    baseIx = (w + 1) * y + x-    p00 = vertices ! baseIx-    c00 = colors   ! baseIx-    -    p03 = vertices ! (baseIx + 1)-    c03 = colors   ! (baseIx + 1)-    -    p30 = vertices ! (baseIx + w + 1)-    c30 = colors   ! (baseIx + w + 1)-    p33 = vertices ! (baseIx + w + 2)-    c33 = colors   ! (baseIx + w + 2)-    -    baseH = w * y + x-    InterBezier p01 p02 = hInter ! baseH-    InterBezier p31 p32 = hInter ! (baseH + w)--    baseV = (w + 1) * y + x-    InterBezier p10 p20 = vInter ! baseV-    InterBezier p13 p23 = vInter ! (baseV + 1)---- | Extract a list of all the coon patches of the mesh.-coonPatchesOf :: MeshPatch px -> [CoonPatch (ParametricValues px)]-coonPatchesOf mesh@MeshPatch { .. } =-  [coonPatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]---- | Extract a list of all the tensor patches of the mesh.-tensorPatchesOf :: MeshPatch px -> [TensorPatch (ParametricValues px)]-tensorPatchesOf mesh@MeshPatch { .. } =-  [tensorPatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]---- | Extract all the coon patch of a mesh using an image interpolation.-imagePatchesOf :: MeshPatch (ImageMesh px) -> [CoonPatch (ImageMesh px)]-imagePatchesOf mesh@MeshPatch { .. } =-  [coonImagePatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]---- | Extract all the tensor patch of a mesh using an image interpolation.-tensorImagePatchesOf :: MeshPatch (ImageMesh px) -> [TensorPatch (ImageMesh px)]-tensorImagePatchesOf mesh@MeshPatch { .. } =-  [tensorImagePatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]---- | Extract all the coon patch of a mesh using cubic interpolation.-cubicCoonPatchesOf :: (InterpolablePixel px)-                   => MeshPatch (Derivative px)-                   -> [CoonPatch (CubicCoefficient px)]-cubicCoonPatchesOf mesh@MeshPatch { .. } =-  [coonPatchAtWithDerivative mesh x y-        | y <- [0 .. _meshPatchHeight - 1]-        , x <- [0 .. _meshPatchWidth - 1] ]---- | Extract all the tensor patch of a mesh using cubic interpolation.-cubicTensorPatchesOf :: (InterpolablePixel px)-                     => MeshPatch (Derivative px)-                     -> [TensorPatch (CubicCoefficient px)]-cubicTensorPatchesOf mesh@MeshPatch { .. } =-  [tensorPatchAtWithDerivative mesh x y-        | y <- [0 .. _meshPatchHeight - 1]-        , x <- [0 .. _meshPatchWidth - 1] ]-+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE CPP #-}
+#define SVG_2
+-- | Module defining the type of mesh patch grid.
+module Graphics.Rasterific.MeshPatch
+    ( -- * Types
+      InterBezier( .. )
+    , Derivatives( .. )
+    , MeshPatch( .. )
+    , CubicCoefficient( .. )
+
+     -- * Functions
+    , calculateMeshColorDerivative
+    , verticeAt
+    , generateLinearGrid
+    , generateImageMesh
+
+      -- * Extraction functions
+      -- ** Simple
+    , coonPatchAt
+    , tensorPatchAt
+    , coonImagePatchAt
+    , tensorImagePatchAt
+    , coonPatchAtWithDerivative
+    , tensorPatchAtWithDerivative
+
+      -- ** Multiple
+    , coonPatchesOf
+    , tensorPatchesOf
+    , imagePatchesOf
+    , tensorImagePatchesOf
+    , cubicCoonPatchesOf
+    , cubicTensorPatchesOf
+
+      -- * Mutable mesh
+    , MutableMesh
+    , thawMesh
+    , freezeMesh
+
+     -- * Monadic mesh creation
+    , withMesh
+    , setVertice
+    , getVertice
+    , setHorizPoints
+    , setVertPoints
+    , setColor
+    ) where
+
+{-import Debug.Trace-}
+{-import Text.Printf-}
+
+import Data.Monoid( (<>) )
+import Control.Monad.ST( runST )
+import Control.Monad.Reader( runReaderT )
+import Control.Monad.Reader.Class
+import Control.Monad.Primitive( PrimMonad, PrimState )
+import Data.Vector( (!) )
+import qualified Data.Vector as V
+import qualified Data.Vector.Mutable as MV
+import qualified Data.Vector.Generic as VG
+
+import Codec.Picture( Image( imageWidth, imageHeight ) )
+import Graphics.Rasterific.Linear
+import Graphics.Rasterific.MiniLens
+import Graphics.Rasterific.Types
+import Graphics.Rasterific.Compositor
+import Graphics.Rasterific.Transformations
+import Graphics.Rasterific.PatchTypes
+
+#ifdef SVG_2
+slopeOf :: (Additive h, Applicative h)
+        => h Float -> h Float -> h Float
+        -> Point -> Point -> Point
+        -> h Float
+slopeOf prevColor thisColor nextColor
+        prevPoint thisPoint nextPoint 
+  | nearZero distPrev || nearZero distNext = zero
+  | otherwise = slopeVal <$> slopePrev <*> slope <*> slopeNext
+  where
+    distPrev = thisPoint `distance` prevPoint
+    distNext = thisPoint `distance` nextPoint
+
+    slopePrev | nearZero distPrev = zero
+              | otherwise = (thisColor ^-^ prevColor) ^/ distPrev
+    slopeNext | nearZero distNext = zero
+              | otherwise = (nextColor ^-^ thisColor) ^/ distNext
+    slope = (slopePrev ^+^ slopeNext) ^* 0.5
+
+    slopeVal :: Float -> Float -> Float -> Float
+    slopeVal sp s sn
+      | signum sp /= signum sn = 0
+      | abs s > abs minSlope = minSlope
+      | otherwise = s
+      where
+        minSlope
+          | abs sp < abs sn = 3 * sp
+          | otherwise = 3 * sn
+#else
+slopeBasic :: (Additive h)
+           => h Float -> h Float
+           -> Point -> Point
+           -> h Float
+slopeBasic prevColor nextColor prevPoint nextPoint 
+  | nearZero d = zero
+  | otherwise = (nextColor ^-^ prevColor) ^/ d
+  where
+    d = prevPoint `distance` nextPoint
+#endif
+
+-- | Prepare a gradient mesh to use cubic color interpolation, see
+-- renderCubicMesh documentation to see the global use of this function.
+calculateMeshColorDerivative :: forall px. (InterpolablePixel px)
+                             => MeshPatch px -> MeshPatch (Derivative px)
+calculateMeshColorDerivative mesh = mesh { _meshColors = withEdgesDerivatives } where
+  withEdgesDerivatives =
+     colorDerivatives V.// (topDerivative <> bottomDerivative <> leftDerivative <> rightDerivative)
+  colorDerivatives =
+     V.fromListN (w * h) [interiorDerivative x y | y <- [0 .. h - 1], x <- [0 .. w - 1]]
+
+  w = _meshPatchWidth mesh + 1
+  h = _meshPatchHeight mesh + 1
+  clampX = max 0 . min (w - 1)
+  clampY = max 0 . min (h - 1)
+
+  rawColorAt x y =_meshColors mesh V.! (y * w + x)
+  atColor x y = toFloatPixel $ rawColorAt (clampX x) (clampY y)
+#ifdef SVG_2
+  isOnVerticalBorder x = x == 0 || x == w - 1 
+  isOnHorizontalBorder y = y == 0 || y == h - 1
+#endif
+
+  pointAt x y = verticeAt mesh (clampX x) (clampY y)
+  derivAt x y = colorDerivatives  V.! (y * w + x)
+
+
+  topDerivative = 
+    [edgeDerivative yDerivative 0 1 x 0 | x <- [1 .. w - 2]]
+  bottomDerivative = 
+    [edgeDerivative yDerivative 0 (-1) x (h - 1) | x <- [1 .. w - 2]]
+  leftDerivative =
+    [edgeDerivative xDerivative 1 0 0 y | y <- [1 .. h - 2]]
+  rightDerivative = 
+    [edgeDerivative xDerivative (-1) 0 (w - 1) y | y <- [1 .. h - 2]]
+
+  edgeDerivative :: Lens' (Derivative px) (Holder px Float) -> Int -> Int -> Int -> Int
+                 -> (Int, Derivative px)
+  edgeDerivative coord dx dy x y
+    | nearZero d = (ix, oldDeriv)
+    | otherwise = (ix, oldDeriv & coord .~ otherDeriv)
+    where
+      ix = y * w + x
+      oldDeriv = derivAt x y
+      derivs = oldDeriv .^ coord
+      otherDeriv = (c ^/ d) ^-^ derivs
+      c = (atColor (x+dx) (y+dy) ^-^ atColor x y) ^* 2
+      d = pointAt (x+dx) (y+dy) `distance` pointAt x y
+
+  -- General case
+  interiorDerivative x y
+#ifdef SVG_2
+    | isOnHorizontalBorder y && isOnVerticalBorder x = Derivative thisColor zero zero zero
+    | isOnHorizontalBorder y = Derivative thisColor dx zero zero
+    | isOnVerticalBorder x = Derivative thisColor zero dy zero
+#endif
+    | otherwise = Derivative thisColor dx dy dxy
+    where
+#ifdef SVG_2
+      dx = slopeOf
+          cxPrev thisColor cxNext
+          xPrev this xNext
+      
+      dy = slopeOf
+          cyPrev thisColor cyNext
+          yPrev this yNext
+          -- -}
+      
+      dxy = zero
+#else
+      dx = slopeBasic cxPrev cxNext xPrev xNext
+      dy = slopeBasic cyPrev cyNext yPrev yNext
+
+      dxy | nearZero xyDist = zero
+          | otherwise = (cxyNext ^-^ cyxPrev ^-^ cyxNext ^+^ cxyPrev) ^/ (xyDist)
+      xyDist = (xNext `distance` xPrev) * (yNext `distance` yPrev)
+
+      cxyPrev = atColor (x - 1) (y - 1)
+      xyPrev = pointAt (x - 1) (y - 1)
+
+      cxyNext = atColor (x + 1) (y + 1)
+      xyNext = pointAt (x + 1) (y + 1)
+
+      cyxPrev = atColor (x - 1) (y + 1)
+      yxPrev = pointAt (x - 1) (y + 1)
+
+      cyxNext = atColor (x + 1) (y - 1)
+      yxNext = pointAt (x + 1) (y - 1)
+#endif
+
+      cxPrev = atColor (x - 1) y
+      thisColor = atColor x y
+      cxNext = atColor (x + 1) y
+      
+      cyPrev = atColor x (y - 1)
+      cyNext = atColor x (y + 1)
+      
+      xPrev = pointAt (x - 1) y
+      this  = pointAt x y
+      xNext = pointAt (x + 1) y
+      
+      yPrev = pointAt x (y - 1)
+      yNext = pointAt x (y + 1)
+
+-- | Mutable version of a MeshPatch
+data MutableMesh s px = MutableMesh
+  { _meshMutWidth :: !Int
+  , _meshMutHeight :: !Int
+  , _meshMutPrimaryVertices :: !(MV.MVector s Point)
+  , _meshMutHorizSecondary :: !(MV.MVector s InterBezier)
+  , _meshMutVertSecondary :: !(MV.MVector s InterBezier)
+  , _meshMutColors :: !(MV.MVector s px)
+  , _meshMutTensorDerivatives :: !(Maybe (MV.MVector s Derivatives))
+  }
+
+-- | Normal mesh to mutable mesh
+thawMesh :: PrimMonad m => MeshPatch px -> m (MutableMesh (PrimState m) px)
+thawMesh MeshPatch { .. } = do
+  let _meshMutWidth = _meshPatchWidth
+      _meshMutHeight = _meshPatchHeight
+  _meshMutPrimaryVertices <- V.thaw _meshPrimaryVertices 
+  _meshMutHorizSecondary <- V.thaw _meshHorizontalSecondary
+  _meshMutVertSecondary <- V.thaw _meshVerticalSecondary
+  _meshMutColors <- V.thaw _meshColors
+  _meshMutTensorDerivatives <- case _meshTensorDerivatives of
+      Nothing -> return Nothing
+      Just v -> Just <$> V.thaw v
+  return MutableMesh { .. }
+
+-- | Mutable mesh to freezed mesh.
+freezeMesh :: PrimMonad m => MutableMesh (PrimState m) px -> m (MeshPatch px)
+freezeMesh MutableMesh { .. } = do
+  let _meshPatchWidth = _meshMutWidth
+      _meshPatchHeight = _meshMutHeight
+  _meshPrimaryVertices <- V.freeze _meshMutPrimaryVertices 
+  _meshHorizontalSecondary <- V.freeze _meshMutHorizSecondary
+  _meshVerticalSecondary <- V.freeze _meshMutVertSecondary
+  _meshTensorDerivatives <- case _meshMutTensorDerivatives of
+        Nothing -> return Nothing
+        Just v -> Just <$> V.freeze v
+  _meshColors <- V.freeze _meshMutColors
+  return MeshPatch { .. }
+
+-- | Retrieve a mesh primary vertice purely
+verticeAt :: MeshPatch px
+          -> Int -- ^ Between 0 and _meshPatchWidth + 1 (excluded)
+          -> Int -- ^ Between 0 and _meshPatchHeight + 1 (excluded)
+          -> Point
+verticeAt m x y = _meshPrimaryVertices m ! idx where
+    idx = y * (_meshPatchWidth m + 1) + x
+
+-- | Given an original MeshPatch, provide context to mutate it through
+-- modification functions.
+withMesh :: MeshPatch px
+         -> (forall m. (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m) =>
+                        m a)
+         -> (a, MeshPatch px)
+withMesh mesh act = runST $ do
+  mut <- thawMesh  mesh
+  v <- runReaderT act mut
+  final <- freezeMesh mut
+  return (v, final)
+
+-- | Set the vertice of a mesh at a given coordinate
+setVertice :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)
+           => Int   -- ^ x coordinate in [0, w]
+           -> Int   -- ^ y coordinate in [0, h]
+           -> Point -- ^ new point value
+           -> m ()
+setVertice x y p = do
+  MutableMesh { .. } <- ask
+  let idx = y * (_meshMutWidth + 1) + x
+  MV.write _meshMutPrimaryVertices idx p
+
+-- | Get the position of vertice
+getVertice :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)
+           => Int -> Int -> m Point
+getVertice x y = do
+  p <- ask
+  let idx = y * (_meshMutWidth p + 1) + x
+  MV.read (_meshMutPrimaryVertices p) idx
+
+-- | Set the two control bezier points horizontally
+setHorizPoints :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)
+               => Int -> Int -> InterBezier -> m ()
+setHorizPoints x y p = do
+  MutableMesh { .. } <- ask
+  let idx = y * _meshMutWidth + x
+  MV.write _meshMutHorizSecondary idx p
+
+-- | Set the two control bezier points vertically
+setVertPoints :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)
+              => Int -> Int -> InterBezier -> m ()
+setVertPoints x y p = do
+  MutableMesh { .. } <- ask
+  let idx = y * (_meshMutWidth + 1) + x
+  MV.write _meshMutVertSecondary idx p
+
+
+-- | Set the value associated to a vertex
+setColor :: (MonadReader (MutableMesh (PrimState m) px) m, PrimMonad m)
+         => Int -> Int -> px -> m ()
+setColor x y p = do
+  MutableMesh { .. } <- ask
+  let idx = y * (_meshMutWidth + 1) + x
+  MV.write _meshMutColors idx p
+
+-- | Generate a meshpatch at the size given by the image and
+-- a number of cell in a mesh
+generateImageMesh :: Int      -- ^ Horizontal cell count
+                  -> Int      -- ^ Vertical cell count
+                  -> Point    -- ^ Position of the corner upper left
+                  -> Image px -- ^ Image to transform through a mesh
+                  -> MeshPatch (ImageMesh px)
+generateImageMesh w h base img = generateLinearGrid w h base (V2 dx dy) infos where
+  dx = fromIntegral (imageWidth img) / fromIntegral w
+  dy = fromIntegral (imageHeight img) / fromIntegral h
+  infos = V.fromListN ((w + 1) * (h + 1))
+    [ImageMesh img $ trans <> scaling
+        | y <- [0 .. h]
+        , x <- [0 .. w]
+        , let fx = fromIntegral x
+              fy = fromIntegral y
+              trans = translate (V2 (fx * dx) (fy * dy))
+              scaling = scale dx dy]
+
+
+-- | Generate a valid gradient with the shape of a simple grid
+-- using some simple information. You can use `thawMesh` and `freezeMesh`
+-- to mutate it.
+generateLinearGrid :: Int           -- ^ Width in patch
+                   -> Int           -- ^ Height in patch
+                   -> Point         -- ^ Position of the upper left corner
+                   -> V2 Float      -- ^ Size of each patch in x adn y
+                   -> V.Vector px   -- ^ Vector of values, size must be (width + 1) * (height + 1)
+                   -> MeshPatch px
+generateLinearGrid w h base (V2 dx dy) colors = MeshPatch
+  { _meshPatchWidth = w
+  , _meshPatchHeight = h
+  , _meshPrimaryVertices = vertices 
+  , _meshHorizontalSecondary = hSecondary 
+  , _meshVerticalSecondary = vSecondary
+  , _meshTensorDerivatives = Nothing
+  , _meshColors = colors
+  }
+  where
+    vertexCount = (w + 1) * (h + 1)
+    vertices =
+      V.fromListN vertexCount [base ^+^ V2 (dx * fromIntegral x) (dy * fromIntegral y)
+                                        | y <- [0 .. h], x <- [0 .. w]]
+    at x y = vertices ! (y * (w + 1) + x)
+    hSecondary = V.fromListN ((h + 1) * w)
+        [InterBezier (p0 ^+^ delta ^* (1/3)) (p0 ^+^ delta ^* (2/3))
+            | y <- [0 .. h], x <- [0 .. w - 1]
+            , let p0 = at x y
+                  p1 = at (x + 1) y
+                  delta = p1 ^-^ p0
+            ]
+
+    vSecondary = V.fromListN ((w + 1) * h)
+        [InterBezier (p0 ^+^ delta ^* (1/3)) (p0 ^+^ delta ^* (2/3))
+            | y <- [0 .. h - 1], x <- [0 .. w]
+            , let p0 = at x y
+                  p1 = at x (y + 1)
+                  delta = p1 ^-^ p0
+            ]
+
+type ColorPreparator px pxt = ParametricValues px -> pxt
+
+-- | Extract a coon patch at a given position.
+coonPatchAt :: MeshPatch px
+            -> Int -- ^ x
+            -> Int -- ^ y
+            -> CoonPatch (ParametricValues px)
+coonPatchAt = coonPatchAt' id
+
+-- | Extract a tensor patch at a given position
+tensorPatchAt :: MeshPatch px
+              -> Int -- ^ x
+              -> Int -- ^ y
+              -> TensorPatch (ParametricValues px)
+tensorPatchAt = tensorPatchAt' id
+
+-- | Extract an image patch out of a mesh at a given position.
+coonImagePatchAt :: MeshPatch (ImageMesh px)
+                 -> Int -- ^ x
+                 -> Int -- ^ y
+                 -> CoonPatch (ImageMesh px)
+coonImagePatchAt = coonPatchAt' _northValue
+
+
+-- | Extract a tensor image patch out of a mesh at
+-- a given position.
+tensorImagePatchAt :: MeshPatch (ImageMesh px)
+                   -> Int -- ^ x
+                   -> Int -- ^ y
+                   -> TensorPatch (ImageMesh px)
+tensorImagePatchAt = tensorPatchAt' _northValue
+
+-- | Extract a coon patch for cubic interpolation at a given position
+-- see `calculateMeshColorDerivative`
+coonPatchAtWithDerivative :: (InterpolablePixel px)
+                          => MeshPatch (Derivative px)
+                          -> Int -- ^ x
+                          -> Int -- ^ y
+                          -> CoonPatch (CubicCoefficient px)
+coonPatchAtWithDerivative = coonPatchAt' cubicPreparator
+
+-- | Extract a tensor patch for cubic interpolation at a given position
+-- see `calculateMeshColorDerivative`
+tensorPatchAtWithDerivative :: (InterpolablePixel px)
+                            => MeshPatch (Derivative px)
+                            -> Int -- ^ x
+                            -> Int -- ^ y
+                            -> TensorPatch (CubicCoefficient px)
+tensorPatchAtWithDerivative = tensorPatchAt' cubicPreparator
+
+rawMatrix :: V.Vector (V.Vector Float)
+rawMatrix = V.fromListN 16 $ V.fromListN 16 <$>
+  [ [ 1, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]
+  , [ 0, 0, 0, 0,  1, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]
+  , [-3, 3, 0, 0, -2,-1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]
+  , [ 2,-2, 0, 0,  1, 1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0 ]
+  , [ 0, 0, 0, 0,  0, 0, 0, 0,  1, 0, 0, 0,  0, 0, 0, 0 ]
+  , [ 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  1, 0, 0, 0 ]
+  , [ 0, 0, 0, 0,  0, 0, 0, 0, -3, 3, 0, 0, -2,-1, 0, 0 ]
+  , [ 0, 0, 0, 0,  0, 0, 0, 0,  2,-2, 0, 0,  1, 1, 0, 0 ]
+  , [-3, 0, 3, 0,  0, 0, 0, 0, -2, 0,-1, 0,  0, 0, 0, 0 ]
+  , [ 0, 0, 0, 0, -3, 0, 3, 0,  0, 0, 0, 0, -2, 0,-1, 0 ]
+  , [ 9,-9,-9, 9,  6, 3,-6,-3,  6,-6, 3,-3,  4, 2, 2, 1 ]
+  , [-6, 6, 6,-6, -3,-3, 3, 3, -4, 4,-2, 2, -2,-2,-1,-1 ]
+  , [ 2, 0,-2, 0,  0, 0, 0, 0,  1, 0, 1, 0,  0, 0, 0, 0 ]
+  , [ 0, 0, 0, 0,  2, 0,-2, 0,  0, 0, 0, 0,  1, 0, 1, 0 ]
+  , [-6, 6, 6,-6, -4,-2, 4, 2, -3, 3,-3, 3, -2,-1,-2,-1 ]
+  , [ 4,-4,-4, 4,  2, 2,-2,-2,  2,-2, 2,-2,  1, 1, 1, 1 ]
+  ]
+
+cubicPreparator :: (InterpolablePixel px)
+                => ParametricValues (Derivative px)
+                -> CubicCoefficient px
+cubicPreparator ParametricValues { .. } =
+    CubicCoefficient $ ParametricValues (sliceAt 0) (sliceAt 4) (sliceAt 8) (sliceAt 12) where
+  Derivative c00 fx00 fy00 fxy00 = _northValue
+  Derivative c10 fx10 fy10 fxy10 = _eastValue
+  Derivative c01 fx01 fy01 fxy01 = _westValue
+  Derivative c11 fx11 fy11 fxy11 = _southValue
+
+  resultVector = mulVec $ V.fromListN 16
+    [  c00,   c10,   c01,   c11
+    , fx00,  fx10,  fx01,  fx11 
+    , fy00,  fy10,  fy01,  fy11 
+    ,fxy00, fxy10, fxy01, fxy11
+    ]
+
+  mulVec vec = VG.foldl' (^+^) zero . VG.zipWith (^*) vec <$> rawMatrix
+
+  sliceAt i = V4 
+    (resultVector V.! i)
+    (resultVector V.! (i + 1))
+    (resultVector V.! (i + 2))
+    (resultVector V.! (i + 3))
+
+tensorPatchAt' :: ColorPreparator px pxt -> MeshPatch px -> Int -> Int
+               -> TensorPatch pxt
+tensorPatchAt' preparator mesh@MeshPatch { _meshTensorDerivatives = Nothing } x y =
+    toTensorPatch $ coonPatchAt' preparator mesh x y
+tensorPatchAt' preparator mesh x y = TensorPatch
+  { _curve0 = CubicBezier p00 p01 p02 p03
+  , _curve1 = CubicBezier p10 p11 p12 p13
+  , _curve2 = CubicBezier p20 p21 p22 p23
+  , _curve3 = CubicBezier p30 p31 p32 p33
+  , _tensorValues = preparator $ ParametricValues
+        { _northValue = c00
+        , _eastValue  = c03
+        , _southValue = c33
+        , _westValue  = c30
+        }
+  }
+  where
+    w = _meshPatchWidth mesh
+    vertices = _meshPrimaryVertices mesh
+    colors = _meshColors mesh
+    
+    hInter = _meshHorizontalSecondary mesh
+    vInter = _meshVerticalSecondary mesh
+    
+    baseIx = (w + 1) * y + x
+    p00 = vertices ! baseIx
+    c00 = colors   ! baseIx
+    
+    p03 = vertices ! (baseIx + 1)
+    c03 = colors   ! (baseIx + 1)
+    
+    p30 = vertices ! (baseIx + w + 1)
+    c30 = colors   ! (baseIx + w + 1)
+    p33 = vertices ! (baseIx + w + 2)
+    c33 = colors   ! (baseIx + w + 2)
+    
+    baseH = w * y + x
+    InterBezier p01 p02 = hInter ! baseH
+    InterBezier p31 p32 = hInter ! (baseH + w)
+
+    baseV = (w + 1) * y + x
+    InterBezier p10 p20 = vInter ! baseV
+    InterBezier p13 p23 = vInter ! (baseV + 1)
+
+    Derivatives p11 p12 p21 p22 = case _meshTensorDerivatives mesh of
+      Nothing -> error "Not a tensor patch"
+      Just v -> v ! (w * y + x)
+
+
+coonPatchAt' :: ColorPreparator px pxt
+             -> MeshPatch px -> Int -> Int -> CoonPatch pxt
+coonPatchAt' preparator mesh x y = CoonPatch 
+    { _north = CubicBezier p00 p01 p02 p03
+    , _east  = CubicBezier p03 p13 p23 p33
+    , _south = CubicBezier p33 p32 p31 p30
+    , _west  = CubicBezier p30 p20 p10 p00
+    , _coonValues = preparator $ ParametricValues
+        { _northValue = c00
+        , _eastValue  = c03
+        , _southValue = c33
+        , _westValue  = c30
+        }
+    }
+  where
+    w = _meshPatchWidth mesh
+    vertices = _meshPrimaryVertices mesh
+    colors = _meshColors mesh
+    
+    hInter = _meshHorizontalSecondary mesh
+    vInter = _meshVerticalSecondary mesh
+    
+    baseIx = (w + 1) * y + x
+    p00 = vertices ! baseIx
+    c00 = colors   ! baseIx
+    
+    p03 = vertices ! (baseIx + 1)
+    c03 = colors   ! (baseIx + 1)
+    
+    p30 = vertices ! (baseIx + w + 1)
+    c30 = colors   ! (baseIx + w + 1)
+    p33 = vertices ! (baseIx + w + 2)
+    c33 = colors   ! (baseIx + w + 2)
+    
+    baseH = w * y + x
+    InterBezier p01 p02 = hInter ! baseH
+    InterBezier p31 p32 = hInter ! (baseH + w)
+
+    baseV = (w + 1) * y + x
+    InterBezier p10 p20 = vInter ! baseV
+    InterBezier p13 p23 = vInter ! (baseV + 1)
+
+-- | Extract a list of all the coon patches of the mesh.
+coonPatchesOf :: MeshPatch px -> [CoonPatch (ParametricValues px)]
+coonPatchesOf mesh@MeshPatch { .. } =
+  [coonPatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]
+
+-- | Extract a list of all the tensor patches of the mesh.
+tensorPatchesOf :: MeshPatch px -> [TensorPatch (ParametricValues px)]
+tensorPatchesOf mesh@MeshPatch { .. } =
+  [tensorPatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]
+
+-- | Extract all the coon patch of a mesh using an image interpolation.
+imagePatchesOf :: MeshPatch (ImageMesh px) -> [CoonPatch (ImageMesh px)]
+imagePatchesOf mesh@MeshPatch { .. } =
+  [coonImagePatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]
+
+-- | Extract all the tensor patch of a mesh using an image interpolation.
+tensorImagePatchesOf :: MeshPatch (ImageMesh px) -> [TensorPatch (ImageMesh px)]
+tensorImagePatchesOf mesh@MeshPatch { .. } =
+  [tensorImagePatchAt mesh x y | y <- [0 .. _meshPatchHeight - 1], x <- [0 .. _meshPatchWidth - 1]]
+
+-- | Extract all the coon patch of a mesh using cubic interpolation.
+cubicCoonPatchesOf :: (InterpolablePixel px)
+                   => MeshPatch (Derivative px)
+                   -> [CoonPatch (CubicCoefficient px)]
+cubicCoonPatchesOf mesh@MeshPatch { .. } =
+  [coonPatchAtWithDerivative mesh x y
+        | y <- [0 .. _meshPatchHeight - 1]
+        , x <- [0 .. _meshPatchWidth - 1] ]
+
+-- | Extract all the tensor patch of a mesh using cubic interpolation.
+cubicTensorPatchesOf :: (InterpolablePixel px)
+                     => MeshPatch (Derivative px)
+                     -> [TensorPatch (CubicCoefficient px)]
+cubicTensorPatchesOf mesh@MeshPatch { .. } =
+  [tensorPatchAtWithDerivative mesh x y
+        | y <- [0 .. _meshPatchHeight - 1]
+        , x <- [0 .. _meshPatchWidth - 1] ]
+
src/Graphics/Rasterific/MicroPdf.hs view
@@ -7,6 +7,7 @@ {-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE TupleSections #-}
 module Graphics.Rasterific.MicroPdf( renderDrawingToPdf
+                                   , renderDrawingsToPdf
                                    , renderOrdersToPdf
                                    ) where
 
@@ -128,6 +129,10 @@ --------------------------------------------------
 type PdfEnv = StateT PdfContext (Reader PdfConfiguration)
 
+runPdfEnvs :: PdfConfiguration -> PdfId -> [PdfEnv a] -> ([a], PdfContext)
+runPdfEnvs conf firstFreeId producers =
+  runReader (runStateT (sequence producers) $ emptyContext firstFreeId) conf 
+
 runPdfEnv :: PdfConfiguration -> PdfId -> PdfEnv a -> (a, PdfContext)
 runPdfEnv conf firstFreeId producer =
   runReader (runStateT producer $ emptyContext firstFreeId) conf 
@@ -373,7 +378,7 @@ pdfSignature = "%PDF-1.4\n%\xBF\xF7\xA2\xFE\n"
 
 refOf :: PdfId -> B.ByteString
-refOf i = buildToStrict $ intDec i <> " 0 R"
+refOf i = buildToStrict $ intDec i <> " 0 R "
 
 arrayOf :: Builder -> Builder
 arrayOf a = tp "[ " <> a <> tp " ]"
@@ -953,7 +958,11 @@ 
 pdfFromProducer :: PdfBaseColorable px
                 => Proxy px -> PdfConfiguration -> PdfEnv Builder -> LB.ByteString
-pdfFromProducer px conf producer = toLazyByteString $
+pdfFromProducer px conf producer = pdfFromProducers px conf [producer]
+
+pdfFromProducers :: PdfBaseColorable px
+                => Proxy px -> PdfConfiguration -> [PdfEnv Builder] -> LB.ByteString
+pdfFromProducers px conf producers = toLazyByteString $
   foldMap byteString objs
     <> xref
     <> buildTrailer objects catalogId
@@ -961,17 +970,27 @@     <> tp "%%EOF"
   where
   height = _pdfHeight conf
-  (catalogId : outlineId : pagesId : pageId : contentId : endObjId : firstFreeId :  _) = [1..]
-  (content, endContext) = runPdfEnv conf firstFreeId producer
+  (catalogId : outlineId : pagesId : endObjId : remainingIds) = [1..]
+  (pageIds, remainingIds') = splitAt (length producers) remainingIds
+  (contentIds, remainingIds'') = splitAt (length producers) remainingIds'
+  firstFreeId = head remainingIds''
+  (contents, endContext) = runPdfEnvs conf firstFreeId producers
   initialTransform = toPdf . toPdfSpace $ fromIntegral height
 
+
   objects =
     [ catalogObject  pagesId outlineId catalogId 
     , outlinesObject [] outlineId
-    , pagesObject    [pageId] pagesId
-    , pageObject     px (_pdfWidth conf) height pagesId contentId endObjId pageId
-    , contentObject  (buildToStrict $ initialTransform <> content) contentId
-    , resourceObject
+    , pagesObject    pageIds pagesId
+    ] <>
+
+    concatMap (\(contentId, pageId, content) -> 
+        [ pageObject     px (_pdfWidth conf) height pagesId contentId endObjId pageId
+        , contentObject  (buildToStrict $ initialTransform <> content) contentId]
+      ) (zip3 contentIds pageIds contents)
+
+    <>
+    [ resourceObject
         (endContext .^ pdfShadings.resAssoc)
         (endContext .^ pdfGraphicStates.resAssoc)
         (endContext .^ pdfPatterns.resAssoc)
@@ -991,8 +1010,13 @@ renderDrawingToPdf :: (forall px . PdfColorable px => Drawing px () -> [DrawOrder px])
                    -> Int -> Int -> Dpi -> Drawing PixelRGBA8 ()
                    -> LB.ByteString
-renderDrawingToPdf toOrders width height dpi =
-    pdfFromProducer px conf . pdfProducer baseTexture
+renderDrawingToPdf toOrders width height dpi d = renderDrawingsToPdf toOrders width height dpi [d]
+
+renderDrawingsToPdf :: (forall px . PdfColorable px => Drawing px () -> [DrawOrder px])
+                   -> Int -> Int -> Dpi -> [Drawing PixelRGBA8 ()]
+                   -> LB.ByteString
+renderDrawingsToPdf toOrders width height dpi ds =
+    pdfFromProducers px conf $ map (pdfProducer baseTexture) ds
   where
     px = Proxy :: Proxy PixelRGBA8
     baseTexture = SolidTexture emptyPx 
src/Graphics/Rasterific/Operators.hs view
@@ -149,7 +149,7 @@ -- point.
 isNearby :: Point -> Point -> Bool
 {-# INLINE isNearby #-}
-isNearby p1 p2 = squareDist < 0.2
+isNearby p1 p2 = squareDist < 0.1
   where vec = p1 ^-^ p2
         squareDist = vec `dot` vec
 
src/Graphics/Rasterific/PatchTypes.hs view
@@ -1,396 +1,396 @@-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies #-}-module Graphics.Rasterific.PatchTypes-  ( -- * New geometry-    CoonPatch( .. )-  , TensorPatch( .. )-  , MeshPatch( .. )-  , InterBezier( .. )--    -- * Types-  , CoonColorWeight-  , PatchInterpolation( .. )-  , ParametricValues( .. )-  , Derivative( .. )-  , Derivatives( .. )-  , UV-  , UVPatch-  , CubicCoefficient( .. )-  , ImageMesh( .. )--    -- * Helper functions-  , transposeParametricValues -  , coonPointAt-  , toTensorPatch-  , foldMeshPoints-  , isVerticalOrientation--    -- * Lenses-  , xDerivative-  , yDerivative-  ) where--import Data.Monoid( (<>) )-import qualified Data.Vector as V--import Codec.Picture( Image )--import Graphics.Rasterific.CubicBezier-import Graphics.Rasterific.MiniLens-import Graphics.Rasterific.Linear-import Graphics.Rasterific.Types-import Graphics.Rasterific.Compositor-import Graphics.Rasterific.Transformations---- | Type of coordinate interpolation-type CoonColorWeight = Float---- | How do we want to perform color/image interpolation--- within the patch.-data PatchInterpolation-  = -- | Bilinear interpolation-    ---    -- @-    -- import qualified Data.Vector as V-    -- let colorCycle = cycle-    --       [ PixelRGBA8 0 0x86 0xc1 255-    --       , PixelRGBA8 0xff 0xf4 0xc1 255-    --       , PixelRGBA8 0xFF 0x53 0x73 255-    --       , PixelRGBA8 0xff 0xf4 0xc1 255-    --       , PixelRGBA8 0 0x86 0xc1 255]-    --     colors = V.fromListN (4 * 4) colorCycle-    -- renderMeshPatch PatchBilinear $ generateLinearGrid 3 3 (V2 10 10) (V2 60 60) colors-    -- @-    ---    -- <<docimages/mesh_patch_interp_bilinear.png>>-    ---    PatchBilinear-    -- | Bicubic interpolation-    ---    -- @-    -- import qualified Data.Vector as V-    -- let colorCycle = cycle-    --       [ PixelRGBA8 0 0x86 0xc1 255-    --       , PixelRGBA8 0xff 0xf4 0xc1 255-    --       , PixelRGBA8 0xFF 0x53 0x73 255-    --       , PixelRGBA8 0xff 0xf4 0xc1 255-    --       , PixelRGBA8 0 0x86 0xc1 255]-    --     colors = V.fromListN (4 * 4) colorCycle-    -- renderMeshPatch PatchBicubic $ generateLinearGrid 3 3 (V2 10 10) (V2 60 60) colors-    -- @-    ---    -- <<docimages/mesh_patch_interp_bicubic.png>>-    ---  | PatchBicubic-  deriving (Eq, Show)---- | Values associated to the corner of a patch------ @---  North               East---      +--------------+---      |0            1|---      |              |---      |              |---      |              |---      |3            2|---      +--------------+---  West                South--- @----data ParametricValues a = ParametricValues-  { _northValue :: !a-  , _eastValue  :: !a-  , _southValue :: !a-  , _westValue  :: !a-  }-  deriving (Functor, Show)---- | Store the derivative necessary for cubic interpolation in--- the gradient mesh.-data Derivative px = Derivative-  { _derivValues :: !(Holder px Float)-  , _xDerivative :: !(Holder px Float)-  , _yDerivative :: !(Holder px Float)-  , _xyDerivative :: !(Holder px Float)-  }--deriving instance Show (Holder px Float) => Show (Derivative px)---- | Helping lens-xDerivative :: Lens' (Derivative px) (Holder px Float)-xDerivative = lens _xDerivative setter where-  setter o v = o { _xDerivative = v }---- | Help lens-yDerivative :: Lens' (Derivative px) (Holder px Float)-yDerivative = lens _yDerivative setter where-  setter o v = o { _yDerivative = v }--instance Applicative ParametricValues where-    pure a = ParametricValues a a a a-    ParametricValues n e s w <*> ParametricValues n' e' s' w' =-        ParametricValues (n n') (e e') (s s') (w w')--instance Foldable ParametricValues where-  foldMap f (ParametricValues n e s w) = f n <> f e <> f s <> f w---- | Transpose (switch vertical/horizontal orientation) of values.-transposeParametricValues :: ParametricValues a -> ParametricValues a-transposeParametricValues (ParametricValues n e s w) = ParametricValues n w s e---- | Describe a tensor patch-data TensorPatch weight = TensorPatch-  { _curve0 :: !CubicBezier-  , _curve1 :: !CubicBezier-  , _curve2 :: !CubicBezier-  , _curve3 :: !CubicBezier-  , _tensorValues :: !weight-  }--isVerticalOrientation :: TensorPatch a -> Bool-isVerticalOrientation p = dy > dx where-  CubicBezier a _ _ d = _curve0 p-  V2 dx dy = abs <$> (d ^-^ a)--instance Transformable (TensorPatch px) where-  transform f (TensorPatch c0 c1 c2 c3 v) =-    TensorPatch-        (transform f c0)-        (transform f c1)-        (transform f c2)-        (transform f c3)-        v-  transformM f (TensorPatch c0 c1 c2 c3 v) =-    TensorPatch-        <$> transformM f c0-        <*> transformM f c1-        <*> transformM f c2-        <*> transformM f c3-        <*> return v---instance {-# OVERLAPPING #-} PointFoldable (TensorPatch px) where-  foldPoints f acc (TensorPatch c0 c1 c2 c3 _) = g c3 . g c2 . g c1 $ g c0 acc-    where g v a = foldPoints f a v---- | Define the boundary and interpolated values of a coon patch.------ @---                        ----->---                  North     _____----------------+---   ^          +------------//                     // .---   |         //                                  //       |---   |        //                                  //        |---   |       //                                  //  east   |---   | west |                                  /          |---          |                                 |           v---           \\                                 \\   .---            \\                  __-------------+---             +----------------/---                    South---                       <-------- @----data CoonPatch weight = CoonPatch-    { _north :: !CubicBezier -- ^ North border, from left to right at top-    , _east :: !CubicBezier  -- ^ East obrder, from top to bottom-    , _south :: !CubicBezier -- ^ South border from right to left-    , _west :: !CubicBezier  -- ^ West border from bottom to top-    , _coonValues :: !weight -- ^ The patch values-    }-    deriving Show--instance {-# OVERLAPPING #-} Transformable (CoonPatch px) where-  transformM = transformCoonM-  transform = transformCoon --instance {-# OVERLAPPING #-} PointFoldable (CoonPatch px) where-  foldPoints f acc (CoonPatch n e s w _) = g n . g e . g s $ g w acc-    where g v a = foldPoints f a v--transformCoonM :: Monad m => (Point -> m Point) -> CoonPatch px -> m (CoonPatch px)-transformCoonM f (CoonPatch n e s w v) =-  CoonPatch <$> transformM f n <*> transformM f e <*> transformM f s <*> transformM f w-            <*> return v--transformCoon :: (Point -> Point) -> CoonPatch px -> CoonPatch px-transformCoon f (CoonPatch n e s w v) =-    CoonPatch-        (transform f n)-        (transform f e)-        (transform f s)-        (transform f w)-        v---- | Define a mesh patch grid, the grid is conceptually--- a regular grid of _meshPatchWidth * _meshPatchHeight--- patches but with shared edges-data MeshPatch px = MeshPatch-  { -- | Count of horizontal of *patch*-    _meshPatchWidth  :: !Int-    -- | Count of vertical of *patch*-  , _meshPatchHeight :: !Int-    -- | Main points defining the patch, of size-    -- (_meshPatchWidth + 1) * (_meshPatchHeight + 1)-  , _meshPrimaryVertices :: !(V.Vector Point)-    -- | For each line, store the points in between each-    -- vertex. There is two points between each vertex, so-    -- _meshPatchWidth * (_meshPatchHeight + 1) points-  , _meshHorizontalSecondary :: !(V.Vector InterBezier)-    -- | For each colun, store the points in between each-    -- vertex. Two points between each vertex, so-    -- _meshPatchHeight * (_meshPatchWidth + 1)-  , _meshVerticalSecondary :: !(V.Vector InterBezier)-    -- | Colors for each vertex points-  , _meshColors :: !(V.Vector px)-    -- | Points used to define tensor patch, if  not define,-    -- the rest of the data structure describes a Coon patch.-    -- size must be equal to `_meshPatchWidth*_meshPatchHeight`-  , _meshTensorDerivatives :: !(Maybe (V.Vector Derivatives))-  }-  deriving (Eq, Show, Functor)---- | Store the two bezier control points of a bezier.-data InterBezier = InterBezier -  { _inter0 :: !Point-  , _inter1 :: !Point-  }-  deriving (Eq, Show)--instance Transformable InterBezier where-  transform f (InterBezier a b) = InterBezier (f a) (f b)-  transformM f (InterBezier a b) = InterBezier <$> f a <*> f b--instance PointFoldable InterBezier where-  foldPoints f acc (InterBezier a b) = f (f acc a) b--transformMeshM :: Monad m => (Point -> m Point) -> MeshPatch px -> m (MeshPatch px)-transformMeshM f MeshPatch { .. } = do-  vertices <- mapM f _meshPrimaryVertices-  hSecondary <- mapM (transformM f) _meshHorizontalSecondary-  vSecondary <- mapM (transformM f) _meshVerticalSecondary-  return $ MeshPatch-      { _meshPatchWidth = _meshPatchWidth -      , _meshPatchHeight = _meshPatchHeight-      , _meshPrimaryVertices = vertices -      , _meshHorizontalSecondary = hSecondary -      , _meshVerticalSecondary = vSecondary-      , _meshColors = _meshColors-      , _meshTensorDerivatives = Nothing-      }--instance {-# OVERLAPPING  #-} Transformable (MeshPatch px) where-  transformM = transformMeshM--instance {-# OVERLAPPING  #-} PointFoldable (MeshPatch px) where-  foldPoints = foldMeshPoints--foldMeshPoints :: (a -> Point -> a) -> a -> MeshPatch px -> a-foldMeshPoints f acc m = acc4 where-  acc1 = V.foldl' f acc (_meshPrimaryVertices m)-  acc2 = foldPoints f acc1 (_meshHorizontalSecondary m)-  acc3 = foldPoints f acc2 (_meshVerticalSecondary m)-  acc4 = case _meshTensorDerivatives m of-    Nothing -> acc3-    Just v -> foldPoints f acc3 v---- | Store the inner points of a tensor patch.-data Derivatives = Derivatives-  { _interNorthWest :: !Point-  , _interNorthEast :: !Point-  , _interSouthWest :: !Point-  , _interSouthEast :: !Point-  }-  deriving (Eq, Show)--instance Transformable Derivatives where-  transform f (Derivatives a b c d) =-     Derivatives (f a) (f b) (f c) (f d)-  transformM f (Derivatives a b c d) =-     Derivatives <$> f a <*> f b <*> f c <*> f d--instance PointFoldable Derivatives where-  foldPoints f acc (Derivatives a b c d) = f (f (f (f acc a) b) c) d---- | Represent a point in the paramaetric U,V space--- from [0, 1]^2-type UV = V2 CoonColorWeight---- | Define a rectangle in the U,V parametric space.-type UVPatch = ParametricValues UV---- | Store information for cubic interpolation in a patch.-newtype CubicCoefficient px = CubicCoefficient-    { getCubicCoefficients :: ParametricValues (V4 (Holder px Float))-    }---- | Type storing the information to be able to interpolate--- part of an image in a patch.-data ImageMesh px = ImageMesh-    { _meshImage :: !(Image px)-    , _meshTransform :: !Transformation-    }---- C1: top      _north--- C2: bottom   _south--- D1: left     _west--- D2: right    _east---- | Return a postion of a point in the coon patch.-coonPointAt :: CoonPatch a -> UV -> Point-coonPointAt CoonPatch { .. } (V2 u v) = sc ^+^ sd ^-^ sb-  where-    CubicBezier c10 _ _ c11 = _north-    CubicBezier c21 _ _ c20 = _south--    sc = lerp v c2 c1-    sd = lerp u d2 d1-    sb = lerp v (lerp u c21 c20)-                (lerp u c11 c10)--    CubicBezier _ _ _ c1 = fst $ cubicBezierBreakAt _north u-    CubicBezier _ _ _ c2 = fst $ cubicBezierBreakAt _south (1 - u)--    CubicBezier _ _ _ d2 = fst $ cubicBezierBreakAt _east v-    CubicBezier _ _ _ d1 = fst $ cubicBezierBreakAt _west (1 - v)---- | Convert a coon patch in-toTensorPatch :: CoonPatch a -> TensorPatch a-toTensorPatch CoonPatch { .. } = TensorPatch-    { _curve0 = _north-    , _curve1 = CubicBezier wt p11 p21 et-    , _curve2 = CubicBezier wb p12 p22 eb-    , _curve3 = CubicBezier sd  sc  sb sa-    , _tensorValues = _coonValues-    }-  where-    formula a b c d e f g h =-      (a ^* (-4) ^+^-       (b ^+^ c) ^* 6 ^-^-       (d ^+^ e) ^* 2 ^+^-       (f ^+^ g) ^* 3 ^-^-       h) ^* (1/9)--    p11 = formula p00 p10 p01 p30 p03 p13 p31 p33-    p21 = formula p30 p20 p31 p00 p33 p23 p01 p03-    p12 = formula p03 p13 p02 p33 p00 p10 p32 p30-    p22 = formula p33 p23 p32 p03 p30 p20 p02 p00--    CubicBezier p00 p10 p20 p30 = _north-    CubicBezier _ p02 p01 _ = _west-    CubicBezier _ p31 p32 _ = _east-    CubicBezier p33 p23 p13 p03 = _south--    CubicBezier sa sb sc sd = _south-    CubicBezier _ et eb _ = _east-    CubicBezier _ wb wt _ = _west--+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeFamilies #-}
+module Graphics.Rasterific.PatchTypes
+  ( -- * New geometry
+    CoonPatch( .. )
+  , TensorPatch( .. )
+  , MeshPatch( .. )
+  , InterBezier( .. )
+
+    -- * Types
+  , CoonColorWeight
+  , PatchInterpolation( .. )
+  , ParametricValues( .. )
+  , Derivative( .. )
+  , Derivatives( .. )
+  , UV
+  , UVPatch
+  , CubicCoefficient( .. )
+  , ImageMesh( .. )
+
+    -- * Helper functions
+  , transposeParametricValues 
+  , coonPointAt
+  , toTensorPatch
+  , foldMeshPoints
+  , isVerticalOrientation
+
+    -- * Lenses
+  , xDerivative
+  , yDerivative
+  ) where
+
+import Data.Monoid( (<>) )
+import qualified Data.Vector as V
+
+import Codec.Picture( Image )
+
+import Graphics.Rasterific.CubicBezier
+import Graphics.Rasterific.MiniLens
+import Graphics.Rasterific.Linear
+import Graphics.Rasterific.Types
+import Graphics.Rasterific.Compositor
+import Graphics.Rasterific.Transformations
+
+-- | Type of coordinate interpolation
+type CoonColorWeight = Float
+
+-- | How do we want to perform color/image interpolation
+-- within the patch.
+data PatchInterpolation
+  = -- | Bilinear interpolation
+    --
+    -- @
+    -- import qualified Data.Vector as V
+    -- let colorCycle = cycle
+    --       [ PixelRGBA8 0 0x86 0xc1 255
+    --       , PixelRGBA8 0xff 0xf4 0xc1 255
+    --       , PixelRGBA8 0xFF 0x53 0x73 255
+    --       , PixelRGBA8 0xff 0xf4 0xc1 255
+    --       , PixelRGBA8 0 0x86 0xc1 255]
+    --     colors = V.fromListN (4 * 4) colorCycle
+    -- renderMeshPatch PatchBilinear $ generateLinearGrid 3 3 (V2 10 10) (V2 60 60) colors
+    -- @
+    --
+    -- <<docimages/mesh_patch_interp_bilinear.png>>
+    --
+    PatchBilinear
+    -- | Bicubic interpolation
+    --
+    -- @
+    -- import qualified Data.Vector as V
+    -- let colorCycle = cycle
+    --       [ PixelRGBA8 0 0x86 0xc1 255
+    --       , PixelRGBA8 0xff 0xf4 0xc1 255
+    --       , PixelRGBA8 0xFF 0x53 0x73 255
+    --       , PixelRGBA8 0xff 0xf4 0xc1 255
+    --       , PixelRGBA8 0 0x86 0xc1 255]
+    --     colors = V.fromListN (4 * 4) colorCycle
+    -- renderMeshPatch PatchBicubic $ generateLinearGrid 3 3 (V2 10 10) (V2 60 60) colors
+    -- @
+    --
+    -- <<docimages/mesh_patch_interp_bicubic.png>>
+    --
+  | PatchBicubic
+  deriving (Eq, Show)
+
+-- | Values associated to the corner of a patch
+--
+-- @
+--  North               East
+--      +--------------+
+--      |0            1|
+--      |              |
+--      |              |
+--      |              |
+--      |3            2|
+--      +--------------+
+--  West                South
+-- @
+--
+data ParametricValues a = ParametricValues
+  { _northValue :: !a
+  , _eastValue  :: !a
+  , _southValue :: !a
+  , _westValue  :: !a
+  }
+  deriving (Functor, Show)
+
+-- | Store the derivative necessary for cubic interpolation in
+-- the gradient mesh.
+data Derivative px = Derivative
+  { _derivValues :: !(Holder px Float)
+  , _xDerivative :: !(Holder px Float)
+  , _yDerivative :: !(Holder px Float)
+  , _xyDerivative :: !(Holder px Float)
+  }
+
+deriving instance Show (Holder px Float) => Show (Derivative px)
+
+-- | Helping lens
+xDerivative :: Lens' (Derivative px) (Holder px Float)
+xDerivative = lens _xDerivative setter where
+  setter o v = o { _xDerivative = v }
+
+-- | Help lens
+yDerivative :: Lens' (Derivative px) (Holder px Float)
+yDerivative = lens _yDerivative setter where
+  setter o v = o { _yDerivative = v }
+
+instance Applicative ParametricValues where
+    pure a = ParametricValues a a a a
+    ParametricValues n e s w <*> ParametricValues n' e' s' w' =
+        ParametricValues (n n') (e e') (s s') (w w')
+
+instance Foldable ParametricValues where
+  foldMap f (ParametricValues n e s w) = f n <> f e <> f s <> f w
+
+-- | Transpose (switch vertical/horizontal orientation) of values.
+transposeParametricValues :: ParametricValues a -> ParametricValues a
+transposeParametricValues (ParametricValues n e s w) = ParametricValues n w s e
+
+-- | Describe a tensor patch
+data TensorPatch weight = TensorPatch
+  { _curve0 :: !CubicBezier
+  , _curve1 :: !CubicBezier
+  , _curve2 :: !CubicBezier
+  , _curve3 :: !CubicBezier
+  , _tensorValues :: !weight
+  }
+
+isVerticalOrientation :: TensorPatch a -> Bool
+isVerticalOrientation p = dy > dx where
+  CubicBezier a _ _ d = _curve0 p
+  V2 dx dy = abs <$> (d ^-^ a)
+
+instance Transformable (TensorPatch px) where
+  transform f (TensorPatch c0 c1 c2 c3 v) =
+    TensorPatch
+        (transform f c0)
+        (transform f c1)
+        (transform f c2)
+        (transform f c3)
+        v
+  transformM f (TensorPatch c0 c1 c2 c3 v) =
+    TensorPatch
+        <$> transformM f c0
+        <*> transformM f c1
+        <*> transformM f c2
+        <*> transformM f c3
+        <*> return v
+
+
+instance {-# OVERLAPPING #-} PointFoldable (TensorPatch px) where
+  foldPoints f acc (TensorPatch c0 c1 c2 c3 _) = g c3 . g c2 . g c1 $ g c0 acc
+    where g v a = foldPoints f a v
+
+-- | Define the boundary and interpolated values of a coon patch.
+--
+-- @
+--                        ----->
+--                  North     _____----------------+
+--   ^          +------------//                     // .
+--   |         //                                  //       |
+--   |        //                                  //        |
+--   |       //                                  //  east   |
+--   | west |                                  /          |
+--          |                                 |           v
+--           \\                                 \\   .
+--            \\                  __-------------+
+--             +----------------/
+--                    South
+--                       <-----
+-- @
+--
+data CoonPatch weight = CoonPatch
+    { _north :: !CubicBezier -- ^ North border, from left to right at top
+    , _east :: !CubicBezier  -- ^ East obrder, from top to bottom
+    , _south :: !CubicBezier -- ^ South border from right to left
+    , _west :: !CubicBezier  -- ^ West border from bottom to top
+    , _coonValues :: !weight -- ^ The patch values
+    }
+    deriving Show
+
+instance {-# OVERLAPPING #-} Transformable (CoonPatch px) where
+  transformM = transformCoonM
+  transform = transformCoon 
+
+instance {-# OVERLAPPING #-} PointFoldable (CoonPatch px) where
+  foldPoints f acc (CoonPatch n e s w _) = g n . g e . g s $ g w acc
+    where g v a = foldPoints f a v
+
+transformCoonM :: Monad m => (Point -> m Point) -> CoonPatch px -> m (CoonPatch px)
+transformCoonM f (CoonPatch n e s w v) =
+  CoonPatch <$> transformM f n <*> transformM f e <*> transformM f s <*> transformM f w
+            <*> return v
+
+transformCoon :: (Point -> Point) -> CoonPatch px -> CoonPatch px
+transformCoon f (CoonPatch n e s w v) =
+    CoonPatch
+        (transform f n)
+        (transform f e)
+        (transform f s)
+        (transform f w)
+        v
+
+-- | Define a mesh patch grid, the grid is conceptually
+-- a regular grid of _meshPatchWidth * _meshPatchHeight
+-- patches but with shared edges
+data MeshPatch px = MeshPatch
+  { -- | Count of horizontal of *patch*
+    _meshPatchWidth  :: !Int
+    -- | Count of vertical of *patch*
+  , _meshPatchHeight :: !Int
+    -- | Main points defining the patch, of size
+    -- (_meshPatchWidth + 1) * (_meshPatchHeight + 1)
+  , _meshPrimaryVertices :: !(V.Vector Point)
+    -- | For each line, store the points in between each
+    -- vertex. There is two points between each vertex, so
+    -- _meshPatchWidth * (_meshPatchHeight + 1) points
+  , _meshHorizontalSecondary :: !(V.Vector InterBezier)
+    -- | For each colun, store the points in between each
+    -- vertex. Two points between each vertex, so
+    -- _meshPatchHeight * (_meshPatchWidth + 1)
+  , _meshVerticalSecondary :: !(V.Vector InterBezier)
+    -- | Colors for each vertex points
+  , _meshColors :: !(V.Vector px)
+    -- | Points used to define tensor patch, if  not define,
+    -- the rest of the data structure describes a Coon patch.
+    -- size must be equal to `_meshPatchWidth*_meshPatchHeight`
+  , _meshTensorDerivatives :: !(Maybe (V.Vector Derivatives))
+  }
+  deriving (Eq, Show, Functor)
+
+-- | Store the two bezier control points of a bezier.
+data InterBezier = InterBezier 
+  { _inter0 :: !Point
+  , _inter1 :: !Point
+  }
+  deriving (Eq, Show)
+
+instance Transformable InterBezier where
+  transform f (InterBezier a b) = InterBezier (f a) (f b)
+  transformM f (InterBezier a b) = InterBezier <$> f a <*> f b
+
+instance PointFoldable InterBezier where
+  foldPoints f acc (InterBezier a b) = f (f acc a) b
+
+transformMeshM :: Monad m => (Point -> m Point) -> MeshPatch px -> m (MeshPatch px)
+transformMeshM f MeshPatch { .. } = do
+  vertices <- mapM f _meshPrimaryVertices
+  hSecondary <- mapM (transformM f) _meshHorizontalSecondary
+  vSecondary <- mapM (transformM f) _meshVerticalSecondary
+  return $ MeshPatch
+      { _meshPatchWidth = _meshPatchWidth 
+      , _meshPatchHeight = _meshPatchHeight
+      , _meshPrimaryVertices = vertices 
+      , _meshHorizontalSecondary = hSecondary 
+      , _meshVerticalSecondary = vSecondary
+      , _meshColors = _meshColors
+      , _meshTensorDerivatives = Nothing
+      }
+
+instance {-# OVERLAPPING  #-} Transformable (MeshPatch px) where
+  transformM = transformMeshM
+
+instance {-# OVERLAPPING  #-} PointFoldable (MeshPatch px) where
+  foldPoints = foldMeshPoints
+
+foldMeshPoints :: (a -> Point -> a) -> a -> MeshPatch px -> a
+foldMeshPoints f acc m = acc4 where
+  acc1 = V.foldl' f acc (_meshPrimaryVertices m)
+  acc2 = foldPoints f acc1 (_meshHorizontalSecondary m)
+  acc3 = foldPoints f acc2 (_meshVerticalSecondary m)
+  acc4 = case _meshTensorDerivatives m of
+    Nothing -> acc3
+    Just v -> foldPoints f acc3 v
+
+-- | Store the inner points of a tensor patch.
+data Derivatives = Derivatives
+  { _interNorthWest :: !Point
+  , _interNorthEast :: !Point
+  , _interSouthWest :: !Point
+  , _interSouthEast :: !Point
+  }
+  deriving (Eq, Show)
+
+instance Transformable Derivatives where
+  transform f (Derivatives a b c d) =
+     Derivatives (f a) (f b) (f c) (f d)
+  transformM f (Derivatives a b c d) =
+     Derivatives <$> f a <*> f b <*> f c <*> f d
+
+instance PointFoldable Derivatives where
+  foldPoints f acc (Derivatives a b c d) = f (f (f (f acc a) b) c) d
+
+-- | Represent a point in the paramaetric U,V space
+-- from [0, 1]^2
+type UV = V2 CoonColorWeight
+
+-- | Define a rectangle in the U,V parametric space.
+type UVPatch = ParametricValues UV
+
+-- | Store information for cubic interpolation in a patch.
+newtype CubicCoefficient px = CubicCoefficient
+    { getCubicCoefficients :: ParametricValues (V4 (Holder px Float))
+    }
+
+-- | Type storing the information to be able to interpolate
+-- part of an image in a patch.
+data ImageMesh px = ImageMesh
+    { _meshImage :: !(Image px)
+    , _meshTransform :: !Transformation
+    }
+
+-- C1: top      _north
+-- C2: bottom   _south
+-- D1: left     _west
+-- D2: right    _east
+
+-- | Return a postion of a point in the coon patch.
+coonPointAt :: CoonPatch a -> UV -> Point
+coonPointAt CoonPatch { .. } (V2 u v) = sc ^+^ sd ^-^ sb
+  where
+    CubicBezier c10 _ _ c11 = _north
+    CubicBezier c21 _ _ c20 = _south
+
+    sc = lerp v c2 c1
+    sd = lerp u d2 d1
+    sb = lerp v (lerp u c21 c20)
+                (lerp u c11 c10)
+
+    CubicBezier _ _ _ c1 = fst $ cubicBezierBreakAt _north u
+    CubicBezier _ _ _ c2 = fst $ cubicBezierBreakAt _south (1 - u)
+
+    CubicBezier _ _ _ d2 = fst $ cubicBezierBreakAt _east v
+    CubicBezier _ _ _ d1 = fst $ cubicBezierBreakAt _west (1 - v)
+
+-- | Convert a coon patch in
+toTensorPatch :: CoonPatch a -> TensorPatch a
+toTensorPatch CoonPatch { .. } = TensorPatch
+    { _curve0 = _north
+    , _curve1 = CubicBezier wt p11 p21 et
+    , _curve2 = CubicBezier wb p12 p22 eb
+    , _curve3 = CubicBezier sd  sc  sb sa
+    , _tensorValues = _coonValues
+    }
+  where
+    formula a b c d e f g h =
+      (a ^* (-4) ^+^
+       (b ^+^ c) ^* 6 ^-^
+       (d ^+^ e) ^* 2 ^+^
+       (f ^+^ g) ^* 3 ^-^
+       h) ^* (1/9)
+
+    p11 = formula p00 p10 p01 p30 p03 p13 p31 p33
+    p21 = formula p30 p20 p31 p00 p33 p23 p01 p03
+    p12 = formula p03 p13 p02 p33 p00 p10 p32 p30
+    p22 = formula p33 p23 p32 p03 p30 p20 p02 p00
+
+    CubicBezier p00 p10 p20 p30 = _north
+    CubicBezier _ p02 p01 _ = _west
+    CubicBezier _ p31 p32 _ = _east
+    CubicBezier p33 p23 p13 p03 = _south
+
+    CubicBezier sa sb sc sd = _south
+    CubicBezier _ et eb _ = _east
+    CubicBezier _ wb wt _ = _west
+
+
src/Graphics/Rasterific/Texture.hs view
@@ -1,180 +1,180 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ConstraintKinds #-}---- | Module describing the various filling method of the--- geometric primitives.------ All points coordinate given in this module are expressed--- final image pixel coordinates.-module Graphics.Rasterific.Texture-    ( Texture-    , Gradient-    , withSampler-    , uniformTexture-      -- * Texture kind-    , linearGradientTexture-    , radialGradientTexture-    , radialGradientWithFocusTexture-    , sampledImageTexture-    , patternTexture-    , meshPatchTexture--      -- * Texture manipulation-    , modulateTexture-    , transformTexture -    ) where---import Codec.Picture.Types( Pixel( .. ), Image( .. ) )-import Graphics.Text.TrueType( Dpi )-import Graphics.Rasterific-import Graphics.Rasterific.MeshPatch-import Graphics.Rasterific.Command-import Graphics.Rasterific.Transformations---- | Set the repeat pattern of the texture (if any).--- With padding:------ > withTexture (sampledImageTexture textureImage) $--- >   fill $ rectangle (V2 0 0) 200 200------ <<docimages/sampled_texture_pad.png>>------ With repeat:------ > withTexture (withSampler SamplerRepeat $--- >                 sampledImageTexture textureImage) $--- >     fill $ rectangle (V2 0 0) 200 200------ <<docimages/sampled_texture_repeat.png>>------ With reflect:------ > withTexture (withSampler SamplerReflect $--- >                 sampledImageTexture textureImage) $--- >     fill $ rectangle (V2 0 0) 200 200------ <<docimages/sampled_texture_reflect.png>>----withSampler :: SamplerRepeat -> Texture px -> Texture px-withSampler = WithSampler---- | Transform the coordinates used for texture before applying--- it, allow interesting transformations.------ > withTexture (withSampler SamplerRepeat $--- >             transformTexture (rotateCenter 1 (V2 0 0) <> --- >                               scale 0.5 0.25)--- >             $ sampledImageTexture textureImage) $--- >     fill $ rectangle (V2 0 0) 200 200------ <<docimages/sampled_texture_scaled.png>>----transformTexture :: Transformation -> Texture px -> Texture px-transformTexture = WithTextureTransform---- | The uniform texture is the simplest texture of all:--- an uniform color.-uniformTexture :: px -- ^ The color used for all the texture.-               -> Texture px-uniformTexture = SolidTexture----- | Texture using a mesh patch as definition-meshPatchTexture :: PatchInterpolation -> MeshPatch px -> Texture px-meshPatchTexture = MeshPatchTexture---- | Linear gradient texture.------ > let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255)--- >               ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255)--- >               ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in--- > withTexture (linearGradientTexture SamplerPad gradDef--- >                        (V2 40 40) (V2 130 130)) $--- >    fill $ circle (V2 100 100) 100------ <<docimages/linear_gradient.png>>----linearGradientTexture :: Gradient px -- ^ Gradient description.-                      -> Point       -- ^ Linear gradient start point.-                      -> Point       -- ^ Linear gradient end point.-                      -> Texture px-linearGradientTexture gradient start end =-    LinearGradientTexture gradient (Line start end)---- | Use another image as a texture for the filling.--- Contrary to `imageTexture`, this function perform a bilinear--- filtering on the texture.----sampledImageTexture :: Image px -> Texture px-sampledImageTexture = SampledTexture---- | Radial gradient texture------ > let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255)--- >               ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255)--- >               ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in--- > withTexture (radialGradientTexture gradDef--- >                    (V2 100 100) 75) $--- >    fill $ circle (V2 100 100) 100------ <<docimages/radial_gradient.png>>----radialGradientTexture :: Gradient px -- ^ Gradient description-                      -> Point       -- ^ Radial gradient center-                      -> Float       -- ^ Radial gradient radius-                      -> Texture px-radialGradientTexture = RadialGradientTexture---- | Radial gradient texture with a focus point.------ > let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255)--- >               ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255)--- >               ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in--- > withTexture (radialGradientWithFocusTexture gradDef--- >                    (V2 100 100) 75 (V2 70 70) ) $--- >    fill $ circle (V2 100 100) 100------ <<docimages/radial_gradient_focus.png>>----radialGradientWithFocusTexture-    :: Gradient px -- ^ Gradient description-    -> Point      -- ^ Radial gradient center-    -> Float      -- ^ Radial gradient radius-    -> Point      -- ^ Radial gradient focus point-    -> Texture px-radialGradientWithFocusTexture = RadialGradientWithFocusTexture---- | Perform a multiplication operation between a full color texture--- and a greyscale one, used for clip-path implementation.-modulateTexture :: Texture px                       -- ^ The full blown texture.-                -> Texture (PixelBaseComponent px)  -- ^ A greyscale modulation texture.-                -> Texture px                       -- ^ The resulting texture.-modulateTexture = ModulateTexture----- | Use a drawing as a repeating background pattern.------ > let pattern =--- >       patternTexture 40 40 96 (PixelRGBA8 0xFF 0x53 0x73 255) .--- >         withTexture (uniformTexture $ PixelRGBA8 0 0x86 0xc1 255) $--- >           fill $ circle (V2 20 20) 13--- > in--- > withTexture pattern $--- >   fill $ roundedRectangle (V2 20 20) 160 160 20 20------ <<docimages/pattern_texture.png>>----patternTexture :: RenderablePixel px-               => Int           -- ^ Width-               -> Int           -- ^ Height-               -> Dpi           -- ^ Dpi if text is present in pattern-               -> px            -- ^ Pattern background color-               -> Drawing px () -- ^ Drawing defining the pattern-               -> Texture px-patternTexture w h dpi back drawing =-    PatternTexture w h back drawing $-        renderDrawingAtDpi w h dpi back drawing-+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE ConstraintKinds #-}
+
+-- | Module describing the various filling method of the
+-- geometric primitives.
+--
+-- All points coordinate given in this module are expressed
+-- final image pixel coordinates.
+module Graphics.Rasterific.Texture
+    ( Texture
+    , Gradient
+    , withSampler
+    , uniformTexture
+      -- * Texture kind
+    , linearGradientTexture
+    , radialGradientTexture
+    , radialGradientWithFocusTexture
+    , sampledImageTexture
+    , patternTexture
+    , meshPatchTexture
+
+      -- * Texture manipulation
+    , modulateTexture
+    , transformTexture 
+    ) where
+
+
+import Codec.Picture.Types( Pixel( .. ), Image( .. ) )
+import Graphics.Text.TrueType( Dpi )
+import Graphics.Rasterific
+import Graphics.Rasterific.MeshPatch
+import Graphics.Rasterific.Command
+import Graphics.Rasterific.Transformations
+
+-- | Set the repeat pattern of the texture (if any).
+-- With padding:
+--
+-- > withTexture (sampledImageTexture textureImage) $
+-- >   fill $ rectangle (V2 0 0) 200 200
+--
+-- <<docimages/sampled_texture_pad.png>>
+--
+-- With repeat:
+--
+-- > withTexture (withSampler SamplerRepeat $
+-- >                 sampledImageTexture textureImage) $
+-- >     fill $ rectangle (V2 0 0) 200 200
+--
+-- <<docimages/sampled_texture_repeat.png>>
+--
+-- With reflect:
+--
+-- > withTexture (withSampler SamplerReflect $
+-- >                 sampledImageTexture textureImage) $
+-- >     fill $ rectangle (V2 0 0) 200 200
+--
+-- <<docimages/sampled_texture_reflect.png>>
+--
+withSampler :: SamplerRepeat -> Texture px -> Texture px
+withSampler = WithSampler
+
+-- | Transform the coordinates used for texture before applying
+-- it, allow interesting transformations.
+--
+-- > withTexture (withSampler SamplerRepeat $
+-- >             transformTexture (rotateCenter 1 (V2 0 0) <> 
+-- >                               scale 0.5 0.25)
+-- >             $ sampledImageTexture textureImage) $
+-- >     fill $ rectangle (V2 0 0) 200 200
+--
+-- <<docimages/sampled_texture_scaled.png>>
+--
+transformTexture :: Transformation -> Texture px -> Texture px
+transformTexture = WithTextureTransform
+
+-- | The uniform texture is the simplest texture of all:
+-- an uniform color.
+uniformTexture :: px -- ^ The color used for all the texture.
+               -> Texture px
+uniformTexture = SolidTexture
+
+
+-- | Texture using a mesh patch as definition
+meshPatchTexture :: PatchInterpolation -> MeshPatch px -> Texture px
+meshPatchTexture = MeshPatchTexture
+
+-- | Linear gradient texture.
+--
+-- > let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255)
+-- >               ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255)
+-- >               ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in
+-- > withTexture (linearGradientTexture SamplerPad gradDef
+-- >                        (V2 40 40) (V2 130 130)) $
+-- >    fill $ circle (V2 100 100) 100
+--
+-- <<docimages/linear_gradient.png>>
+--
+linearGradientTexture :: Gradient px -- ^ Gradient description.
+                      -> Point       -- ^ Linear gradient start point.
+                      -> Point       -- ^ Linear gradient end point.
+                      -> Texture px
+linearGradientTexture gradient start end =
+    LinearGradientTexture gradient (Line start end)
+
+-- | Use another image as a texture for the filling.
+-- Contrary to `imageTexture`, this function perform a bilinear
+-- filtering on the texture.
+--
+sampledImageTexture :: Image px -> Texture px
+sampledImageTexture = SampledTexture
+
+-- | Radial gradient texture
+--
+-- > let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255)
+-- >               ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255)
+-- >               ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in
+-- > withTexture (radialGradientTexture gradDef
+-- >                    (V2 100 100) 75) $
+-- >    fill $ circle (V2 100 100) 100
+--
+-- <<docimages/radial_gradient.png>>
+--
+radialGradientTexture :: Gradient px -- ^ Gradient description
+                      -> Point       -- ^ Radial gradient center
+                      -> Float       -- ^ Radial gradient radius
+                      -> Texture px
+radialGradientTexture = RadialGradientTexture
+
+-- | Radial gradient texture with a focus point.
+--
+-- > let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255)
+-- >               ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255)
+-- >               ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in
+-- > withTexture (radialGradientWithFocusTexture gradDef
+-- >                    (V2 100 100) 75 (V2 70 70) ) $
+-- >    fill $ circle (V2 100 100) 100
+--
+-- <<docimages/radial_gradient_focus.png>>
+--
+radialGradientWithFocusTexture
+    :: Gradient px -- ^ Gradient description
+    -> Point      -- ^ Radial gradient center
+    -> Float      -- ^ Radial gradient radius
+    -> Point      -- ^ Radial gradient focus point
+    -> Texture px
+radialGradientWithFocusTexture = RadialGradientWithFocusTexture
+
+-- | Perform a multiplication operation between a full color texture
+-- and a greyscale one, used for clip-path implementation.
+modulateTexture :: Texture px                       -- ^ The full blown texture.
+                -> Texture (PixelBaseComponent px)  -- ^ A greyscale modulation texture.
+                -> Texture px                       -- ^ The resulting texture.
+modulateTexture = ModulateTexture
+
+
+-- | Use a drawing as a repeating background pattern.
+--
+-- > let pattern =
+-- >       patternTexture 40 40 96 (PixelRGBA8 0xFF 0x53 0x73 255) .
+-- >         withTexture (uniformTexture $ PixelRGBA8 0 0x86 0xc1 255) $
+-- >           fill $ circle (V2 20 20) 13
+-- > in
+-- > withTexture pattern $
+-- >   fill $ roundedRectangle (V2 20 20) 160 160 20 20
+--
+-- <<docimages/pattern_texture.png>>
+--
+patternTexture :: RenderablePixel px
+               => Int           -- ^ Width
+               -> Int           -- ^ Height
+               -> Dpi           -- ^ Dpi if text is present in pattern
+               -> px            -- ^ Pattern background color
+               -> Drawing px () -- ^ Drawing defining the pattern
+               -> Texture px
+patternTexture w h dpi back drawing =
+    PatternTexture w h back drawing $
+        renderDrawingAtDpi w h dpi back drawing
+