 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE RecordWildCards #-}
-module NanoVG.Internal where
-
-import           Data.Bits
+module NanoVG.Internal
+  ( FileName(..)
+  , Image(..)
+  , Font(..)
+  , Context(..)
+  , Transformation(..)
+  , Extent(..)
+  , Color(..)
+  , Paint(..)
+  , Bounds(..)
+  , GlyphPosition(..)
+  , GlyphPositionPtr
+  , TextRow(..)
+  , TextRowPtr
+  , CreateFlags(..)
+  , Solidity(..)
+  , LineCap(..)
+  , Align(..)
+  , Winding(..)
+  , beginFrame
+  , cancelFrame
+  , endFrame
+  -- * Color utils
+  , rgb
+  , rgbf
+  , rgba
+  , rgbaf
+  , lerpRGBA
+  , transRGBA
+  , transRGBAf
+  , hsl
+  , hsla
+  -- * State handling
+  , save
+  , restore
+  , reset
+  -- * Render styles
+  , strokeColor
+  , strokePaint
+  , fillColor
+  , fillPaint
+  , miterLimit
+  , strokeWidth
+  , lineCap
+  , lineJoin
+  , globalAlpha
+  -- * Transforms
+  , resetTransform
+  , transform
+  , translate
+  , rotate
+  , skewX
+  , skewY
+  , scale
+  , currentTransform
+  , transformIdentity
+  , transformTranslate
+  , transformScale
+  , transformRotate
+  , transformSkewX
+  , transformSkewY
+  , transformMultiply
+  , transformPremultiply
+  , transformInverse
+  , transformPoint
+  , degToRad
+  , radToDeg
+  -- * Images
+  , createImage
+  , createImageMem
+  , createImageRGBA
+  , updateImage
+  , imageSize
+  , deleteImage
+  -- * Paints
+  , linearGradient
+  , boxGradient
+  , radialGradient
+  , imagePattern
+  -- * Scissoring
+  , scissor
+  , intersectScissor
+  , resetScissor
+  -- * Paths
+  , beginPath
+  , moveTo
+  , lineTo
+  , bezierTo
+  , quadTo
+  , arcTo
+  , closePath
+  , pathWinding
+  , arc
+  , rect
+  , roundedRect
+  , ellipse
+  , circle
+  , fill
+  , stroke
+  -- * Text
+  , createFont
+  , createFontMem
+  , findFont
+  , fontSize
+  , fontBlur
+  , textLetterSpacing
+  , textLineHeight
+  , textAlign
+  , fontFaceId
+  , fontFace
+  , text
+  , textBox
+  , textBounds
+  , textBoxBounds
+  , textGlyphPositions
+  , textMetrics
+  , textBreakLines
+  -- * GL
+  , createGL3
+  , deleteGL3
+  , createImageFromHandleGL3
+  , imageHandleGL3
+  ) where
+
+import           Data.Bits hiding (rotate)
 import           Data.ByteString hiding (null)
 import qualified Data.Set as S
 import qualified Data.Text as T

allocaBounds :: (Ptr CFloat -> IO b) -> IO b
allocaBounds f = alloca (\(p :: Ptr Bounds) -> f (castPtr p))

withBounds :: Bounds -> (Ptr CFloat -> IO b) -> IO b
withBounds t f = with t (\p -> f (castPtr p)) 

{#fun unsafe nvgTextBounds as textBounds
        {`Context',`CFloat',`CFloat',withCString*`T.Text',null-`Ptr CUChar', allocaBounds-`Bounds'peekBounds*} -> `()'#}

{#fun unsafe nvgTextBoxBounds as textBoxBounds
        {`Context',`CFloat',`CFloat',`CFloat',withCString*`T.Text',null-`Ptr CUChar',allocaBounds-`Bounds'peekBounds*} -> `()'#}

-- TODO: This should probably take a vector
{#fun unsafe nvgTextGlyphPositions as textGlyphPositions
        {`Context',`CFloat',`CFloat',id`Ptr CChar',id`Ptr CChar',`GlyphPositionPtr', `CInt'} -> `CInt'#}

{#fun unsafe nvgTextMetrics as textMetrics
        {`Context',alloca-`CFloat'peek*,alloca-`CFloat'peek*,alloca-`CFloat'peek*} -> `()'#}

-- TODO: This should probably take a vector
{#fun unsafe nvgTextBreakLines as textBreakLines
        {`Context',id`Ptr CChar',id`Ptr CChar',`CFloat',`TextRowPtr',`CInt'} -> `CInt'#}


withTransformation :: Transformation -> (Ptr CFloat -> IO b) -> IO b
withTransformation t f = with t (\p -> f (castPtr p)) 

-- | Returns the current transformation matrix.
{#fun unsafe nvgCurrentTransform as currentTransform
        {`Context',allocaTransformation-`Transformation'peekTransformation*} -> `()'#}

-- | Sets the transform to identity matrix.
{#fun unsafe nvgTransformIdentity as transformIdentity
        {allocaTransformation-`Transformation'peekTransformation*} -> `()'#}

-- | Sets the transform to translation matrix matrix.
{#fun unsafe nvgTransformTranslate as transformTranslate
        {allocaTransformation-`Transformation'peekTransformation*,`CFloat',`CFloat'} -> `()'#}

-- | Sets the transform to scale matrix.
{#fun unsafe nvgTransformScale as transformScale
        {allocaTransformation-`Transformation'peekTransformation*,`CFloat',`CFloat'} -> `()'#}

-- | Sets the transform to rotate matrix. Angle is specified in radians.
{#fun unsafe nvgTransformRotate as transformRotate
        {allocaTransformation-`Transformation'peekTransformation*,`CFloat'} -> `()'#}

-- | Sets the transform to skew-x matrix. Angle is specified in radians.
{#fun unsafe nvgTransformSkewX as transformSkewX
        {allocaTransformation-`Transformation'peekTransformation*,`CFloat'} -> `()'#}

-- | Sets the transform to skew-y matrix. Angle is specified in radians.
{#fun unsafe nvgTransformSkewY as transformSkewY
        {allocaTransformation-`Transformation'peekTransformation*,`CFloat'} -> `()'#}

-- | Sets the transform to the result of multiplication of two transforms, of A = A*B.
{#fun unsafe nvgTransformMultiply as transformMultiply
        {withTransformation*`Transformation'peekTransformation*,withTransformation*`Transformation'} -> `()'#}

-- | Sets the transform to the result of multiplication of two transforms, of A = B*A.
{#fun unsafe nvgTransformPremultiply as transformPremultiply
        {withTransformation*`Transformation'peekTransformation*,withTransformation*`Transformation'} -> `()'#}

-- | Sets the destination to inverse of specified transform.
-- Returns 1 if the inverse could be calculated, else 0.
{#fun unsafe nvgTransformInverse as transformInverse
        {allocaTransformation-`Transformation'peekTransformation*,withTransformation*`Transformation'} -> `()'#}

-- | Transform a point by given transform.
{#fun pure unsafe nvgTransformPoint as transformPoint
        {alloca-`CFloat'peek*,alloca-`CFloat'peek*,withTransformation*`Transformation',`CFloat',`CFloat'} -> `()'#}

-- | Converts degrees to radians.
{#fun pure unsafe nvgDegToRad as degToRad
        {`CFloat'} -> `CFloat'#}

-- | Converts radians to degrees.
{#fun pure unsafe nvgRadToDeg as radToDeg
        {`CFloat'} -> `CFloat'#}

