1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Lazyfoo.Lesson17 (main) where
import Prelude hiding (foldl1, and)
import Control.Monad
import Data.Foldable
import Data.Monoid
import Data.Maybe
import Foreign.C.Types
import SDL.Vect
import SDL (($=))
import qualified SDL
import Paths_sdl2 (getDataFileName)
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative
#endif
screenWidth, screenHeight :: CInt
(screenWidth, screenHeight) = (640, 480)
data Texture = Texture SDL.Texture (V2 CInt)
loadTexture :: SDL.Renderer -> FilePath -> IO Texture
loadTexture r filePath = do
surface <- getDataFileName filePath >>= SDL.loadBMP
size <- SDL.surfaceDimensions surface
let key = V4 0 maxBound maxBound maxBound
SDL.surfaceColorKey surface $= Just key
t <- SDL.createTextureFromSurface r surface
SDL.freeSurface surface
return (Texture t size)
renderTexture :: SDL.Renderer -> Texture -> Point V2 CInt -> Maybe (SDL.Rectangle CInt) -> Maybe CDouble -> Maybe (Point V2 CInt) -> Maybe (V2 Bool) -> IO ()
renderTexture r (Texture t size) xy clip theta center flips =
let dstSize =
maybe size (\(SDL.Rectangle _ size') -> size') clip
in SDL.copyEx r
t
clip
(Just (SDL.Rectangle xy dstSize))
(fromMaybe 0 theta)
center
(fromMaybe (pure False) flips)
data ButtonSprite = MouseOut | MouseOver | MouseDown | MouseUp
data Button = Button (Point V2 CInt) ButtonSprite
buttonSize :: V2 CInt
buttonWidth, buttonHeight :: CInt
buttonSize@(V2 buttonWidth buttonHeight) = V2 300 200
handleEvent :: Point V2 CInt -> SDL.EventPayload -> Button -> Button
handleEvent mousePos ev (Button buttonPos _) =
let inside = and ((>=) <$> mousePos <*> buttonPos) &&
and ((<=) <$> mousePos <*> buttonPos + P buttonSize)
sprite
| inside = case ev of
SDL.MouseButtonEvent e
| SDL.mouseButtonEventMotion e == SDL.Pressed -> MouseDown
| SDL.mouseButtonEventMotion e == SDL.Released -> MouseUp
| otherwise -> MouseOver
_ -> MouseOver
| otherwise = MouseOut
in Button buttonPos sprite
renderButton :: SDL.Renderer -> Texture -> Button -> IO ()
renderButton r spriteSheet (Button xy sprite) =
renderTexture r spriteSheet xy (Just spriteClipRect) Nothing Nothing Nothing
where
spriteClipRect =
let i = case sprite of
MouseOut -> 0
MouseOver -> 1
MouseDown -> 2
MouseUp -> 3
in SDL.Rectangle (P (V2 0 (i * 200))) (V2 300 200)
main :: IO ()
main = do
SDL.initialize [SDL.InitVideo]
SDL.HintRenderScaleQuality $= SDL.ScaleLinear
do renderQuality <- SDL.get SDL.HintRenderScaleQuality
when (renderQuality /= SDL.ScaleLinear) $
putStrLn "Warning: Linear texture filtering not enabled!"
window <-
SDL.createWindow
"SDL Tutorial"
SDL.defaultWindow {SDL.windowInitialSize = V2 screenWidth screenHeight}
SDL.showWindow window
renderer <-
SDL.createRenderer
window
(-1)
SDL.RendererConfig
{ SDL.rendererType = SDL.AcceleratedVSyncRenderer
, SDL.rendererTargetTexture = False
}
SDL.rendererDrawColor renderer $= V4 maxBound maxBound maxBound maxBound
buttonSpriteSheet <- loadTexture renderer "examples/lazyfoo/button.bmp"
let loop buttons = do
events <- SDL.pollEvents
mousePos <- SDL.getAbsoluteMouseLocation
let (Any quit, Endo updateButton) =
foldMap (\case
SDL.QuitEvent -> (Any True, mempty)
e -> (mempty, Endo (handleEvent mousePos e))) $
map SDL.eventPayload events
SDL.rendererDrawColor renderer $= V4 maxBound maxBound maxBound maxBound
SDL.clear renderer
let buttons' = map updateButton buttons
for_ buttons' (renderButton renderer buttonSpriteSheet)
SDL.present renderer
unless quit (loop buttons')
loop (let newButton xy = Button xy MouseOut
in [ newButton (P (V2 0 0))
, newButton (P (V2 (screenWidth - buttonWidth) 0))
, newButton (P (V2 0 (screenHeight - buttonHeight)))
, newButton (P (V2 screenWidth screenHeight - buttonSize))
])
SDL.destroyRenderer renderer
SDL.destroyWindow window
SDL.quit
|