{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Graphics.Gloss.Raster.Field
(
module Graphics.Gloss.Data.Color
, rgb, rgbI, rgb8w
, rgb', rgbI'
, Display (..)
, Point
, animateField
, playField
, makePicture
, makeFrame)
where
import Graphics.Gloss.Data.Color
import Graphics.Gloss.Data.Picture
import Graphics.Gloss.Data.Display
import Graphics.Gloss.Data.Bitmap
import Graphics.Gloss.Interface.Pure.Game
import Graphics.Gloss.Interface.IO.Animate
import Graphics.Gloss.Interface.Environment
import Data.Word
import System.IO.Unsafe
import Unsafe.Coerce
import Debug.Trace
import Data.Bits
import Data.Array.Repa as R
import Data.Array.Repa.Repr.ForeignPtr as R
import Data.Array.Repa.Repr.HintInterleave as R
import Prelude as P
rgb :: Float -> Float -> Float -> Color
rgb r g b = makeColor r g b 1.0
{-# INLINE rgb #-}
rgbI :: Int -> Int -> Int -> Color
rgbI r g b = makeColorI r g b 255
{-# INLINE rgbI #-}
rgb8w :: Word8 -> Word8 -> Word8 -> Color
rgb8w r g b = makeColorI (fromIntegral r) (fromIntegral g) (fromIntegral b) 255
{-# INLINE rgb8w #-}
rgb' :: Float -> Float -> Float -> Color
rgb' r g b = makeColor r g b 1.0
{-# INLINE rgb' #-}
rgbI' :: Int -> Int -> Int -> Color
rgbI' r g b = makeColorI r g b 255
{-# INLINE rgbI' #-}
animateField
:: Display
-> (Int, Int)
-> (Float -> Point -> Color)
-> IO ()
animateField display (zoomX, zoomY) makePixel
= zoomX `seq` zoomY `seq`
if zoomX < 1 || zoomY < 1
then error $ "Graphics.Gloss.Raster.Field: invalid pixel scale factor "
P.++ show (zoomX, zoomY)
else
do (winSizeX, winSizeY) <- sizeOfDisplay display
let frame !time
= return
$ makePicture winSizeX winSizeY zoomX zoomY (makePixel time)
animateFixedIO display black frame (const $ return ())
{-# INLINE animateField #-}
playField
:: Display
-> (Int, Int)
-> Int
-> world
-> (world -> Point -> Color)
-> (Event -> world -> world)
-> (Float -> world -> world)
-> IO ()
playField !display (zoomX, zoomY) !stepRate
!initWorld !makePixel !handleEvent !stepWorld
= zoomX `seq` zoomY `seq`
if zoomX < 1 || zoomY < 1
then error $ "Graphics.Gloss.Raster.Field: invalid pixel scale factor "
P.++ show (zoomX, zoomY)
else do (winSizeX, winSizeY) <- sizeOfDisplay display
winSizeX `seq` winSizeY `seq`
play display black stepRate
((winSizeX, winSizeY), initWorld)
(\((winSizeX', winSizeY'), world) ->
winSizeX' `seq` winSizeY' `seq` world `seq`
makePicture winSizeX' winSizeY' zoomX zoomY (makePixel world))
(\event (winSize, world) ->
let winSize' =
case event of
EventResize dims -> dims
_ -> winSize
in (winSize', handleEvent event world))
(fmap . stepWorld)
{-# INLINE playField #-}
sizeOfDisplay :: Display -> IO (Int, Int)
sizeOfDisplay display
= case display of
InWindow _ s _ -> return s
FullScreen -> getScreenSize
{-# INLINE sizeOfDisplay #-}
makePicture
:: Int
-> Int
-> Int
-> Int
-> (Point -> Color)
-> Picture
makePicture !winSizeX !winSizeY !zoomX !zoomY !makePixel
= let
sizeX = winSizeX `div` zoomX
sizeY = winSizeY `div` zoomY
{-# INLINE conv #-}
conv (r, g, b)
= let r' = fromIntegral r
g' = fromIntegral g
b' = fromIntegral b
a = 255
!w = unsafeShiftL r' 24
.|. unsafeShiftL g' 16
.|. unsafeShiftL b' 8
.|. a
in w
in unsafePerformIO $ do
traceEventIO "Gloss.Raster[makePicture]: start frame evaluation."
(arrRGB :: Array F DIM2 Word32)
<- R.computeP
$ R.map conv
$ makeFrame sizeX sizeY makePixel
traceEventIO "Gloss.Raster[makePicture]: done, returning picture."
let picture
= Scale (fromIntegral zoomX) (fromIntegral zoomY)
$ bitmapOfForeignPtr
sizeX sizeY
(BitmapFormat BottomToTop PxABGR)
(R.toForeignPtr $ unsafeCoerce arrRGB)
False
return picture
{-# INLINE makePicture #-}
makeFrame
:: Int
-> Int
-> (Point -> Color)
-> Array (I D) DIM2 (Word8, Word8, Word8)
makeFrame !sizeX !sizeY !makePixel
= let
fsizeX, fsizeY :: Float
!fsizeX = fromIntegral sizeX
!fsizeY = fromIntegral sizeY
fsizeX2, fsizeY2 :: Float
!fsizeX2 = fsizeX / 2
!fsizeY2 = fsizeY / 2
midX, midY :: Int
!midX = sizeX `div` 2
!midY = sizeY `div` 2
{-# INLINE pixelOfIndex #-}
pixelOfIndex (Z :. y :. x)
= let x' = fromIntegral (x - midX) / fsizeX2
y' = fromIntegral (y - midY) / fsizeY2
in makePixel (x', y')
in R.hintInterleave
$ R.map unpackColor
$ R.fromFunction (Z :. sizeY :. sizeX)
$ pixelOfIndex
{-# INLINE makeFrame #-}
word8OfFloat :: Float -> Word8
word8OfFloat f
= fromIntegral (truncate f :: Int)
{-# INLINE word8OfFloat #-}
unpackColor :: Color -> (Word8, Word8, Word8)
unpackColor c
| (r, g, b, _) <- rgbaOfColor c
= ( word8OfFloat (r * 255)
, word8OfFloat (g * 255)
, word8OfFloat (b * 255))
{-# INLINE unpackColor #-}