-
Notifications
You must be signed in to change notification settings - Fork 15
/
AppUtil.hs
151 lines (123 loc) · 3.94 KB
/
AppUtil.hs
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
142
143
144
145
146
147
148
149
150
151
{-# LANGUAGE ForeignFunctionInterface #-}
module AppUtil (
KeyProc,
getKeyState,
key2btn,
delayedStream,
procSDLEvent,
ImageResource,
loadImageResource,
releaseImageResource,
getImageSurface,
putimg,
SoundResource,
loadSoundResource,
bgmPath,
cellCrd,
Rect(..),
ishit
) where
import Graphics.UI.SDL hiding (flip)
import Graphics.UI.SDL.Utilities
import Graphics.UI.SDL.Mixer
import Data.Maybe (fromJust)
import Data.List (findIndices)
import System.IO.Unsafe (unsafeInterleaveIO)
import Foreign
import Foreign.C.Types
import Pad
import Const
import Images
import Sounds
imagePath, soundPath, bgmPath :: String
imagePath = "data/img/"
soundPath = "data/snd/"
bgmPath = "data/snd/"
-- `SDL_GetKeyState' is not defined in Graphic.UI.SDL
foreign import ccall unsafe "SDL_GetKeyState" sdlGetKeyState :: Ptr CInt -> IO (Ptr Word8)
type KeyProc = SDLKey -> Bool
-- Get keyboard state and return function
getKeyState :: IO KeyProc
getKeyState = alloca $ \numkeysPtr -> do
keysPtr <- sdlGetKeyState numkeysPtr
if True
then do -- for anarchy: Use unsafePerformIO
let f = \k -> (/= 0) $ unsafePerformIO $ (peekByteOff keysPtr $ fromIntegral $ Graphics.UI.SDL.Utilities.fromEnum k :: IO Word8)
return f
else do -- for conservative
numkeys <- peek numkeysPtr
keys <- (map Graphics.UI.SDL.Utilities.toEnum . map fromIntegral . findIndices (== 1)) `fmap` peekArray (fromIntegral numkeys) keysPtr
return $ (`elem` keys)
key2btn :: KeyProc -> Int
key2btn ks = foldl (\r -> (r .|.) . uncurry press) 0 btns
where
btns = [
(padU, [SDLK_UP, SDLK_i]),
(padD, [SDLK_DOWN, SDLK_k]),
(padL, [SDLK_LEFT, SDLK_j]),
(padR, [SDLK_RIGHT, SDLK_l]),
(padA, [SDLK_SPACE, SDLK_z]),
(padB, [SDLK_LSHIFT, SDLK_RSHIFT])
]
press v ls = if any ks ls then v else 0
-- Delayed stream
-- return result list of action, interval microsec
delayedStream :: Int -> IO a -> IO [a]
delayedStream microsec func = unsafeInterleaveIO $ do
Graphics.UI.SDL.delay $ Prelude.toEnum $ microsec `div` 1000
x <- func
xs <- delayedStream microsec func
return $ x:xs
-- Process SDL events
-- return True if quit event has come
procSDLEvent :: IO Bool
procSDLEvent = do
ev <- pollEvent
case ev of
Quit -> return True
KeyDown (Keysym { symKey = ks, symModifiers = km } )
| ks == SDLK_ESCAPE -> return True
| ks == SDLK_F4 && (KeyModLeftAlt `elem` km || KeyModRightAlt `elem` km) -> return True
NoEvent -> return False
_ -> procSDLEvent
-- Image resource
type ImageResource = [(ImageType, Surface)]
-- Load image resources
loadImageResource :: [ImageType] -> IO ImageResource
loadImageResource = mapM load
where
load imgtype = do
sur <- loadBMP $ (imagePath ++) $ imageFn imgtype
setNuki sur
converted <- displayFormat sur
freeSurface sur
return (imgtype, converted)
setNuki sur = setColorKey sur [SrcColorKey] (Pixel 0) >> return () -- Set color key to palet 0
releaseImageResource :: ImageResource -> IO ()
releaseImageResource = mapM_ (\(_, sur) -> freeSurface sur)
getImageSurface :: ImageResource -> ImageType -> Surface
getImageSurface imgres = fromJust . (`lookup` imgres)
putimg :: Surface -> ImageResource -> ImageType -> Int -> Int -> IO ()
putimg sur imgres imgtype x y = do
blitSurface (getImageSurface imgres imgtype) Nothing sur (Just $ Rect x y 0 0)
return ()
-- Sound resource
type SoundResource = [(SoundType, Maybe Chunk)]
-- Load sound resources
loadSoundResource :: [SoundType] -> IO SoundResource
loadSoundResource sndtypes = mapM load sndtypes
where
load :: SoundType -> IO (SoundType, Maybe Chunk)
load sndtype = flip catch err $ do
dat <- loadWAV $ (soundPath ++) $ soundFn sndtype
return (sndtype, Just dat)
where
err _ = return (sndtype, Nothing)
-- From fixed point integer to cell coordinate
cellCrd :: Int -> Int
cellCrd x = x `div` (chrSize * one)
-- ========
--data Rect = Rect Int Int Int Int
ishit :: Rect -> Rect -> Bool
ishit (Rect l1 t1 r1 b1) (Rect l2 t2 r2 b2) =
l1 < r2 && t1 < b2 && l2 < r1 && t2 < b1