{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
module SDL.Video.Renderer
( Renderer
, RendererConfig(..)
, defaultRenderer
, RendererType(..)
, clear
, copy
, copyEx
, drawLine
, drawLines
, drawPoint
, drawPoints
, drawRect
, drawRects
, fillRect
, fillRects
, present
, rendererDrawBlendMode
, rendererDrawColor
, rendererRenderTarget
, rendererClipRect
, rendererLogicalSize
, rendererScale
, rendererViewport
, renderTargetSupported
, Surface(..)
, updateWindowSurface
, surfaceBlit
, surfaceBlitScaled
, surfaceFillRect
, surfaceFillRects
, convertSurface
, createRGBSurface
, createRGBSurfaceFrom
, freeSurface
, getWindowSurface
, loadBMP
, surfaceColorKey
, surfaceBlendMode
, surfaceDimensions
, surfaceFormat
, surfacePixels
, lockSurface
, unlockSurface
, Palette
, paletteNColors
, paletteColors
, paletteColor
, PixelFormat(..)
, SurfacePixelFormat
, formatPalette
, setPaletteColors
, pixelFormatToMasks
, masksToPixelFormat
, Texture
, createTexture
, TextureAccess(..)
, createTextureFromSurface
, updateTexture
, destroyTexture
, glBindTexture
, glUnbindTexture
, textureAlphaMod
, textureBlendMode
, BlendMode(..)
, textureColorMod
, lockTexture
, unlockTexture
, queryTexture
, TextureInfo(..)
, Rectangle(..)
, getRendererInfo
, RendererInfo(..)
, getRenderDriverInfo
) where
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Exception (catch, throw, SomeException, uninterruptibleMask_)
import Data.Bits
import Data.Data (Data)
import Data.Foldable
import Data.StateVar
import Data.Text (Text)
import Data.Typeable
import Data.Word
import Foreign.C.String
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Marshal.Alloc
import Foreign.Marshal.Utils
import Foreign.Ptr
import Foreign.Storable
import GHC.Generics (Generic)
import Prelude hiding (foldr)
import SDL.Vect
import SDL.Internal.Exception
import SDL.Internal.Numbered
import SDL.Internal.Types
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BSI
import qualified Data.Text.Encoding as Text
import qualified Data.Vector.Storable as SV
import qualified Data.Vector.Storable.Mutable as MSV
import qualified SDL.Raw as Raw
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative
import Data.Traversable
#endif
surfaceBlit :: MonadIO m
=> Surface
-> Maybe (Rectangle CInt)
-> Surface
-> Maybe (Point V2 CInt)
-> m (Maybe (Rectangle CInt))
surfaceBlit (Surface src _) srcRect (Surface dst _) dstLoc = liftIO $
maybeWith with srcRect $ \srcPtr ->
maybeWith with (fmap (flip Rectangle 0) dstLoc) $ \dstPtr -> do
_ <- throwIfNeg "SDL.Video.blitSurface" "SDL_BlitSurface" $
Raw.blitSurface src (castPtr srcPtr) dst (castPtr dstPtr)
maybe (pure Nothing) (\_ -> Just <$> peek dstPtr) dstLoc
createTexture :: (Functor m,MonadIO m)
=> Renderer
-> PixelFormat
-> TextureAccess
-> V2 CInt
-> m Texture
createTexture (Renderer r) fmt access (V2 w h) =
fmap Texture $
throwIfNull "SDL.Video.Renderer.createTexture" "SDL_CreateTexture" $
Raw.createTexture r (toNumber fmt) (toNumber access) w h
createTextureFromSurface :: (Functor m,MonadIO m)
=> Renderer
-> Surface
-> m Texture
createTextureFromSurface (Renderer r) (Surface s _) =
fmap Texture $
throwIfNull "SDL.Video.createTextureFromSurface" "SDL_CreateTextureFromSurface" $
Raw.createTextureFromSurface r s
glBindTexture :: (Functor m,MonadIO m)
=> Texture
-> m ()
glBindTexture (Texture t) =
throwIfNeg_ "SDL.Video.Renderer.glBindTexture" "SDL_GL_BindTexture" $
Raw.glBindTexture t nullPtr nullPtr
glUnbindTexture :: (Functor m,MonadIO m)
=> Texture
-> m ()
glUnbindTexture (Texture t) =
throwIfNeg_ "SDL.Video.Renderer.glUnindTexture" "SDL_GL_UnbindTexture" $
Raw.glUnbindTexture t
updateTexture :: (Functor m, MonadIO m)
=> Texture
-> Maybe (Rectangle CInt)
-> BS.ByteString
-> CInt
-> m Texture
updateTexture tex@(Texture t) rect pixels pitch = do
liftIO $ throwIfNeg_ "SDL.Video.updateTexture" "SDL_UpdateTexture" $
maybeWith with rect $ \rectPtr ->
let (pixelForeign, _, _) = BSI.toForeignPtr pixels
in withForeignPtr pixelForeign $ \pixelsPtr ->
Raw.updateTexture t (castPtr rectPtr) (castPtr pixelsPtr) pitch
return tex
destroyTexture :: MonadIO m => Texture -> m ()
destroyTexture (Texture t) = Raw.destroyTexture t
lockTexture :: MonadIO m
=> Texture
-> Maybe (Rectangle CInt)
-> m (Ptr (),CInt)
lockTexture (Texture t) rect = liftIO $
alloca $ \pixelsPtr ->
alloca $ \pitchPtr ->
maybeWith with rect $ \rectPtr -> do
throwIfNeg_ "lockTexture" "SDL_LockTexture" $
Raw.lockTexture t (castPtr rectPtr) pixelsPtr pitchPtr
pixels <- peek pixelsPtr
pitch <- peek pitchPtr
return (pixels, pitch)
unlockTexture :: MonadIO m => Texture -> m ()
unlockTexture (Texture t) = Raw.unlockTexture t
lockSurface :: MonadIO m => Surface -> m ()
lockSurface (Surface s _) =
throwIfNeg_ "lockSurface" "SDL_LockSurface" $
Raw.lockSurface s
unlockSurface :: MonadIO m => Surface -> m ()
unlockSurface (Surface s _) = Raw.unlockSurface s
data TextureAccess
= TextureAccessStatic
| TextureAccessStreaming
| TextureAccessTarget
deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)
instance FromNumber TextureAccess CInt where
fromNumber n' = case n' of
Raw.SDL_TEXTUREACCESS_STATIC -> TextureAccessStatic
Raw.SDL_TEXTUREACCESS_STREAMING -> TextureAccessStreaming
Raw.SDL_TEXTUREACCESS_TARGET -> TextureAccessTarget
_ -> error "Unknown value"
instance ToNumber TextureAccess CInt where
toNumber t = case t of
TextureAccessStatic -> Raw.SDL_TEXTUREACCESS_STATIC
TextureAccessStreaming -> Raw.SDL_TEXTUREACCESS_STREAMING
TextureAccessTarget -> Raw.SDL_TEXTUREACCESS_TARGET
data TextureInfo = TextureInfo
{ texturePixelFormat :: PixelFormat
, textureAccess :: TextureAccess
, textureWidth :: CInt
, textureHeight :: CInt
} deriving (Eq, Generic, Ord, Read, Show, Typeable)
queryTexture :: MonadIO m => Texture -> m TextureInfo
queryTexture (Texture tex) = liftIO $
alloca $ \pfPtr ->
alloca $ \acPtr ->
alloca $ \wPtr ->
alloca $ \hPtr -> do
throwIfNeg_ "SDL.Video.queryTexture" "SDL_QueryTexture" $
Raw.queryTexture tex pfPtr acPtr wPtr hPtr
TextureInfo <$>
fmap fromNumber (peek pfPtr) <*>
fmap fromNumber (peek acPtr) <*>
peek wPtr <*>
peek hPtr
createRGBSurface :: (Functor m, MonadIO m)
=> V2 CInt
-> PixelFormat
-> m Surface
createRGBSurface (V2 w h) pf =
fmap unmanagedSurface $
throwIfNull "SDL.Video.createRGBSurface" "SDL_CreateRGBSurface" $ do
(bpp, V4 r g b a) <- pixelFormatToMasks pf
Raw.createRGBSurface 0 w h bpp r g b a
createRGBSurfaceFrom :: (Functor m, MonadIO m)
=> MSV.IOVector Word8
-> V2 CInt
-> CInt
-> PixelFormat
-> m Surface
createRGBSurfaceFrom pixels (V2 w h) p pf = liftIO $
fmap (managedSurface pixels) $
throwIfNull "SDL.Video.createRGBSurfaceFrom" "SDL_CreateRGBSurfaceFrom" $ do
(bpp, V4 r g b a) <- pixelFormatToMasks pf
MSV.unsafeWith pixels $ \pixelPtr ->
Raw.createRGBSurfaceFrom (castPtr pixelPtr) w h bpp p r g b a
surfaceFillRect :: MonadIO m
=> Surface
-> Maybe (Rectangle CInt)
-> V4 Word8
-> m ()
surfaceFillRect (Surface s _) rect (V4 r g b a) = liftIO $
throwIfNeg_ "SDL.Video.fillRect" "SDL_FillRect" $
maybeWith with rect $ \rectPtr -> do
format <- Raw.surfaceFormat <$> peek s
Raw.mapRGBA format r g b a >>= Raw.fillRect s (castPtr rectPtr)
surfaceFillRects :: MonadIO m
=> Surface
-> SV.Vector (Rectangle CInt)
-> V4 Word8
-> m ()
surfaceFillRects (Surface s _) rects (V4 r g b a) = liftIO $ do
throwIfNeg_ "SDL.Video.fillRects" "SDL_FillRects" $
SV.unsafeWith rects $ \rp -> do
format <- Raw.surfaceFormat <$> peek s
Raw.fillRects s
(castPtr rp)
(fromIntegral (SV.length rects))
=<< Raw.mapRGBA format r g b a
freeSurface :: MonadIO m => Surface -> m ()
freeSurface (Surface s _) = Raw.freeSurface s
loadBMP :: MonadIO m => FilePath -> m Surface
loadBMP filePath = liftIO $
fmap unmanagedSurface $
throwIfNull "SDL.Video.loadBMP" "SDL_LoadBMP" $
withCString filePath $ Raw.loadBMP
newtype SurfacePixelFormat = SurfacePixelFormat (Ptr Raw.PixelFormat)
deriving (Eq, Typeable)
surfaceDimensions :: MonadIO m => Surface -> m (V2 CInt)
surfaceDimensions (Surface s _) = liftIO $ (V2 <$> Raw.surfaceW <*> Raw.surfaceH) <$> peek s
surfacePixels :: MonadIO m => Surface -> m (Ptr ())
surfacePixels (Surface s _) = liftIO $ Raw.surfacePixels <$> peek s
surfaceFormat :: MonadIO m => Surface -> m SurfacePixelFormat
surfaceFormat (Surface s _) = liftIO $ SurfacePixelFormat . Raw.surfaceFormat <$> peek s
newtype Palette = Palette (Ptr Raw.Palette)
deriving (Eq, Typeable)
formatPalette :: MonadIO m => SurfacePixelFormat -> m (Maybe Palette)
formatPalette (SurfacePixelFormat f) = liftIO $ wrap . Raw.pixelFormatPalette <$> peek f
where wrap p
| p == nullPtr = Nothing
| otherwise = Just (Palette p)
paletteNColors :: MonadIO m => Palette -> m CInt
paletteNColors (Palette p) = liftIO $ Raw.paletteNColors <$> peek p
paletteColors :: MonadIO m => Palette -> m (Maybe (SV.Vector (V4 Word8)))
paletteColors q@(Palette p) = do
n <- liftIO $ fromIntegral <$> paletteNColors q
let wrap p' | p' == nullPtr = Nothing
| otherwise = return p'
mv <- liftIO $ wrap . castPtr . Raw.paletteColors <$> peek p
mColor <- liftIO $ traverse newForeignPtr_ mv
return $ flip SV.unsafeFromForeignPtr0 n <$> mColor
paletteColor :: MonadIO m => Palette -> CInt -> m (Maybe (V4 Word8))
paletteColor q@(Palette p) i = do
rp <- liftIO $ peek p
m <- paletteNColors q
if m > i && i >= 0 then
liftIO $ fmap return . flip peekElemOff (fromIntegral i) . castPtr . Raw.paletteColors $ rp
else
return Nothing
setPaletteColors :: MonadIO m
=> Palette
-> (SV.Vector (V4 Word8))
-> CInt
-> m ()
setPaletteColors (Palette p) colors first = liftIO $
throwIfNeg_ "SDL.Video.setPaletteColors" "SDL_SetPaletteColors" $
SV.unsafeWith colors $ \cp ->
Raw.setPaletteColors p (castPtr cp) first n
where
n = fromIntegral $ SV.length colors
getWindowSurface :: (Functor m, MonadIO m) => Window -> m Surface
getWindowSurface (Window w) =
fmap unmanagedSurface $
throwIfNull "SDL.Video.getWindowSurface" "SDL_GetWindowSurface" $
Raw.getWindowSurface w
rendererDrawBlendMode :: Renderer -> StateVar BlendMode
rendererDrawBlendMode (Renderer r) = makeStateVar getRenderDrawBlendMode setRenderDrawBlendMode
where
getRenderDrawBlendMode = liftIO $
alloca $ \bmPtr -> do
throwIfNeg_ "SDL.Video.Renderer.getRenderDrawBlendMode" "SDL_GetRenderDrawBlendMode" $
Raw.getRenderDrawBlendMode r bmPtr
fromNumber <$> peek bmPtr
setRenderDrawBlendMode bm =
throwIfNeg_ "SDL.Video.Renderer.setRenderDrawBlendMode" "SDL_SetRenderDrawBlendMode" $
Raw.setRenderDrawBlendMode r (toNumber bm)
rendererDrawColor :: Renderer -> StateVar (V4 Word8)
rendererDrawColor (Renderer re) = makeStateVar getRenderDrawColor setRenderDrawColor
where
getRenderDrawColor = liftIO $
alloca $ \r ->
alloca $ \g ->
alloca $ \b ->
alloca $ \a -> do
throwIfNeg_ "SDL.Video.Renderer.getRenderDrawColor" "SDL_GetRenderDrawColor" $
Raw.getRenderDrawColor re r g b a
V4 <$> peek r <*> peek g <*> peek b <*> peek a
setRenderDrawColor (V4 r g b a) =
throwIfNeg_ "SDL.Video.setRenderDrawColor" "SDL_SetRenderDrawColor" $
Raw.setRenderDrawColor re r g b a
updateWindowSurface :: (Functor m, MonadIO m) => Window -> m ()
updateWindowSurface (Window w) =
throwIfNeg_ "SDL.Video.updateWindowSurface" "SDL_UpdateWindowSurface" $
Raw.updateWindowSurface w
data BlendMode
= BlendNone
| BlendAlphaBlend
| BlendAdditive
| BlendMod
deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)
instance FromNumber BlendMode Word32 where
fromNumber n = case n of
Raw.SDL_BLENDMODE_ADD -> BlendAdditive
Raw.SDL_BLENDMODE_BLEND -> BlendAlphaBlend
Raw.SDL_BLENDMODE_NONE -> BlendNone
Raw.SDL_BLENDMODE_MOD -> BlendMod
_ -> error $ "fromNumber<BlendMode>: unknown blend mode: " ++ show n
instance ToNumber BlendMode Word32 where
toNumber BlendNone = Raw.SDL_BLENDMODE_NONE
toNumber BlendAlphaBlend = Raw.SDL_BLENDMODE_BLEND
toNumber BlendAdditive = Raw.SDL_BLENDMODE_ADD
toNumber BlendMod = Raw.SDL_BLENDMODE_MOD
data Rectangle a = Rectangle (Point V2 a) (V2 a)
deriving (Eq, Functor, Generic, Ord, Read, Show, Typeable)
instance Storable a => Storable (Rectangle a) where
sizeOf ~(Rectangle o s) = sizeOf o + sizeOf s
alignment _ = 0
peek ptr = do
o <- peek (castPtr ptr)
s <- peek (castPtr (ptr `plusPtr` sizeOf o))
return (Rectangle o s)
poke ptr (Rectangle o s) = do
poke (castPtr ptr) o
poke (castPtr (ptr `plusPtr` sizeOf o)) s
data Surface = Surface (Ptr Raw.Surface) (Maybe (MSV.IOVector Word8))
deriving (Typeable)
unmanagedSurface :: Ptr Raw.Surface -> Surface
unmanagedSurface s = Surface s Nothing
managedSurface :: MSV.IOVector Word8 -> Ptr Raw.Surface -> Surface
managedSurface p s = Surface s (Just p)
newtype Texture = Texture Raw.Texture
deriving (Eq, Typeable)
drawRect :: MonadIO m
=> Renderer
-> Maybe (Rectangle CInt)
-> m ()
drawRect (Renderer r) rect = liftIO $
throwIfNeg_ "SDL.Video.drawRect" "SDL_RenderDrawRect" $
maybeWith with rect (Raw.renderDrawRect r . castPtr)
drawRects :: MonadIO m => Renderer -> SV.Vector (Rectangle CInt) -> m ()
drawRects (Renderer r) rects = liftIO $
throwIfNeg_ "SDL.Video.drawRects" "SDL_RenderDrawRects" $
SV.unsafeWith rects $ \rp ->
Raw.renderDrawRects r
(castPtr rp)
(fromIntegral (SV.length rects))
fillRect ::
MonadIO m
=> Renderer
-> Maybe (Rectangle CInt)
-> m ()
fillRect (Renderer r) rect =
liftIO $
throwIfNeg_ "SDL.Video.fillRect" "SDL_RenderFillRect" $
case rect of
Nothing -> Raw.renderFillRect r nullPtr
Just (Rectangle (P (V2 x y)) (V2 w h)) -> Raw.renderFillRectEx r x y w h
{-# INLINE fillRect #-}
fillRects :: MonadIO m => Renderer -> SV.Vector (Rectangle CInt) -> m ()
fillRects (Renderer r) rects = liftIO $
throwIfNeg_ "SDL.Video.fillRects" "SDL_RenderFillRects" $
SV.unsafeWith rects $ \rp ->
Raw.renderFillRects r
(castPtr rp)
(fromIntegral (SV.length rects))
clear :: (Functor m, MonadIO m) => Renderer -> m ()
clear (Renderer r) =
throwIfNeg_ "SDL.Video.clear" "SDL_RenderClear" $
Raw.renderClear r
{-# INLINE clear #-}
rendererScale :: Renderer -> StateVar (V2 CFloat)
rendererScale (Renderer r) = makeStateVar renderGetScale renderSetScale
where
renderSetScale (V2 x y) =
throwIfNeg_ "SDL.Video.renderSetScale" "SDL_RenderSetScale" $
Raw.renderSetScale r x y
renderGetScale = liftIO $
alloca $ \w ->
alloca $ \h -> do
Raw.renderGetScale r w h
V2 <$> peek w <*> peek h
rendererClipRect :: Renderer -> StateVar (Maybe (Rectangle CInt))
rendererClipRect (Renderer r) = makeStateVar renderGetClipRect renderSetClipRect
where
renderGetClipRect = liftIO $
alloca $ \rPtr -> do
Raw.renderGetClipRect r rPtr
maybePeek peek (castPtr rPtr)
renderSetClipRect rect =
liftIO $
throwIfNeg_ "SDL.Video.renderSetClipRect" "SDL_RenderSetClipRect" $
maybeWith with rect $ Raw.renderSetClipRect r . castPtr
rendererViewport :: Renderer -> StateVar (Maybe (Rectangle CInt))
rendererViewport (Renderer r) = makeStateVar renderGetViewport renderSetViewport
where
renderGetViewport = liftIO $
alloca $ \rect -> do
Raw.renderGetViewport r rect
maybePeek peek (castPtr rect)
renderSetViewport rect =
liftIO $
throwIfNeg_ "SDL.Video.renderSetViewport" "SDL_RenderSetViewport" $
maybeWith with rect $ Raw.renderSetViewport r . castPtr
present :: MonadIO m => Renderer -> m ()
present (Renderer r) = Raw.renderPresent r
copy :: MonadIO m
=> Renderer
-> Texture
-> Maybe (Rectangle CInt)
-> Maybe (Rectangle CInt)
-> m ()
copy (Renderer r) (Texture t) srcRect dstRect =
liftIO $
throwIfNeg_ "SDL.Video.copy" "SDL_RenderCopy" $
maybeWith with srcRect $ \src ->
maybeWith with dstRect $ \dst ->
Raw.renderCopy r t (castPtr src) (castPtr dst)
copyEx :: MonadIO m
=> Renderer
-> Texture
-> Maybe (Rectangle CInt)
-> Maybe (Rectangle CInt)
-> CDouble
-> Maybe (Point V2 CInt)
-> V2 Bool
-> m ()
copyEx (Renderer r) (Texture t) srcRect dstRect theta center flips =
liftIO $
throwIfNeg_ "SDL.Video.copyEx" "SDL_RenderCopyEx" $
maybeWith with srcRect $ \src ->
maybeWith with dstRect $ \dst ->
maybeWith with center $ \c ->
Raw.renderCopyEx r t (castPtr src) (castPtr dst) theta (castPtr c)
(case flips of
V2 x y -> (if x then Raw.SDL_FLIP_HORIZONTAL else 0) .|.
(if y then Raw.SDL_FLIP_VERTICAL else 0))
drawLine :: (Functor m,MonadIO m)
=> Renderer
-> Point V2 CInt
-> Point V2 CInt
-> m ()
drawLine (Renderer r) (P (V2 x y)) (P (V2 x' y')) =
throwIfNeg_ "SDL.Video.drawLine" "SDL_RenderDrawLine" $
Raw.renderDrawLine r x y x' y'
drawLines :: MonadIO m
=> Renderer
-> SV.Vector (Point V2 CInt)
-> m ()
drawLines (Renderer r) points =
liftIO $
throwIfNeg_ "SDL.Video.drawLines" "SDL_RenderDrawLines" $
SV.unsafeWith points $ \cp ->
Raw.renderDrawLines r
(castPtr cp)
(fromIntegral (SV.length points))
drawPoint :: (Functor m, MonadIO m) => Renderer -> Point V2 CInt -> m ()
drawPoint (Renderer r) (P (V2 x y)) =
throwIfNeg_ "SDL.Video.drawPoint" "SDL_RenderDrawPoint" $
Raw.renderDrawPoint r x y
drawPoints :: MonadIO m => Renderer -> SV.Vector (Point V2 CInt) -> m ()
drawPoints (Renderer r) points =
liftIO $
throwIfNeg_ "SDL.Video.drawPoints" "SDL_RenderDrawPoints" $
SV.unsafeWith points $ \cp ->
Raw.renderDrawPoints r
(castPtr cp)
(fromIntegral (SV.length points))
convertSurface :: (Functor m,MonadIO m)
=> Surface
-> SurfacePixelFormat
-> m Surface
convertSurface (Surface s _) (SurfacePixelFormat fmt) =
fmap unmanagedSurface $
throwIfNull "SDL.Video.Renderer.convertSurface" "SDL_ConvertSurface" $
Raw.convertSurface s fmt 0
surfaceBlitScaled :: MonadIO m
=> Surface
-> Maybe (Rectangle CInt)
-> Surface
-> Maybe (Rectangle CInt)
-> m ()
surfaceBlitScaled (Surface src _) srcRect (Surface dst _) dstRect =
liftIO $
throwIfNeg_ "SDL.Video.blitSurface" "SDL_BlitSurface" $
maybeWith with srcRect $ \srcPtr ->
maybeWith with dstRect $ \dstPtr ->
Raw.blitScaled src (castPtr srcPtr) dst (castPtr dstPtr)
surfaceColorKey :: Surface -> StateVar (Maybe (V4 Word8))
surfaceColorKey (Surface s _) = makeStateVar getColorKey setColorKey
where
getColorKey =
liftIO $
alloca $ \keyPtr -> do
ret <- Raw.getColorKey s keyPtr
if ret == -1
then return Nothing
else do format <- liftIO (Raw.surfaceFormat <$> peek s)
mapped <- peek keyPtr
alloca $ \r ->
alloca $ \g ->
alloca $ \b ->
alloca $ \a ->
do Raw.getRGBA mapped format r g b a
Just <$> (V4 <$> peek r <*> peek g <*> peek b <*> peek a)
setColorKey key =
liftIO $
throwIfNeg_ "SDL.Video.Renderer.setColorKey" "SDL_SetColorKey" $
case key of
Nothing ->
alloca $ \keyPtr -> do
ret <- Raw.getColorKey s keyPtr
if ret == -1
then return 0
else do key' <- peek keyPtr
Raw.setColorKey s 0 key'
Just (V4 r g b a) -> do
format <- liftIO (Raw.surfaceFormat <$> peek s)
Raw.mapRGBA format r g b a >>= Raw.setColorKey s 1
textureColorMod :: Texture -> StateVar (V3 Word8)
textureColorMod (Texture t) = makeStateVar getTextureColorMod setTextureColorMod
where
getTextureColorMod = liftIO $
alloca $ \r ->
alloca $ \g ->
alloca $ \b -> do
throwIfNeg_ "SDL.Video.Renderer.getTextureColorMod" "SDL_GetTextureColorMod" $
Raw.getTextureColorMod t r g b
V3 <$> peek r <*> peek g <*> peek b
setTextureColorMod (V3 r g b) =
throwIfNeg_ "SDL.Video.Renderer.setTextureColorMod" "SDL_SetTextureColorMod" $
Raw.setTextureColorMod t r g b
data PixelFormat
= Unknown
| Index1LSB
| Index1MSB
| Index4LSB
| Index4MSB
| Index8
| RGB332
| RGB444
| RGB555
| BGR555
| ARGB4444
| RGBA4444
| ABGR4444
| BGRA4444
| ARGB1555
| RGBA5551
| ABGR1555
| BGRA5551
| RGB565
| BGR565
| RGB24
| BGR24
| RGB888
| RGBX8888
| BGR888
| BGRX8888
| ARGB8888
| RGBA8888
| ABGR8888
| BGRA8888
| ARGB2101010
| YV12
| IYUV
| YUY2
| UYVY
| YVYU
deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)
instance FromNumber PixelFormat Word32 where
fromNumber n' = case n' of
Raw.SDL_PIXELFORMAT_UNKNOWN -> Unknown
Raw.SDL_PIXELFORMAT_INDEX1LSB -> Index1LSB
Raw.SDL_PIXELFORMAT_INDEX1MSB -> Index1MSB
Raw.SDL_PIXELFORMAT_INDEX4LSB -> Index4LSB
Raw.SDL_PIXELFORMAT_INDEX4MSB -> Index4MSB
Raw.SDL_PIXELFORMAT_INDEX8 -> Index8
Raw.SDL_PIXELFORMAT_RGB332 -> RGB332
Raw.SDL_PIXELFORMAT_RGB444 -> RGB444
Raw.SDL_PIXELFORMAT_RGB555 -> RGB555
Raw.SDL_PIXELFORMAT_BGR555 -> BGR555
Raw.SDL_PIXELFORMAT_ARGB4444 -> ARGB4444
Raw.SDL_PIXELFORMAT_RGBA4444 -> RGBA4444
Raw.SDL_PIXELFORMAT_ABGR4444 -> ABGR4444
Raw.SDL_PIXELFORMAT_BGRA4444 -> BGRA4444
Raw.SDL_PIXELFORMAT_ARGB1555 -> ARGB1555
Raw.SDL_PIXELFORMAT_RGBA5551 -> RGBA5551
Raw.SDL_PIXELFORMAT_ABGR1555 -> ABGR1555
Raw.SDL_PIXELFORMAT_BGRA5551 -> BGRA5551
Raw.SDL_PIXELFORMAT_RGB565 -> RGB565
Raw.SDL_PIXELFORMAT_BGR565 -> BGR565
Raw.SDL_PIXELFORMAT_RGB24 -> RGB24
Raw.SDL_PIXELFORMAT_BGR24 -> BGR24
Raw.SDL_PIXELFORMAT_RGB888 -> RGB888
Raw.SDL_PIXELFORMAT_RGBX8888 -> RGBX8888
Raw.SDL_PIXELFORMAT_BGR888 -> BGR888
Raw.SDL_PIXELFORMAT_BGRX8888 -> BGRX8888
Raw.SDL_PIXELFORMAT_ARGB8888 -> ARGB8888
Raw.SDL_PIXELFORMAT_RGBA8888 -> RGBA8888
Raw.SDL_PIXELFORMAT_ABGR8888 -> ABGR8888
Raw.SDL_PIXELFORMAT_BGRA8888 -> BGRA8888
Raw.SDL_PIXELFORMAT_ARGB2101010 -> ARGB2101010
Raw.SDL_PIXELFORMAT_YV12 -> YV12
Raw.SDL_PIXELFORMAT_IYUV -> IYUV
Raw.SDL_PIXELFORMAT_YUY2 -> YUY2
Raw.SDL_PIXELFORMAT_UYVY -> UYVY
Raw.SDL_PIXELFORMAT_YVYU -> YVYU
_ -> error "fromNumber: not numbered"
instance ToNumber PixelFormat Word32 where
toNumber pf = case pf of
Unknown -> Raw.SDL_PIXELFORMAT_UNKNOWN
Index1LSB -> Raw.SDL_PIXELFORMAT_INDEX1LSB
Index1MSB -> Raw.SDL_PIXELFORMAT_INDEX1MSB
Index4LSB -> Raw.SDL_PIXELFORMAT_INDEX4LSB
Index4MSB -> Raw.SDL_PIXELFORMAT_INDEX4MSB
Index8 -> Raw.SDL_PIXELFORMAT_INDEX8
RGB332 -> Raw.SDL_PIXELFORMAT_RGB332
RGB444 -> Raw.SDL_PIXELFORMAT_RGB444
RGB555 -> Raw.SDL_PIXELFORMAT_RGB555
BGR555 -> Raw.SDL_PIXELFORMAT_BGR555
ARGB4444 -> Raw.SDL_PIXELFORMAT_ARGB4444
RGBA4444 -> Raw.SDL_PIXELFORMAT_RGBA4444
ABGR4444 -> Raw.SDL_PIXELFORMAT_ABGR4444
BGRA4444 -> Raw.SDL_PIXELFORMAT_BGRA4444
ARGB1555 -> Raw.SDL_PIXELFORMAT_ARGB1555
RGBA5551 -> Raw.SDL_PIXELFORMAT_RGBA5551
ABGR1555 -> Raw.SDL_PIXELFORMAT_ABGR1555
BGRA5551 -> Raw.SDL_PIXELFORMAT_BGRA5551
RGB565 -> Raw.SDL_PIXELFORMAT_RGB565
BGR565 -> Raw.SDL_PIXELFORMAT_BGR565
RGB24 -> Raw.SDL_PIXELFORMAT_RGB24
BGR24 -> Raw.SDL_PIXELFORMAT_BGR24
RGB888 -> Raw.SDL_PIXELFORMAT_RGB888
RGBX8888 -> Raw.SDL_PIXELFORMAT_RGBX8888
BGR888 -> Raw.SDL_PIXELFORMAT_BGR888
BGRX8888 -> Raw.SDL_PIXELFORMAT_BGRX8888
ARGB8888 -> Raw.SDL_PIXELFORMAT_ARGB8888
RGBA8888 -> Raw.SDL_PIXELFORMAT_RGBA8888
ABGR8888 -> Raw.SDL_PIXELFORMAT_ABGR8888
BGRA8888 -> Raw.SDL_PIXELFORMAT_BGRA8888
ARGB2101010 -> Raw.SDL_PIXELFORMAT_ARGB2101010
YV12 -> Raw.SDL_PIXELFORMAT_YV12
IYUV -> Raw.SDL_PIXELFORMAT_IYUV
YUY2 -> Raw.SDL_PIXELFORMAT_YUY2
UYVY -> Raw.SDL_PIXELFORMAT_UYVY
YVYU -> Raw.SDL_PIXELFORMAT_YVYU
data RendererType
= UnacceleratedRenderer
| AcceleratedRenderer
| AcceleratedVSyncRenderer
| SoftwareRenderer
deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)
data RendererConfig = RendererConfig
{ rendererType :: RendererType
, rendererTargetTexture :: Bool
} deriving (Data, Eq, Generic, Ord, Read, Show, Typeable)
instance FromNumber RendererConfig Word32 where
fromNumber n = RendererConfig
{ rendererType = rendererType'
(n .&. Raw.SDL_RENDERER_SOFTWARE /= 0)
(n .&. Raw.SDL_RENDERER_ACCELERATED /= 0)
(n .&. Raw.SDL_RENDERER_PRESENTVSYNC /= 0)
, rendererTargetTexture = n .&. Raw.SDL_RENDERER_TARGETTEXTURE /= 0
}
where
rendererType' s a v | s = SoftwareRenderer
| a && v = AcceleratedVSyncRenderer
| a = AcceleratedRenderer
| otherwise = UnacceleratedRenderer
instance ToNumber RendererConfig Word32 where
toNumber config = foldr (.|.) 0
[ if isSoftware then Raw.SDL_RENDERER_SOFTWARE else 0
, if not isSoftware then Raw.SDL_RENDERER_ACCELERATED else 0
, if rendererType config == AcceleratedVSyncRenderer then Raw.SDL_RENDERER_PRESENTVSYNC else 0
, if rendererTargetTexture config then Raw.SDL_RENDERER_TARGETTEXTURE else 0
]
where
isSoftware = rendererType config == SoftwareRenderer
defaultRenderer :: RendererConfig
defaultRenderer = RendererConfig
{ rendererType = AcceleratedRenderer
, rendererTargetTexture = False
}
data RendererInfo = RendererInfo
{ rendererInfoName :: Text
, rendererInfoFlags :: RendererConfig
, rendererInfoNumTextureFormats :: Word32
, rendererInfoTextureFormats :: [PixelFormat]
, rendererInfoMaxTextureWidth :: CInt
, rendererInfoMaxTextureHeight :: CInt
} deriving (Eq, Generic, Ord, Read, Show, Typeable)
fromRawRendererInfo :: MonadIO m => Raw.RendererInfo -> m RendererInfo
fromRawRendererInfo (Raw.RendererInfo name flgs ntf tfs mtw mth) = liftIO $ do
name' <- Text.decodeUtf8 <$> BS.packCString name
return $ RendererInfo name' (fromNumber flgs) ntf (fmap fromNumber tfs) mtw mth
getRendererInfo :: MonadIO m => Renderer -> m RendererInfo
getRendererInfo (Renderer renderer) = liftIO $
alloca $ \rptr -> do
throwIfNeg_ "getRendererInfo" "SDL_GetRendererInfo" $
Raw.getRendererInfo renderer rptr
peek rptr >>= fromRawRendererInfo
getRenderDriverInfo :: MonadIO m => m [RendererInfo]
getRenderDriverInfo = liftIO $ do
count <- Raw.getNumRenderDrivers
traverse go [0..count-1]
where
go idx = alloca $ \rptr -> do
throwIfNeg_ "getRenderDriverInfo" "SDL_GetRenderDriverInfo" $
Raw.getRenderDriverInfo idx rptr
peek rptr >>= fromRawRendererInfo
textureAlphaMod :: Texture -> StateVar Word8
textureAlphaMod (Texture t) = makeStateVar getTextureAlphaMod setTextureAlphaMod
where
getTextureAlphaMod = liftIO $
alloca $ \x -> do
throwIfNeg_ "SDL.Video.Renderer.getTextureAlphaMod" "SDL_GetTextureAlphaMod" $
Raw.getTextureAlphaMod t x
peek x
setTextureAlphaMod alpha =
throwIfNeg_ "SDL.Video.Renderer.setTextureAlphaMod" "SDL_SetTextureAlphaMod" $
Raw.setTextureAlphaMod t alpha
textureBlendMode :: Texture -> StateVar BlendMode
textureBlendMode (Texture t) = makeStateVar getTextureBlendMode setTextureBlendMode
where
getTextureBlendMode = liftIO $
alloca $ \x -> do
throwIfNeg_ "SDL.Video.Renderer.getTextureBlendMode" "SDL_GetTextureBlendMode" $
Raw.getTextureBlendMode t x
fromNumber <$> peek x
setTextureBlendMode bm =
throwIfNeg_ "SDL.Video.Renderer.setTextureBlendMode" "SDL_SetTextureBlendMode" $
Raw.setTextureBlendMode t (toNumber bm)
surfaceBlendMode :: Surface -> StateVar BlendMode
surfaceBlendMode (Surface s _) = makeStateVar getSurfaceBlendMode setSurfaceBlendMode
where
getSurfaceBlendMode = liftIO $
alloca $ \x -> do
throwIfNeg_ "SDL.Video.Renderer.getSurfaceBlendMode" "SDL_GetSurfaceBlendMode" $
Raw.getSurfaceBlendMode s x
fromNumber <$> peek x
setSurfaceBlendMode bm =
throwIfNeg_ "SDL.Video.Renderer.setSurfaceBlendMode" "SDL_SetSurfaceBlendMode" $
Raw.setSurfaceBlendMode s (toNumber bm)
rendererRenderTarget :: Renderer -> StateVar (Maybe Texture)
rendererRenderTarget (Renderer r) = makeStateVar getRenderTarget setRenderTarget
where
getRenderTarget = do
t <- Raw.getRenderTarget r
return $
if t == nullPtr
then Nothing
else Just (Texture t)
setRenderTarget texture =
throwIfNeg_ "SDL.Video.Renderer.setRenderTarget" "SDL_SetRenderTarget" $
case texture of
Nothing -> Raw.setRenderTarget r nullPtr
Just (Texture t) -> Raw.setRenderTarget r t
rendererLogicalSize :: Renderer -> StateVar (Maybe (V2 CInt))
rendererLogicalSize (Renderer r) = makeStateVar renderGetLogicalSize renderSetLogicalSize
where
renderGetLogicalSize = liftIO $
alloca $ \w -> do
alloca $ \h -> do
Raw.renderGetLogicalSize r w h
v <- V2 <$> peek w <*> peek h
return $ if v == 0 then Nothing else Just v
renderSetLogicalSize v =
throwIfNeg_ "SDL.Video.renderSetLogicalSize" "SDL_RenderSetLogicalSize" $ do
let (x,y) = case v of Just (V2 vx vy) -> (vx, vy)
Nothing -> (0,0)
Raw.renderSetLogicalSize r x y
renderTargetSupported :: (MonadIO m) => Renderer -> m Bool
renderTargetSupported (Renderer r) = Raw.renderTargetSupported r
pixelFormatToMasks :: (MonadIO m) => PixelFormat -> m (CInt, V4 Word32)
pixelFormatToMasks pf = liftIO $
alloca $ \bpp ->
alloca $ \r ->
alloca $ \g ->
alloca $ \b ->
alloca $ \a -> do
throwIf_ not "SDL.Video.pixelFormatEnumToMasks" "SDL_PixelFormatEnumToMasks" $
Raw.pixelFormatEnumToMasks (toNumber pf) bpp r g b a
wrap <$> peek bpp <*> peek r <*> peek g <*> peek b <*> peek a
where
wrap bpp r g b a = (bpp, V4 r g b a)
masksToPixelFormat :: (MonadIO m) => CInt -> V4 Word32 -> m PixelFormat
masksToPixelFormat bpp (V4 r g b a) = liftIO $
fromNumber <$> Raw.masksToPixelFormatEnum bpp r g b a