{-# 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