From 475bcc107ba65dacae361b47af916511e470414e Mon Sep 17 00:00:00 2001 From: Stefan Dresselhaus Date: Mon, 20 Jan 2014 13:51:40 +0100 Subject: [PATCH] removed testfile --- test2.hs | 660 ------------------------------------------------------- 1 file changed, 660 deletions(-) delete mode 100644 test2.hs diff --git a/test2.hs b/test2.hs deleted file mode 100644 index fe31cd2..0000000 --- a/test2.hs +++ /dev/null @@ -1,660 +0,0 @@ -module Main (main) where - --------------------------------------------------------------------------------- - -import Control.Concurrent.STM (TQueue, atomically, newTQueueIO, tryReadTQueue, writeTQueue) -import Control.Monad (unless, when, void) -import Control.Monad.RWS.Strict (RWST, ask, asks, evalRWST, get, liftIO, modify, put) -import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT) -import Data.List (intercalate) -import Data.Maybe (catMaybes) -import Text.PrettyPrint -import Control.Applicative -import Control.Lens -import Control.Monad (forever) -import Data.Distributive (distribute) -import Foreign (Ptr, castPtr, nullPtr, sizeOf, with) -import Foreign.C (CFloat) - -import Graphics.Rendering.OpenGL (($=)) -import qualified Graphics.Rendering.OpenGL as GL -import qualified Graphics.Rendering.OpenGL.Raw as GL -import qualified Graphics.UI.GLFW as GLFW -import qualified Data.Text as Text -import qualified Data.Text.Encoding as Text -import qualified Data.Vector.Storable as V -import Linear as L -import Linear ((!*!)) - -import Data.IORef - --------------------------------------------------------------------------------- - -data Env = Env - { envEventsChan :: TQueue Event - , envWindow :: !GLFW.Window - , envGear1 :: !GL.DisplayList - , envGear2 :: !GL.DisplayList - , envGear3 :: !GL.DisplayList - , envZDistClosest :: !Double - , envZDistFarthest :: !Double - } - -data State = State - { stateWindowWidth :: !Int - , stateWindowHeight :: !Int - , stateXAngle :: !Double - , stateYAngle :: !Double - , stateZAngle :: !Double - , stateGearZAngle :: !Double - , stateZDist :: !Double - , stateMouseDown :: !Bool - , stateDragging :: !Bool - , stateDragStartX :: !Double - , stateDragStartY :: !Double - , stateDragStartXAngle :: !Double - , stateDragStartYAngle :: !Double - } - -type Demo = RWST Env () State IO - --------------------------------------------------------------------------------- - -data Event = - EventError !GLFW.Error !String - | EventWindowPos !GLFW.Window !Int !Int - | EventWindowSize !GLFW.Window !Int !Int - | EventWindowClose !GLFW.Window - | EventWindowRefresh !GLFW.Window - | EventWindowFocus !GLFW.Window !GLFW.FocusState - | EventWindowIconify !GLFW.Window !GLFW.IconifyState - | EventFramebufferSize !GLFW.Window !Int !Int - | EventMouseButton !GLFW.Window !GLFW.MouseButton !GLFW.MouseButtonState !GLFW.ModifierKeys - | EventCursorPos !GLFW.Window !Double !Double - | EventCursorEnter !GLFW.Window !GLFW.CursorState - | EventScroll !GLFW.Window !Double !Double - | EventKey !GLFW.Window !GLFW.Key !Int !GLFW.KeyState !GLFW.ModifierKeys - | EventChar !GLFW.Window !Char - deriving Show - --------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- -triangleTransformation :: (Epsilon a, Floating a) => a -> M44 a -triangleTransformation = - liftA2 (!*!) triangleTranslation triangleRotation - --------------------------------------------------------------------------------- -triangleRotation :: (Epsilon a, Floating a) => a -> M44 a -triangleRotation t = - m33_to_m44 $ - fromQuaternion $ - axisAngle (V3 0 1 0) (t * 2) - -triangleTranslation :: Floating a => a -> M44 a -triangleTranslation t = - eye4 & translation .~ V3 (sin t * 2) 0 (-5) - --------------------------------------------------------------------------------- - -main :: IO () -main = do - let width = 640 - height = 480 - - eventsChan <- newTQueueIO :: IO (TQueue Event) - - withWindow width height "GLFW-b-demo" $ \win -> do - let z = 0 - let vertices = V.fromList [ 0, 1, 0 - , -1, -1, z - , 1, -1, z ] :: V.Vector Float - vertexAttribute = GL.AttribLocation 0 - - cubeVbo <- GL.genObjectName - - GL.bindBuffer GL.ArrayBuffer $= Just cubeVbo - - V.unsafeWith vertices $ \v -> GL.bufferData GL.ArrayBuffer $= - (fromIntegral $ V.length vertices * sizeOf (0 :: Float), v, GL.StaticDraw) - - GL.vertexAttribPointer vertexAttribute $= - (GL.ToFloat, GL.VertexArrayDescriptor 3 GL.Float 0 nullPtr) - - GL.vertexAttribArray vertexAttribute $= GL.Enabled - GL.bindBuffer GL.ArrayBuffer $= Just cubeVbo - - vertexShader <- GL.createShader GL.VertexShader - fragmentShader <- GL.createShader GL.FragmentShader - - GL.shaderSourceBS vertexShader $= Text.encodeUtf8 - (Text.pack $ unlines - [ "#version 130" - , "uniform mat4 projection;" - , "uniform mat4 model;" - , "in vec3 in_Position;" - , "void main(void) {" - , " gl_Position = projection * model * vec4(in_Position, 1.0);" - , "}" - ]) - - GL.shaderSourceBS fragmentShader $= Text.encodeUtf8 - (Text.pack $ unlines - [ "#version 130" - , "out vec4 fragColor;" - , "void main(void) {" - , " fragColor = vec4(1.0,1.0,1.0,1.0);" - , "}" - ]) - - GL.compileShader vertexShader - GL.compileShader fragmentShader - - shaderProg <- GL.createProgram - GL.attachShader shaderProg vertexShader - GL.attachShader shaderProg fragmentShader - GL.attribLocation shaderProg "in_Position" $= vertexAttribute - GL.linkProgram shaderProg - GL.currentProgram $= Just shaderProg - - let fov = 90 - s = recip (tan $ fov * 0.5 * pi / 180) - f = 1000 - n = 1 - - let perspective = V.fromList [ s, 0, 0, 0 - , 0, s, 0, 0 - , 0, 0, -(f/(f - n)), -1 - , 0, 0, -((f*n)/(f-n)), 0 - ] - - GL.UniformLocation loc <- GL.get (GL.uniformLocation shaderProg "projection") - V.unsafeWith perspective $ \ptr -> GL.glUniformMatrix4fv loc 1 0 ptr - - tr <- newIORef 0 - forever $ do - t <- readIORef tr - - GL.clearColor $= GL.Color4 0.5 0.2 1 1 - GL.clear [GL.ColorBuffer] - - GL.UniformLocation loc <- GL.get (GL.uniformLocation shaderProg "model") - with (distribute $ triangleTransformation t) $ \ptr -> - GL.glUniformMatrix4fv loc 1 0 (castPtr (ptr :: Ptr (M44 CFloat))) - - GL.drawArrays GL.Triangles 0 3 - - GLFW.swapBuffers win - writeIORef tr (t + 0.1) - --------------------------------------------------------------------------------- - --- GLFW-b is made to be very close to the C API, so creating a window is pretty --- clunky by Haskell standards. A higher-level API would have some function --- like withWindow. - -withWindow :: Int -> Int -> String -> (GLFW.Window -> IO ()) -> IO () -withWindow width height title f = do - GLFW.setErrorCallback $ Just simpleErrorCallback - r <- GLFW.init - when r $ do - m <- GLFW.createWindow width height title Nothing Nothing - case m of - (Just win) -> do - GLFW.makeContextCurrent m - f win - GLFW.setErrorCallback $ Just simpleErrorCallback - GLFW.destroyWindow win - Nothing -> return () - GLFW.terminate - where - simpleErrorCallback e s = - putStrLn $ unwords [show e, show s] - --------------------------------------------------------------------------------- - --- Each callback does just one thing: write an appropriate Event to the events --- TQueue. - -errorCallback :: TQueue Event -> GLFW.Error -> String -> IO () -windowPosCallback :: TQueue Event -> GLFW.Window -> Int -> Int -> IO () -windowSizeCallback :: TQueue Event -> GLFW.Window -> Int -> Int -> IO () -windowCloseCallback :: TQueue Event -> GLFW.Window -> IO () -windowRefreshCallback :: TQueue Event -> GLFW.Window -> IO () -windowFocusCallback :: TQueue Event -> GLFW.Window -> GLFW.FocusState -> IO () -windowIconifyCallback :: TQueue Event -> GLFW.Window -> GLFW.IconifyState -> IO () -framebufferSizeCallback :: TQueue Event -> GLFW.Window -> Int -> Int -> IO () -mouseButtonCallback :: TQueue Event -> GLFW.Window -> GLFW.MouseButton -> GLFW.MouseButtonState -> GLFW.ModifierKeys -> IO () -cursorPosCallback :: TQueue Event -> GLFW.Window -> Double -> Double -> IO () -cursorEnterCallback :: TQueue Event -> GLFW.Window -> GLFW.CursorState -> IO () -scrollCallback :: TQueue Event -> GLFW.Window -> Double -> Double -> IO () -keyCallback :: TQueue Event -> GLFW.Window -> GLFW.Key -> Int -> GLFW.KeyState -> GLFW.ModifierKeys -> IO () -charCallback :: TQueue Event -> GLFW.Window -> Char -> IO () - -errorCallback tc e s = atomically $ writeTQueue tc $ EventError e s -windowPosCallback tc win x y = atomically $ writeTQueue tc $ EventWindowPos win x y -windowSizeCallback tc win w h = atomically $ writeTQueue tc $ EventWindowSize win w h -windowCloseCallback tc win = atomically $ writeTQueue tc $ EventWindowClose win -windowRefreshCallback tc win = atomically $ writeTQueue tc $ EventWindowRefresh win -windowFocusCallback tc win fa = atomically $ writeTQueue tc $ EventWindowFocus win fa -windowIconifyCallback tc win ia = atomically $ writeTQueue tc $ EventWindowIconify win ia -framebufferSizeCallback tc win w h = atomically $ writeTQueue tc $ EventFramebufferSize win w h -mouseButtonCallback tc win mb mba mk = atomically $ writeTQueue tc $ EventMouseButton win mb mba mk -cursorPosCallback tc win x y = atomically $ writeTQueue tc $ EventCursorPos win x y -cursorEnterCallback tc win ca = atomically $ writeTQueue tc $ EventCursorEnter win ca -scrollCallback tc win x y = atomically $ writeTQueue tc $ EventScroll win x y -keyCallback tc win k sc ka mk = atomically $ writeTQueue tc $ EventKey win k sc ka mk -charCallback tc win c = atomically $ writeTQueue tc $ EventChar win c - --------------------------------------------------------------------------------- - -runDemo :: Env -> State -> IO () -runDemo env state = do - printInstructions - void $ evalRWST (adjustWindow >> run) env state - -run :: Demo () -run = do - win <- asks envWindow - - draw - liftIO $ do - GLFW.swapBuffers win - GL.flush -- not necessary, but someone recommended it - GLFW.pollEvents - processEvents - - state <- get - if stateDragging state - then do - let sodx = stateDragStartX state - sody = stateDragStartY state - sodxa = stateDragStartXAngle state - sodya = stateDragStartYAngle state - (x, y) <- liftIO $ GLFW.getCursorPos win - let myrot = (x - sodx) / 2 - mxrot = (y - sody) / 2 - put $ state - { stateXAngle = sodxa + mxrot - , stateYAngle = sodya + myrot - } - else do - (kxrot, kyrot) <- liftIO $ getCursorKeyDirections win - (jxrot, jyrot) <- liftIO $ getJoystickDirections GLFW.Joystick'1 - put $ state - { stateXAngle = stateXAngle state + (2 * kxrot) + (2 * jxrot) - , stateYAngle = stateYAngle state + (2 * kyrot) + (2 * jyrot) - } - - mt <- liftIO GLFW.getTime - modify $ \s -> s - { stateGearZAngle = maybe 0 (realToFrac . (100*)) mt - } - - q <- liftIO $ GLFW.windowShouldClose win - unless q run - -processEvents :: Demo () -processEvents = do - tc <- asks envEventsChan - me <- liftIO $ atomically $ tryReadTQueue tc - case me of - Just e -> do - processEvent e - processEvents - Nothing -> return () - -processEvent :: Event -> Demo () -processEvent ev = - case ev of - (EventError e s) -> do - printEvent "error" [show e, show s] - win <- asks envWindow - liftIO $ GLFW.setWindowShouldClose win True - - (EventWindowPos _ x y) -> - printEvent "window pos" [show x, show y] - - (EventWindowSize _ width height) -> - printEvent "window size" [show width, show height] - - (EventWindowClose _) -> - printEvent "window close" [] - - (EventWindowRefresh _) -> - printEvent "window refresh" [] - - (EventWindowFocus _ fs) -> - printEvent "window focus" [show fs] - - (EventWindowIconify _ is) -> - printEvent "window iconify" [show is] - - (EventFramebufferSize _ width height) -> do - printEvent "framebuffer size" [show width, show height] - modify $ \s -> s - { stateWindowWidth = width - , stateWindowHeight = height - } - adjustWindow - - (EventMouseButton _ mb mbs mk) -> do - printEvent "mouse button" [show mb, show mbs, showModifierKeys mk] - when (mb == GLFW.MouseButton'1) $ do - let pressed = mbs == GLFW.MouseButtonState'Pressed - modify $ \s -> s - { stateMouseDown = pressed - } - unless pressed $ - modify $ \s -> s - { stateDragging = False - } - - (EventCursorPos _ x y) -> do - let x' = round x :: Int - y' = round y :: Int - printEvent "cursor pos" [show x', show y'] - state <- get - when (stateMouseDown state && not (stateDragging state)) $ - put $ state - { stateDragging = True - , stateDragStartX = x - , stateDragStartY = y - , stateDragStartXAngle = stateXAngle state - , stateDragStartYAngle = stateYAngle state - } - - (EventCursorEnter _ cs) -> - printEvent "cursor enter" [show cs] - - (EventScroll _ x y) -> do - let x' = round x :: Int - y' = round y :: Int - printEvent "scroll" [show x', show y'] - env <- ask - modify $ \s -> s - { stateZDist = - let zDist' = stateZDist s + realToFrac (negate $ y / 2) - in curb (envZDistClosest env) (envZDistFarthest env) zDist' - } - adjustWindow - - (EventKey win k scancode ks mk) -> do - printEvent "key" [show k, show scancode, show ks, showModifierKeys mk] - when (ks == GLFW.KeyState'Pressed) $ do - -- Q, Esc: exit - when (k == GLFW.Key'Q || k == GLFW.Key'Escape) $ - liftIO $ GLFW.setWindowShouldClose win True - -- ?: print instructions - when (k == GLFW.Key'Slash && GLFW.modifierKeysShift mk) $ - liftIO printInstructions - -- i: print GLFW information - when (k == GLFW.Key'I) $ - liftIO $ printInformation win - - (EventChar _ c) -> - printEvent "char" [show c] - -adjustWindow :: Demo () -adjustWindow = do - state <- get - let width = stateWindowWidth state - height = stateWindowHeight state - zDist = stateZDist state - - let pos = GL.Position 0 0 - size = GL.Size (fromIntegral width) (fromIntegral height) - h = fromIntegral height / fromIntegral width :: Double - znear = 1 :: Double - zfar = 40 :: Double - xmax = znear * 0.5 :: Double - liftIO $ do - GL.viewport GL.$= (pos, size) - GL.matrixMode GL.$= GL.Projection - GL.loadIdentity - GL.frustum (realToFrac $ -xmax) - (realToFrac xmax) - (realToFrac $ -xmax * realToFrac h) - (realToFrac $ xmax * realToFrac h) - (realToFrac znear) - (realToFrac zfar) - GL.matrixMode GL.$= GL.Modelview 0 - GL.loadIdentity - GL.translate (GL.Vector3 0 0 (negate $ realToFrac zDist) :: GL.Vector3 GL.GLfloat) - -draw :: Demo () -draw = do - env <- ask - state <- get - let gear1 = envGear1 env - gear2 = envGear2 env - gear3 = envGear3 env - xa = stateXAngle state - ya = stateYAngle state - za = stateZAngle state - ga = stateGearZAngle state - liftIO $ do - GL.clear [GL.ColorBuffer, GL.DepthBuffer] - GL.preservingMatrix $ do - GL.rotate (realToFrac xa) xunit - GL.rotate (realToFrac ya) yunit - GL.rotate (realToFrac za) zunit - GL.preservingMatrix $ do - GL.translate gear1vec - GL.rotate (realToFrac ga) zunit - GL.callList gear1 - GL.preservingMatrix $ do - GL.translate gear2vec - GL.rotate (-2 * realToFrac ga - 9) zunit - GL.callList gear2 - GL.preservingMatrix $ do - GL.translate gear3vec - GL.rotate (-2 * realToFrac ga - 25) zunit - GL.callList gear3 - where - gear1vec = GL.Vector3 (-3) (-2) 0 :: GL.Vector3 GL.GLfloat - gear2vec = GL.Vector3 3.1 (-2) 0 :: GL.Vector3 GL.GLfloat - gear3vec = GL.Vector3 (-3.1) 4.2 0 :: GL.Vector3 GL.GLfloat - xunit = GL.Vector3 1 0 0 :: GL.Vector3 GL.GLfloat - yunit = GL.Vector3 0 1 0 :: GL.Vector3 GL.GLfloat - zunit = GL.Vector3 0 0 1 :: GL.Vector3 GL.GLfloat - -getCursorKeyDirections :: GLFW.Window -> IO (Double, Double) -getCursorKeyDirections win = do - x0 <- isPress `fmap` GLFW.getKey win GLFW.Key'Up - x1 <- isPress `fmap` GLFW.getKey win GLFW.Key'Down - y0 <- isPress `fmap` GLFW.getKey win GLFW.Key'Left - y1 <- isPress `fmap` GLFW.getKey win GLFW.Key'Right - let x0n = if x0 then (-1) else 0 - x1n = if x1 then 1 else 0 - y0n = if y0 then (-1) else 0 - y1n = if y1 then 1 else 0 - return (x0n + x1n, y0n + y1n) - -getJoystickDirections :: GLFW.Joystick -> IO (Double, Double) -getJoystickDirections js = do - maxes <- GLFW.getJoystickAxes js - return $ case maxes of - (Just (x:y:_)) -> (-y, x) - _ -> ( 0, 0) - -isPress :: GLFW.KeyState -> Bool -isPress GLFW.KeyState'Pressed = True -isPress GLFW.KeyState'Repeating = True -isPress _ = False - --------------------------------------------------------------------------------- - -printInstructions :: IO () -printInstructions = - putStrLn $ render $ - nest 4 ( - text "------------------------------------------------------------" $+$ - text "'?': Print these instructions" $+$ - text "'i': Print GLFW information" $+$ - text "" $+$ - text "* Mouse cursor, keyboard cursor keys, and/or joystick" $+$ - text " control rotation." $+$ - text "* Mouse scroll wheel controls distance from scene." $+$ - text "------------------------------------------------------------" - ) - -printInformation :: GLFW.Window -> IO () -printInformation win = do - version <- GLFW.getVersion - versionString <- GLFW.getVersionString - monitorInfos <- runMaybeT getMonitorInfos - joystickNames <- getJoystickNames - clientAPI <- GLFW.getWindowClientAPI win - cv0 <- GLFW.getWindowContextVersionMajor win - cv1 <- GLFW.getWindowContextVersionMinor win - cv2 <- GLFW.getWindowContextVersionRevision win - robustness <- GLFW.getWindowContextRobustness win - forwardCompat <- GLFW.getWindowOpenGLForwardCompat win - debug <- GLFW.getWindowOpenGLDebugContext win - profile <- GLFW.getWindowOpenGLProfile win - - putStrLn $ render $ - nest 4 ( - text "------------------------------------------------------------" $+$ - text "GLFW C library:" $+$ - nest 4 ( - text "Version:" <+> renderVersion version $+$ - text "Version string:" <+> renderVersionString versionString - ) $+$ - text "Monitors:" $+$ - nest 4 ( - renderMonitorInfos monitorInfos - ) $+$ - text "Joysticks:" $+$ - nest 4 ( - renderJoystickNames joystickNames - ) $+$ - text "OpenGL context:" $+$ - nest 4 ( - text "Client API:" <+> renderClientAPI clientAPI $+$ - text "Version:" <+> renderContextVersion cv0 cv1 cv2 $+$ - text "Robustness:" <+> renderContextRobustness robustness $+$ - text "Forward compatibility:" <+> renderForwardCompat forwardCompat $+$ - text "Debug:" <+> renderDebug debug $+$ - text "Profile:" <+> renderProfile profile - ) $+$ - text "------------------------------------------------------------" - ) - where - renderVersion (GLFW.Version v0 v1 v2) = - text $ intercalate "." $ map show [v0, v1, v2] - - renderVersionString = - text . show - - renderMonitorInfos = - maybe (text "(error)") (vcat . map renderMonitorInfo) - - renderMonitorInfo (name, (x,y), (w,h), vms) = - text (show name) $+$ - nest 4 ( - location <+> size $+$ - fsep (map renderVideoMode vms) - ) - where - location = int x <> text "," <> int y - size = int w <> text "x" <> int h <> text "mm" - - renderVideoMode (GLFW.VideoMode w h r g b rr) = - brackets $ res <+> rgb <+> hz - where - res = int w <> text "x" <> int h - rgb = int r <> text "x" <> int g <> text "x" <> int b - hz = int rr <> text "Hz" - - renderJoystickNames pairs = - vcat $ map (\(js, name) -> text (show js) <+> text (show name)) pairs - - renderContextVersion v0 v1 v2 = - hcat [int v0, text ".", int v1, text ".", int v2] - - renderClientAPI = text . show - renderContextRobustness = text . show - renderForwardCompat = text . show - renderDebug = text . show - renderProfile = text . show - -type MonitorInfo = (String, (Int,Int), (Int,Int), [GLFW.VideoMode]) - -getMonitorInfos :: MaybeT IO [MonitorInfo] -getMonitorInfos = - getMonitors >>= mapM getMonitorInfo - where - getMonitors :: MaybeT IO [GLFW.Monitor] - getMonitors = MaybeT GLFW.getMonitors - - getMonitorInfo :: GLFW.Monitor -> MaybeT IO MonitorInfo - getMonitorInfo mon = do - name <- getMonitorName mon - vms <- getVideoModes mon - MaybeT $ do - pos <- liftIO $ GLFW.getMonitorPos mon - size <- liftIO $ GLFW.getMonitorPhysicalSize mon - return $ Just (name, pos, size, vms) - - getMonitorName :: GLFW.Monitor -> MaybeT IO String - getMonitorName mon = MaybeT $ GLFW.getMonitorName mon - - getVideoModes :: GLFW.Monitor -> MaybeT IO [GLFW.VideoMode] - getVideoModes mon = MaybeT $ GLFW.getVideoModes mon - -getJoystickNames :: IO [(GLFW.Joystick, String)] -getJoystickNames = - catMaybes `fmap` mapM getJoystick joysticks - where - getJoystick js = - fmap (maybe Nothing (\name -> Just (js, name))) - (GLFW.getJoystickName js) - --------------------------------------------------------------------------------- - -printEvent :: String -> [String] -> Demo () -printEvent cbname fields = - liftIO $ putStrLn $ cbname ++ ": " ++ unwords fields - -showModifierKeys :: GLFW.ModifierKeys -> String -showModifierKeys mk = - "[mod keys: " ++ keys ++ "]" - where - keys = if null xs then "none" else unwords xs - xs = catMaybes ys - ys = [ if GLFW.modifierKeysShift mk then Just "shift" else Nothing - , if GLFW.modifierKeysControl mk then Just "control" else Nothing - , if GLFW.modifierKeysAlt mk then Just "alt" else Nothing - , if GLFW.modifierKeysSuper mk then Just "super" else Nothing - ] - -curb :: Ord a => a -> a -> a -> a -curb l h x - | x < l = l - | x > h = h - | otherwise = x - --------------------------------------------------------------------------------- - -joysticks :: [GLFW.Joystick] -joysticks = - [ GLFW.Joystick'1 - , GLFW.Joystick'2 - , GLFW.Joystick'3 - , GLFW.Joystick'4 - , GLFW.Joystick'5 - , GLFW.Joystick'6 - , GLFW.Joystick'7 - , GLFW.Joystick'8 - , GLFW.Joystick'9 - , GLFW.Joystick'10 - , GLFW.Joystick'11 - , GLFW.Joystick'12 - , GLFW.Joystick'13 - , GLFW.Joystick'14 - , GLFW.Joystick'15 - , GLFW.Joystick'16 - ] -