{-# OPTIONS -fwarn-incomplete-patterns #-} -- | Helper functions for rendering bitmaps module Graphics.Gloss.Internals.Render.Bitmap ( BitmapData(..) , reverseRGBA , bitmapPath , freeBitmapData ) where import Foreign -- | Abstract 32-bit RGBA bitmap data. data BitmapData = BitmapData Int -- length (in bytes) (ForeignPtr Word8) -- pointer to data deriving (Eq) instance Show BitmapData where show _ = "BitmapData" -- | Generates the point path to display the bitmap centred bitmapPath :: Float -> Float -> [(Float, Float)] bitmapPath width height = [(-width', -height'), (width', -height'), (width', height'), (-width', height')] where width' = width / 2 height' = height / 2 -- | Destructively reverse the byte order in an array. -- This is necessary as OpenGL reads pixel data as ABGR, rather than RGBA reverseRGBA :: BitmapData -> IO () reverseRGBA (BitmapData length8 fptr) = withForeignPtr fptr (reverseRGBA_ptr length8) -- | Destructively reverses the byte order in an array. reverseRGBA_ptr :: Int -> Ptr Word8 -> IO () reverseRGBA_ptr length8 ptr8 = go (length8 `div` 4) (castPtr ptr8) 0 where go :: Int -> Ptr Word32 -> Int -> IO () go len ptr count | count < len = do curr <- peekElemOff ptr count let byte0 = shift (isolateByte0 curr) 24 let byte1 = shift (isolateByte1 curr) 8 let byte2 = shift (isolateByte2 curr) (-8) let byte3 = shift (isolateByte3 curr) (-24) pokeElemOff ptr count (byte0 .|. byte1 .|. byte2 .|. byte3) go len ptr (count + 1) | otherwise = return () -- | Frees the allocated memory given to OpenGL to avoid a memory leak freeBitmapData :: Ptr Word8 -> IO () {-# INLINE freeBitmapData #-} freeBitmapData p = free p -- | These functions work as bit masks to isolate the Word8 components {-# INLINE isolateByte0 #-} isolateByte0 :: Word32 -> Word32 isolateByte0 word = word .&. (255 :: Word32) {-# INLINE isolateByte1 #-} isolateByte1 :: Word32 -> Word32 isolateByte1 word = word .&. (65280 :: Word32) {-# INLINE isolateByte2 #-} isolateByte2 :: Word32 -> Word32 isolateByte2 word = word .&. (16711680 :: Word32) {-# INLINE isolateByte3 #-} isolateByte3 :: Word32 -> Word32 isolateByte3 word = word .&. (4278190080 :: Word32)