Render cannon direction; handle resize in GLX driver

This commit is contained in:
Matthias Schiffer 2010-03-05 03:32:02 +01:00
parent 88fd16d930
commit 1020310190
10 changed files with 91 additions and 63 deletions

View file

@ -17,4 +17,4 @@ data CPUPlayer = CPUPlayer Micro
deriving (Typeable, Show) deriving (Typeable, Show)
instance Player CPUPlayer where instance Player CPUPlayer where
playerMovement (CPUPlayer angle) _ = (CPUPlayer (if (angle+0.1) > 180 then angle-359.9 else angle+0.1), Just angle, True) playerUpdate (CPUPlayer angle) _ = (CPUPlayer (if (angle+0.1) > 180 then angle-359.9 else angle+0.1), Just angle, True, Just (-angle))

View file

@ -14,20 +14,20 @@ import Player
import Tank import Tank
data DefaultPlayer = DefaultPlayer (S.Set Key) data DefaultPlayer = DefaultPlayer (S.Set Key) Micro Micro
deriving (Typeable, Show) deriving (Typeable, Show)
instance Player DefaultPlayer where instance Player DefaultPlayer where
playerMovement (DefaultPlayer keys) _ = playerMovement' keys playerUpdate (DefaultPlayer keys aimx aimy) tank = playerUpdate' keys aimx aimy tank
handleEvent (DefaultPlayer keys) ev handleEvent (DefaultPlayer keys aimx aimy) ev
| Just (KeyPressEvent key) <- fromEvent ev = DefaultPlayer $ S.insert key keys | Just (KeyPressEvent key) <- fromEvent ev = DefaultPlayer (S.insert key keys) aimx aimy
| Just (KeyReleaseEvent key) <- fromEvent ev = DefaultPlayer $ S.delete key keys | Just (KeyReleaseEvent key) <- fromEvent ev = DefaultPlayer (S.delete key keys) aimx aimy
| otherwise = DefaultPlayer keys | otherwise = DefaultPlayer keys aimx aimy
playerMovement' :: S.Set Key -> (DefaultPlayer, Maybe Micro, Bool) playerUpdate' :: S.Set Key -> Micro -> Micro -> Tank -> (DefaultPlayer, Maybe Micro, Bool, Maybe Micro)
playerMovement' keys = (DefaultPlayer keys, angle, move) playerUpdate' keys aimx aimy tank = (DefaultPlayer keys aimx aimy, angle, move, Nothing)
where where
x = (if (S.member KeyLeft keys) then (-1) else 0) + (if (S.member KeyRight keys) then 1 else 0) x = (if (S.member KeyLeft keys) then (-1) else 0) + (if (S.member KeyRight keys) then 1 else 0)
y = (if (S.member KeyDown keys) then (-1) else 0) + (if (S.member KeyUp keys) then 1 else 0) y = (if (S.member KeyDown keys) then (-1) else 0) + (if (S.member KeyUp keys) then 1 else 0)

View file

@ -6,7 +6,7 @@ module GLDriver ( Driver(..)
, SomeEvent(..) , SomeEvent(..)
, fromEvent , fromEvent
, QuitEvent(..) , QuitEvent(..)
, ResizeEvent(..) --, ResizeEvent(..)
, Key(..) , Key(..)
, KeyPressEvent(..) , KeyPressEvent(..)
, KeyReleaseEvent(..) , KeyReleaseEvent(..)
@ -48,9 +48,6 @@ fromEvent (SomeEvent a) = cast a
data QuitEvent = QuitEvent deriving (Typeable, Show) data QuitEvent = QuitEvent deriving (Typeable, Show)
instance Event QuitEvent instance Event QuitEvent
data ResizeEvent = ResizeEvent Int Int deriving (Typeable, Show)
instance Event ResizeEvent
data Key = KeyLeft | KeyRight | KeyUp | KeyDown data Key = KeyLeft | KeyRight | KeyUp | KeyDown
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)

49
GLX.hs
View file

@ -9,6 +9,9 @@ import Control.Monad (when, unless)
import Data.Bits ((.|.)) import Data.Bits ((.|.))
import Data.Maybe (isJust) import Data.Maybe (isJust)
import Graphics.Rendering.OpenGL.GL (($=), GLdouble, Capability(..))
import Graphics.Rendering.OpenGL.GL.CoordTrans (matrixMode, MatrixMode(..), viewport, Position(..), Size(..), loadIdentity, ortho)
import Graphics.X11.Types import Graphics.X11.Types
import Graphics.X11.Xlib.Atom (internAtom) import Graphics.X11.Xlib.Atom (internAtom)
import Graphics.X11.Xlib.Display (defaultScreen, openDisplay, rootWindow) import Graphics.X11.Xlib.Display (defaultScreen, openDisplay, rootWindow)
@ -29,6 +32,7 @@ data GLX = GLX
, glxWindow :: !Window , glxWindow :: !Window
, glxContext :: !Context , glxContext :: !Context
, glxDeleteWindow :: !Atom , glxDeleteWindow :: !Atom
, glxScale :: !GLdouble
} }
glxDriver :: GLX glxDriver :: GLX
@ -37,6 +41,7 @@ glxDriver = GLX
, glxWindow = 0 , glxWindow = 0
, glxContext = Context nullPtr , glxContext = Context nullPtr
, glxDeleteWindow = 0 , glxDeleteWindow = 0
, glxScale = 1
} }
@ -60,7 +65,7 @@ instance Driver GLX where
rootwindow <- rootWindow disp (fromIntegral $ viScreen visualinfo) rootwindow <- rootWindow disp (fromIntegral $ viScreen visualinfo)
cmap <- createColormap disp rootwindow (viVisual visualinfo) allocNone cmap <- createColormap disp rootwindow (viVisual visualinfo) allocNone
let swa = nullSetWindowAttributes {swaColormap = cmap, swaEventMask = structureNotifyMask .|. keyPressMask .|. keyReleaseMask} let swa = nullSetWindowAttributes {swaColormap = cmap, swaEventMask = structureNotifyMask .|. keyPressMask .|. keyReleaseMask .|. pointerMotionMask}
wnd <- with swa $ \swaptr -> wnd <- with swa $ \swaptr ->
createWindow disp rootwindow 0 0 800 600 0 (fromIntegral $ viDepth visualinfo) inputOutput (viVisual visualinfo) (cWBorderPixel.|.cWColormap.|.cWEventMask) swaptr createWindow disp rootwindow 0 0 800 600 0 (fromIntegral $ viDepth visualinfo) inputOutput (viVisual visualinfo) (cWBorderPixel.|.cWColormap.|.cWEventMask) swaptr
@ -77,11 +82,14 @@ instance Driver GLX where
ctx <- with visualinfo $ \vi -> createContext disp vi (Context nullPtr) True ctx <- with visualinfo $ \vi -> createContext disp vi (Context nullPtr) True
makeCurrent disp wnd ctx makeCurrent disp wnd ctx
resize 800 600
return GLX return GLX
{ glxDisplay = disp { glxDisplay = disp
, glxWindow = wnd , glxWindow = wnd
, glxContext = ctx , glxContext = ctx
, glxDeleteWindow = delwnd , glxDeleteWindow = delwnd
, glxScale = 1
} }
deinitGL glx = do deinitGL glx = do
@ -90,33 +98,34 @@ instance Driver GLX where
swapBuffers glx = Bindings.GLX.swapBuffers (glxDisplay glx) (glxWindow glx) swapBuffers glx = Bindings.GLX.swapBuffers (glxDisplay glx) (glxWindow glx)
nextEvent glx = allocaXEvent $ nextEvent' glx $ glxDisplay glx nextEvent glx = allocaXEvent $ nextEvent' glx
nextEvent' :: GLX -> Display -> XEventPtr -> IO (Maybe SomeEvent) nextEvent' :: GLX -> XEventPtr -> IO (Maybe SomeEvent)
nextEvent' glx disp xevent = do nextEvent' glx xevent = do
p <- pending disp p <- pending $ glxDisplay glx
if (p > 0) then do if (p > 0) then do
Graphics.X11.Xlib.Event.nextEvent disp xevent Graphics.X11.Xlib.Event.nextEvent (glxDisplay glx) xevent
ev <- handleEvent glx disp xevent ev <- handleEvent glx xevent
if isJust ev then if isJust ev then
return ev return ev
else else
nextEvent' glx disp xevent nextEvent' glx xevent
else else
return Nothing return Nothing
handleEvent :: GLX -> Display -> XEventPtr -> IO (Maybe SomeEvent) handleEvent :: GLX -> XEventPtr -> IO (Maybe SomeEvent)
handleEvent glx disp xevent = do handleEvent glx xevent = do
event <- getEvent xevent event <- getEvent xevent
let evtype = ev_event_type event let evtype = ev_event_type event
case () of case () of
_ | evtype == configureNotify -> do _ | evtype == configureNotify -> do
return $ Just $ SomeEvent $ ResizeEvent (fromIntegral . ev_width $ event) (fromIntegral . ev_height $ event) resize (fromIntegral . ev_width $ event) (fromIntegral . ev_height $ event)
return Nothing
| evtype == keyPress -> do | evtype == keyPress -> do
keysym <- keycodeToKeysym disp (ev_keycode event) 0 keysym <- keycodeToKeysym (glxDisplay glx) (ev_keycode event) 0
case () of case () of
_ | keysym == xK_Escape -> return $ Just $ SomeEvent QuitEvent _ | keysym == xK_Escape -> return $ Just $ SomeEvent QuitEvent
| keysym == xK_Up -> return $ Just $ SomeEvent $ KeyPressEvent KeyUp | keysym == xK_Up -> return $ Just $ SomeEvent $ KeyPressEvent KeyUp
@ -125,7 +134,7 @@ handleEvent glx disp xevent = do
| keysym == xK_Right -> return $ Just $ SomeEvent $ KeyPressEvent KeyRight | keysym == xK_Right -> return $ Just $ SomeEvent $ KeyPressEvent KeyRight
| otherwise -> return Nothing | otherwise -> return Nothing
| evtype == keyRelease -> do | evtype == keyRelease -> do
keysym <- keycodeToKeysym disp (ev_keycode event) 0 keysym <- keycodeToKeysym (glxDisplay glx) (ev_keycode event) 0
case () of case () of
_ | keysym == xK_Up -> return $ Just $ SomeEvent $ KeyReleaseEvent KeyUp _ | keysym == xK_Up -> return $ Just $ SomeEvent $ KeyReleaseEvent KeyUp
| keysym == xK_Down -> return $ Just $ SomeEvent $ KeyReleaseEvent KeyDown | keysym == xK_Down -> return $ Just $ SomeEvent $ KeyReleaseEvent KeyDown
@ -141,6 +150,20 @@ handleEvent glx disp xevent = do
| otherwise -> return Nothing | otherwise -> return Nothing
resize :: Int -> Int -> IO ()
resize w h = do
let aspect = (fromIntegral w)/(fromIntegral h)
s = max (5/aspect) 5 :: GLdouble
matrixMode $= Projection
loadIdentity
ortho (-s*aspect) (s*aspect) (-s) s (-1) 1
matrixMode $= Modelview 0
viewport $= ((Position 0 0), (Size (fromIntegral w) (fromIntegral h)))
waitForMapNotify :: Display -> Window -> IO () waitForMapNotify :: Display -> Window -> IO ()
waitForMapNotify disp wnd = allocaXEvent waitForMapNotify' waitForMapNotify disp wnd = allocaXEvent waitForMapNotify'
where where

View file

@ -44,7 +44,7 @@ main = do
when (initialized gl) $ do when (initialized gl) $ do
currentTime <- getCurrentTime currentTime <- getCurrentTime
let mainState = MainState {run = True, driver = SomeDriver gl, time = currentTime, players = let mainState = MainState {run = True, driver = SomeDriver gl, time = currentTime, players =
[ SomePlayer $ DefaultPlayer S.empty [ SomePlayer $ DefaultPlayer S.empty 0 0
, SomePlayer $ CPUPlayer 0 , SomePlayer $ CPUPlayer 0
]} ]}
gameState = GameState {level = testLevel, tanks = [ Tank 0.0 0.0 0 0 2 360 False gameState = GameState {level = testLevel, tanks = [ Tank 0.0 0.0 0 0 2 360 False
@ -52,7 +52,7 @@ main = do
], textures = M.empty} ], textures = M.empty}
runGame gameState $ do runGame gameState $ do
setup 800 600 setup
runMain mainState mainLoop runMain mainState mainLoop
deinitGL gl deinitGL gl
@ -123,11 +123,14 @@ updateAngle angle = do
modify $ \tank -> tank {dir = newangle180} modify $ \tank -> tank {dir = newangle180}
updateTank :: Maybe Micro -> Bool -> State Tank () updateTank :: Maybe Micro -> Bool -> Maybe Micro -> State Tank ()
updateTank angle move = do updateTank angle move aangle = do
when (isJust angle) $ when (isJust angle) $
updateAngle $ fromJust angle updateAngle $ fromJust angle
when (isJust aangle) $
modify $ \tank -> tank {aim = fromJust aangle}
when move $ do when move $ do
tdir <- gets dir tdir <- gets dir
tspeed <- gets speed tspeed <- gets speed
@ -154,8 +157,8 @@ simulationStep = do
modify $ \state -> state {players = fst pt} modify $ \state -> state {players = fst pt}
lift $ modify $ \state -> state {tanks = snd pt} lift $ modify $ \state -> state {tanks = snd pt}
where where
updateTank' (player, tank) = let (p, angle, move) = playerMovement player tank updateTank' (player, tank) = let (p, angle, move, aangle) = playerUpdate player tank
t = execState (updateTank angle move) tank t = execState (updateTank angle move aangle) tank
in (p, t) in (p, t)
@ -169,6 +172,5 @@ handleEvents = do
handleEvent :: SomeEvent -> Main () handleEvent :: SomeEvent -> Main ()
handleEvent ev handleEvent ev
| Just (ResizeEvent w h) <- fromEvent ev = lift $ resize w h | Just QuitEvent <- fromEvent ev = modify $ \state -> state {run = False}
| Just QuitEvent <- fromEvent ev = modify $ \state -> state {run = False}
| otherwise = return () | otherwise = return ()

View file

@ -12,7 +12,7 @@ import GLDriver (SomeEvent)
class Player a where class Player a where
playerMovement :: a -> Tank -> (a, Maybe Micro, Bool) playerUpdate :: a -> Tank -> (a, Maybe Micro, Bool, Maybe Micro)
handleEvent :: a -> SomeEvent -> a handleEvent :: a -> SomeEvent -> a
handleEvent player _ = player handleEvent player _ = player
@ -21,5 +21,7 @@ class Player a where
data SomePlayer = forall a. Player a => SomePlayer a data SomePlayer = forall a. Player a => SomePlayer a
instance Player SomePlayer where instance Player SomePlayer where
playerMovement (SomePlayer player) tank = (\(p, angle, move) -> (SomePlayer p, angle, move)) $ playerMovement player tank playerUpdate (SomePlayer player) tank =
let (p, angle, move, aangle) = playerUpdate player tank
in (SomePlayer p, angle, move, aangle)
handleEvent (SomePlayer player) event = SomePlayer $ handleEvent player event handleEvent (SomePlayer player) event = SomePlayer $ handleEvent player event

View file

@ -1,5 +1,5 @@
module Render ( setup module Render ( setup
, resize --, resize
, render , render
) where ) where
@ -34,6 +34,7 @@ texturePath :: Texture -> String
texturePath t texturePath t
| t == TextureWood = "tex/Wood.png" | t == TextureWood = "tex/Wood.png"
| t == TextureTank = "tex/Tank.png" | t == TextureTank = "tex/Tank.png"
| t == TextureCannon = "tex/Cannon.png"
getTexture :: Texture -> Game TextureObject getTexture :: Texture -> Game TextureObject
getTexture t = do getTexture t = do
@ -49,9 +50,8 @@ getTexture t = do
return tex return tex
setup :: Int -> Int -> Game () setup :: Game ()
setup w h = do setup = do
resize w h
liftIO $ do liftIO $ do
blend $= Enabled blend $= Enabled
blendFunc $= (SrcAlpha, OneMinusSrcAlpha) blendFunc $= (SrcAlpha, OneMinusSrcAlpha)
@ -59,33 +59,17 @@ setup w h = do
-- cache textures -- cache textures
getTexture TextureWood getTexture TextureWood
getTexture TextureTank getTexture TextureTank
getTexture TextureCannon
return () return ()
resize :: Int -> Int -> Game ()
resize w h = do
let wn = fromIntegral w
hn = fromIntegral h
aspect = fromReal (wn/hn)
lvl <- gets level
let s = max (0.5*(fromIntegral $ levelWidth lvl)/aspect) (0.5*(fromIntegral $ levelHeight lvl)) :: GLdouble
liftIO $ do
matrixMode $= Projection
loadIdentity
ortho (-s*aspect) (s*aspect) (-s) s (-1) 1
matrixMode $= Modelview 0
viewport $= ((Position 0 0), (Size (fromIntegral w) (fromIntegral h)))
render :: Game () render :: Game ()
render = do render = do
tanklist <- gets tanks tanklist <- gets tanks
textureWood <- getTexture TextureWood textureWood <- getTexture TextureWood
textureTank <- getTexture TextureTank textureTank <- getTexture TextureTank
textureCannon <- getTexture TextureCannon
(lw, lh) <- gets level >>= \l -> return (fromIntegral . levelWidth $ l :: GLfloat, fromIntegral . levelHeight $ l :: GLfloat) (lw, lh) <- gets level >>= \l -> return (fromIntegral . levelWidth $ l :: GLfloat, fromIntegral . levelHeight $ l :: GLfloat)
@ -108,14 +92,16 @@ render = do
texCoord $ TexCoord2 lh (0 :: GLfloat) texCoord $ TexCoord2 lh (0 :: GLfloat)
vertex $ Vertex2 (0.5*lw) (-0.5*lh) vertex $ Vertex2 (0.5*lw) (-0.5*lh)
textureBinding Texture2D $= Just textureTank
forM_ tanklist $ \tank -> preservingMatrix $ do forM_ tanklist $ \tank -> preservingMatrix $ do
let x = fromReal . posx $ tank let x = fromReal . posx $ tank
y = fromReal . posy $ tank y = fromReal . posy $ tank
rotDir = 90 + (fromReal . dir $ tank)
rotAim = 90 + (fromReal . aim $ tank)
translate $ Vector3 x y (0 :: GLfloat) translate $ Vector3 x y (0 :: GLfloat)
rotate (90 + (fromReal . dir $ tank)) $ Vector3 0 0 (1 :: GLfloat) rotate rotDir $ Vector3 0 0 (1 :: GLfloat)
textureBinding Texture2D $= Just textureTank
renderPrimitive Quads $ do renderPrimitive Quads $ do
texCoord $ TexCoord2 (0 :: GLfloat) (0 :: GLfloat) texCoord $ TexCoord2 (0 :: GLfloat) (0 :: GLfloat)
@ -130,5 +116,23 @@ render = do
texCoord $ TexCoord2 (1 :: GLfloat) (0 :: GLfloat) texCoord $ TexCoord2 (1 :: GLfloat) (0 :: GLfloat)
vertex $ Vertex2 (0.5 :: GLfloat) (-0.5 :: GLfloat) vertex $ Vertex2 (0.5 :: GLfloat) (-0.5 :: GLfloat)
rotate (rotAim-rotDir) $ Vector3 0 0 (1 :: GLfloat)
textureBinding Texture2D $= Just textureCannon
renderPrimitive Quads $ do
texCoord $ TexCoord2 (0 :: GLfloat) (0 :: GLfloat)
vertex $ Vertex2 (-0.5 :: GLfloat) (-0.5 :: GLfloat)
texCoord $ TexCoord2 (0 :: GLfloat) (1 :: GLfloat)
vertex $ Vertex2 (-0.5 :: GLfloat) (0.5 :: GLfloat)
texCoord $ TexCoord2 (1 :: GLfloat) (1 :: GLfloat)
vertex $ Vertex2 (0.5 :: GLfloat) (0.5 :: GLfloat)
texCoord $ TexCoord2 (1 :: GLfloat) (0 :: GLfloat)
vertex $ Vertex2 (0.5 :: GLfloat) (-0.5 :: GLfloat)
fromReal :: (Real a, Fractional b) => a -> b fromReal :: (Real a, Fractional b) => a -> b
fromReal = fromRational . toRational fromReal = fromRational . toRational

View file

@ -4,6 +4,6 @@ module Texture ( Texture(..)
import Graphics.Rendering.OpenGL.GL.Texturing.Objects (TextureObject) import Graphics.Rendering.OpenGL.GL.Texturing.Objects (TextureObject)
data Texture = TextureWood | TextureTank data Texture = TextureWood | TextureTank | TextureCannon
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)

BIN
tex/Cannon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 1.1 KiB