From 990f1a7daf5b648b9432df99e8ced2b703a3c935 Mon Sep 17 00:00:00 2001 From: nek0 Date: Tue, 19 Dec 2017 06:49:41 +0100 Subject: [PATCH] make it work with nanovg --- assets/haskelloid.png | Bin 0 -> 44788 bytes haskelloids.cabal | 4 ++- src/Commons.hs | 6 ++++ src/Init.hs | 27 +++++++++++---- src/Main.hs | 13 ++++++-- src/Menu.hs | 76 ++++++++++++++++++++++++++++++++---------- src/StateMachine.hs | 2 +- src/Types.hs | 44 ++++++++++++++++++++++++ 8 files changed, 143 insertions(+), 29 deletions(-) create mode 100644 assets/haskelloid.png diff --git a/assets/haskelloid.png b/assets/haskelloid.png new file mode 100644 index 0000000000000000000000000000000000000000..f75a4e7d5e45cbb074192a4db23bc4cf0a82e0e2 GIT binary patch literal 44788 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 2.1.3.1 , containers , random - , nanovg , linear + , stm + , nanovg -- Directories containing source files. hs-source-dirs: src diff --git a/src/Commons.hs b/src/Commons.hs index ff60770..8544682 100644 --- a/src/Commons.hs +++ b/src/Commons.hs @@ -59,3 +59,9 @@ updateHaskelloid sec has = { hPos = hPos has + hVel has * V2 sec sec , hRot = hRot has + hPitch has * sec } + +clamp :: Ord a => a -> a -> a -> a +clamp a' low up + | a' < low = low + | a' > up = up + | otherwise = a' diff --git a/src/Init.hs b/src/Init.hs index d3cd264..8f8b200 100644 --- a/src/Init.hs +++ b/src/Init.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE ForeignFunctionInterface #-} module Init where import Affection as A @@ -10,26 +11,39 @@ import Data.Maybe import Control.Monad (when) import Control.Monad.IO.Class (liftIO) +import Control.Concurrent.STM import System.Random - -import NanoVG hiding (V2(..)) +import System.Exit (exitFailure) import Linear +import NanoVG hiding (V2) + +import Foreign.C.Types (CInt(..)) + -- Internal imports import Types +foreign import ccall unsafe "glewInit" + glewInit :: IO CInt + load :: IO UserData load = do + liftIO $ logIO A.Debug "init GLEW" + _ <- glewInit liftIO $ logIO A.Debug "loading state" - liftIO $ logIO A.Debug "creating NanoVG context" - nvgCtx <- createGL3 (S.fromList [Antialias, StencilStrokes]) + liftIO $ logIO A.Debug "create context" + nvgCtx <- createGL3 (S.fromList [Antialias, StencilStrokes, NanoVG.Debug]) liftIO $ logIO A.Debug "load ship image" - mshipImage <- createImage nvgCtx (FileName "assets/ship.svg") 0 - when (isNothing mshipImage) $ + mshipImage <- createImage nvgCtx (FileName "assets/ship.png") 0 + when (isNothing mshipImage) $ do logIO Error "Failed loading image assets" + exitFailure + subs <- Subsystems + <$> (return . Window =<< newTVarIO []) + <*> (return . Keyboard =<< newTVarIO []) return UserData { ship = Ship { sPos = V2 400 300 @@ -42,6 +56,7 @@ load = do , state = Menu , fade = FadeIn 1 , nano = nvgCtx + , subsystems = subs } diff --git a/src/Main.hs b/src/Main.hs index c132847..d206e91 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -1,7 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} module Main where -import Affection +import Affection as A import SDL (($=)) import qualified SDL @@ -9,6 +9,10 @@ import qualified Data.Map as M import Linear as L +import NanoVG + +import Control.Monad.IO.Class (liftIO) + -- internal imports import Types @@ -18,7 +22,7 @@ import Init main :: IO () main = do - logIO Debug "Starting" + logIO A.Debug "Starting" withAffection AffectionConfig { initComponents = All , windowTitle = "Haskelloids" @@ -49,7 +53,10 @@ handle e = do draw :: Affection UserData () draw = do - return () + ud <- getAffection + liftIO $ beginFrame (nano ud) 800 600 (800/600) + smDraw (state ud) + liftIO $ endFrame (nano ud) -- GL.viewport $= (GL.Position 0 0, GL.Size 800 600) -- ud <- getAffection -- GL.currentProgram $= (Just . GLU.program $ program sd) diff --git a/src/Menu.hs b/src/Menu.hs index 389ee59..1976332 100644 --- a/src/Menu.hs +++ b/src/Menu.hs @@ -12,7 +12,11 @@ import Control.Monad.IO.Class (liftIO) import qualified Data.Map as M -import NanoVG +import NanoVG hiding (V2(..)) + +import Linear + +import Foreign.C.Types -- internal imports @@ -20,23 +24,10 @@ import Types import Commons handleMenuEvent :: (Affection UserData ()) -> [SDL.EventPayload] -> Affection UserData () -handleMenuEvent loader es = - mapM_ (\e -> - case e of - SDL.KeyboardEvent dat -> - case SDL.keysymKeycode $ SDL.keyboardEventKeysym dat of - SDL.KeycodeSpace -> - when (SDL.keyboardEventKeyMotion dat == SDL.Pressed) $ do - ud <- getAffection - loader - _ -> return () - SDL.WindowClosedEvent _ -> do - ad <- get - put ad - { quitEvent = True - } - _ -> return () - ) es +handleMenuEvent _ es = do + (Subsystems w k) <- subsystems <$> getAffection + _ <- consumeSDLEvents w =<< consumeSDLEvents k es + return () loadMenu :: Affection UserData () loadMenu = do @@ -47,6 +38,17 @@ loadMenu = do when (isNothing mhaskImage) $ liftIO $ logIO Error "Failed to load asset haskelloid" hs <- newHaskelloids (fromJust mhaskImage) + _ <- partSubscribe (subKeyboard $ subsystems ud) + (\kbdev -> case SDL.keysymKeycode (msgKbdKeysym kbdev) of + SDL.KeycodeEscape -> do + liftIO $ logIO A.Debug "seeya" + quit + SDL.KeycodeF -> do + when (msgKbdKeyMotion kbdev == SDL.Pressed) $ do + liftIO $ logIO A.Debug "screen toggling" + toggleScreen + _ -> return () + ) putAffection ud { haskelloids = hs , fade = FadeIn 1 @@ -70,3 +72,41 @@ updateMenu sec = do { fade = if (ttl - sec) > 0 then FadeOut (ttl - sec) else FadeIn 1 , haskelloids = nhs } + +drawMenu :: Affection UserData () +drawMenu = do + ud <- getAffection + let V2 sx sy = fmap (CFloat . realToFrac) (sPos $ ship ud) + liftIO $ do + save (nano ud) + sPaint <- imagePattern (nano ud) 400 300 20 20 0 (sImg $ ship ud) 255 + beginPath (nano ud) + rect (nano ud) 400 300 20 20 + fillPaint (nano ud) sPaint + fill (nano ud) + restore (nano ud) + dt <- getElapsedTime + liftIO $ + drawSpinner (nano ud) 100 100 100 (CFloat $ realToFrac dt) + +drawSpinner :: Context -> CFloat -> CFloat -> CFloat -> CFloat -> IO () +drawSpinner vg cx cy r t = do + let a0 = 0+t*6 + a1 = pi + t*6 + r0 = r + r1 = r*0.75 + save vg + + beginPath vg + arc vg cx cy r0 a0 a1 CW + arc vg cx cy r1 a1 a0 CCW + closePath vg + let ax = cx+cos a0 * (r0+r1)*0.5 + ay = cy+sin a0 * (r0+r1)*0.5 + bx = cx+cos a1 * (r0+r1)*0.5 + by = cy+sin a1 * (r0+r1)*0.5 + paint <- linearGradient vg ax ay bx by (rgba 255 255 255 0) (rgba 255 255 255 128) + fillPaint vg paint + fill vg + + restore vg diff --git a/src/StateMachine.hs b/src/StateMachine.hs index 5aad6ca..920489a 100644 --- a/src/StateMachine.hs +++ b/src/StateMachine.hs @@ -30,6 +30,6 @@ instance StateMachine State UserData where -- smEvent InGame = handleGameEvent - smDraw Menu = return () + smDraw Menu = drawMenu -- smDraw InGame = drawGame diff --git a/src/Types.hs b/src/Types.hs index 3c72a58..11ba3ae 100644 --- a/src/Types.hs +++ b/src/Types.hs @@ -7,6 +7,9 @@ import qualified SDL import NanoVG hiding (V2(..)) import Linear +import Control.Concurrent.STM +import Control.Monad.IO.Class (liftIO) + data UserData = UserData { ship :: Ship , haskelloids :: [Haskelloid] @@ -17,6 +20,7 @@ data UserData = UserData , state :: State , fade :: MenuFade , nano :: Context + , subsystems :: Subsystems } data Ship = Ship @@ -48,3 +52,43 @@ data WonLost = Won | Lost deriving (Eq) + +data Subsystems = Subsystems + { subWindow :: Window + , subKeyboard :: Keyboard + } + +newtype Window = Window (TVar [(UUID, WindowMessage -> Affection UserData ())]) + +instance Participant Window WindowMessage UserData where + partSubscribers (Window t) = do + subTups <- liftIO $ readTVarIO t + return $ map snd subTups + + partSubscribe (Window t) = generalSubscribe t + + partUnSubscribe (Window t) uuid = + liftIO $ atomically $ modifyTVar' t (filter (\(u, _) -> u /= uuid)) + +instance SDLSubsystem Window UserData where + consumeSDLEvents = consumeSDLWindowEvents + +newtype Keyboard = Keyboard (TVar [(UUID, KeyboardMessage -> Affection UserData ())]) + +instance Participant Keyboard KeyboardMessage UserData where + partSubscribers (Keyboard t) = do + subTups <- liftIO $ readTVarIO t + return $ map snd subTups + + partSubscribe (Keyboard t) = generalSubscribe t + + partUnSubscribe (Keyboard t) uuid = + liftIO $ atomically $ modifyTVar' t (filter (\(u, _) -> u /= uuid)) + +instance SDLSubsystem Keyboard UserData where + consumeSDLEvents = consumeSDLKeyboardEvents + +generalSubscribe t funct = do + uuid <- genUUID + liftIO $ atomically $ modifyTVar' t ((uuid, funct) :) + return uuid