File: Lesson17.hs

package info (click to toggle)
haskell-sdl2 2.5.5.0-2
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 17,348 kB
  • sloc: haskell: 10,160; ansic: 102; makefile: 5
file content (141 lines) | stat: -rw-r--r-- 4,472 bytes parent folder | download | duplicates (4)
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