SDL, is a library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.
Surface
is used in software rendering
using regular RAM to store image data
using CPU
Texture
is used in hardware rendering
using regular VRAM to store image data
using GPU (internally, using OpenGL)
有兩套 haskell bindings to SDL 2 library,
關於讀圖, sdl2 只提供了
SDL_Surface* SDL_LoadBMP(const char* file)
也就是說,我們基本上只有
loadBMP :: MonadIO m => FilePath -> m Surface
SDL_image 2.0 (C library)
SDL-image (Haskell package)
JuixyPixel (Haskell package)
自己的格式: Image
沒人寫過 JuixyPixel -> sdl2 (至少我沒找到過)
JiuscyPixel, sdl2, cairo 和 sdl2-cairo
ill-designed and ill-implemented (buggy + slow)
sdl2-image
low/high-level binding to SDL_image (C library)
先來整理一下各套件是怎麼儲存圖片的..
import qualified Data.Vector.Storable as V
data Image a = Image
{ imageWidth :: {-# UNPACK #-} !Int
, imageHeight :: {-# UNPACK #-} !Int
, imageData :: V.Vector (PixelBaseComponent a)}
e.g. V.Vector PixelRGBA8
or V.Vector PixelCMYK16
newtype Texture =
Texture Raw.Texture deriving (Eq, Typeable)
type Texture = Ptr ()
.....(默)
import qualified Data.Vector.Storable.Mutable as MSV
data Surface = Surface
(Ptr Raw.Surface) (Maybe (MSV.IOVector Word8))
data Surface = Surface
{ ...
, surfacePixels :: !(Ptr ())
, ...} deriving (Eq, Show, Typeable)
MSV.IOVector Word8
?surfacePixels :: !(Ptr ())
?
在 sdl2 裡面繪圖要用 Renderer
搞不清楚 Renderer
, Surface
, Texture
仨之間的關係
聽說 SDL.Cairo.Canvas 比較方便繪圖
改用 sdl2-cairo
Canvas 可以...
data Canvas a = ...
Instances
Functor Canvas
Applicative Canvas
Monad Canvas
MonadIO Canvas
... = do
background $ gray 102
fill $ red 255 !@ 128
noStroke
rect $ D 200 200 100 100
...
但是
wrapper around the Cairo
Render
monad, providing a Processing-style API.
那我何必呢? 直接用 Cairo 的 Render
就好啦~ orz
乾脆兩種都做:
class Pixel px => RenderablePixel px where
drawPx :: (V2 Int, px) -> Canvas ()
class Pixel px => RenderablePixelC px where
renderPx :: (V2 Int, px) -> Render ()
Renderer
+--- Image.hs
|--- Image
+--- General.hs
|--- Info.hs
|--- Loading.hs
|--- Raw.hs
|--- Raw
+--- General.hs
|--- Info.hs
|--- Loading.hs
|--- Enum.hsc
設定 cabal (以 sdl2-image 為例)
includes:
SDL_image.h
extra-libraries:
SDL2_image
pkgconfig-depends:
SDL2_image >= 2.0.0
#include
#const
#type
.../Raw/
下面)module SDL.Image.Raw.Enum where
--
#include "SDL_image.h"
--
pattern IMG_INIT_JPG = (#const IMG_INIT_JPG) :: CInt
pattern IMG_INIT_PNG = (#const IMG_INIT_PNG) :: CInt
pattern IMG_INIT_TIF = (#const IMG_INIT_TIF) :: CInt
module SDL.Image.Raw.Enum where
--
{-# LINE 13 "src/SDL/Image/Raw/Enum.hsc" #-}
--
pattern IMG_INIT_JPG = (1) :: CInt
{-# LINE 19 "src/SDL/Image/Raw/Enum.hsc" #-}
pattern IMG_INIT_PNG = (2) :: CInt
{-# LINE 20 "src/SDL/Image/Raw/Enum.hsc" #-}
pattern IMG_INIT_TIF = (4) :: CInt
{-# LINE 21 "src/SDL/Image/Raw/Enum.hsc" #-}
type Texture = Ptr ()
type InitFlag = Word32
type Keycode = (#type SDL_Keycode)
data Color = Color !Word8 !Word8 !Word8 !Word8
deriving (Eq, Show, Typeable)
instance Storable Color where
sizeOf _ = (#size SDL_Color)
peek ptr = do
r <- (#peek SDL_Color, r) ptr
g <- (#peek SDL_Color, g) ptr
b <- (#peek SDL_Color, b) ptr
a <- (#peek SDL_Color, a) ptr
return $! Color r g b a
../Raw/xxx.hs
|--- Raw
+--- General.hs
|--- Info.hs
|--- Loading.hs
|--- Enum.hsc
foreign import ccall
注意 function type!
SDL_Surface *IMG_LoadTyped_RW( SDL_RWops *src
, int freesrc
, char *type)
foreign import ccall "SDL_image.h IMG_LoadTyped_RW"
imgLoadRWTyped_FFI :: Ptr RowType.RWops
-> CInt
-> CString
-> IO (Ptr RowType.Surface)
可以根據情況再稍微多包一點點
讓 type 更有意義一點
imgLoadRWTyped :: MonadIO m => Ptr RowType.RWops
-> Bool
-> CString
-> m (Ptr RowType.Surface)
imgLoadRWTyped p autoFree typeStr = liftIO $
imgLoadRWTyped_FFI p (fromBool autoFree) typeStr
{-# INLINE imgLoadRWTyped #-}
imgLoadRWTyped :: MonadIO m => Ptr SDL.Row.RWops
-> Bool
-> CString
-> m (Ptr SDL.Row.Surface)
surfaceFromImgT :: MonadIO m => ImageType -> Image -> m SDL.Surface