GLUT-2.5.1.0: Graphics/UI/GLUT/State.hs
--------------------------------------------------------------------------------
-- |
-- Module : Graphics.UI.GLUT.State
-- Copyright : (c) Sven Panne 2002-2013
-- License : BSD3
--
-- Maintainer : Sven Panne <svenpanne@gmail.com>
-- Stability : stable
-- Portability : portable
--
-- GLUT maintains a considerable amount of programmer visible state. Some (but
-- not all) of this state may be directly retrieved.
--
--------------------------------------------------------------------------------
module Graphics.UI.GLUT.State (
-- * State of all windows
windowBorderWidth, windowHeaderHeight, skipStaleMotionEvents,
-- * State of the /current window/
-- ** Framebuffer state
rgba,
BufferDepth, rgbaBufferDepths, colorBufferDepth,
doubleBuffered, stereo,
accumBufferDepths, depthBufferDepth, stencilBufferDepth,
SampleCount, sampleCount, formatID,
-- ** Full screen state
fullScreenMode,
-- ** Object rendering state
geometryVisualizeNormals,
-- ** Vertex attribute state
vertexAttribCoord3, vertexAttribNormal, vertexAttribTexCoord2,
-- ** Layer state
damaged,
-- * Timing
elapsedTime,
-- * Device information
-- $DeviceInformation
screenSize, screenSizeMM,
hasKeyboard,
ButtonCount, numMouseButtons,
numSpaceballButtons,
DialCount, numDialsAndButtons,
numTabletButtons,
AxisCount, PollRate, joystickInfo,
supportedNumAuxBuffers, supportedSamplesPerPixel,
-- * GLUT information
glutVersion, initState
) where
import Control.Monad
import Foreign.C.Types
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.Storable
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT.Overlay
import Graphics.UI.GLUT.QueryUtils
import Graphics.UI.GLUT.Raw
import Graphics.UI.GLUT.Window
--------------------------------------------------------------------------------
-- | Contains 'True' when the current layer of the /current window/ is in RGBA
-- mode, 'False' means color index mode.
rgba :: GettableStateVar Bool
rgba = makeGettableStateVar$ simpleGet i2b glut_WINDOW_RGBA
-- | Bit depth of a buffer
type BufferDepth = Int
-- | Contains the number of red, green, blue, and alpha bits in the color buffer
-- of the /current window\'s/ current layer (0 in color index mode).
rgbaBufferDepths ::
GettableStateVar (BufferDepth, BufferDepth, BufferDepth, BufferDepth)
rgbaBufferDepths = makeGettableStateVar $ do
r <- simpleGet fromIntegral glut_WINDOW_RED_SIZE
g <- simpleGet fromIntegral glut_WINDOW_GREEN_SIZE
b <- simpleGet fromIntegral glut_WINDOW_BLUE_SIZE
a <- simpleGet fromIntegral glut_WINDOW_ALPHA_SIZE
return (r, g, b, a)
-- | Contains the total number of bits in the color buffer of the /current
-- window\'s/ current layer. For an RGBA layer, this is the sum of the red,
-- green, blue, and alpha bits. For an color index layer, this is the number
-- of bits of the color indexes.
colorBufferDepth :: GettableStateVar BufferDepth
colorBufferDepth =
makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_BUFFER_SIZE
-- | Contains 'True' when the current layer of the /current window/ is double
-- buffered, 'False' otherwise.
doubleBuffered :: GettableStateVar Bool
doubleBuffered = makeGettableStateVar $ simpleGet i2b glut_WINDOW_DOUBLEBUFFER
-- | Contains 'True' when the current layer of the /current window/ is stereo,
-- 'False' otherwise.
stereo :: GettableStateVar Bool
stereo = makeGettableStateVar $ simpleGet i2b glut_WINDOW_STEREO
-- | Contains the number of red, green, blue, and alpha bits in the accumulation
-- buffer of the /current window\'s/ current layer (0 in color index mode).
accumBufferDepths ::
GettableStateVar (BufferDepth, BufferDepth, BufferDepth, BufferDepth)
accumBufferDepths = makeGettableStateVar $ do
r <- simpleGet fromIntegral glut_WINDOW_ACCUM_RED_SIZE
g <- simpleGet fromIntegral glut_WINDOW_ACCUM_GREEN_SIZE
b <- simpleGet fromIntegral glut_WINDOW_ACCUM_BLUE_SIZE
a <- simpleGet fromIntegral glut_WINDOW_ACCUM_ALPHA_SIZE
return (r, g, b, a)
-- | Contains the number of bits in the depth buffer of the /current window\'s/
-- current layer.
depthBufferDepth :: GettableStateVar BufferDepth
depthBufferDepth =
makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_DEPTH_SIZE
-- | Contains the number of bits in the stencil buffer of the /current
-- window\'s/ current layer.
stencilBufferDepth :: GettableStateVar BufferDepth
stencilBufferDepth =
makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_STENCIL_SIZE
-- | Number of samples for multisampling
type SampleCount = Int
-- | Contains the number of samples for multisampling for the /current window./
sampleCount :: GettableStateVar SampleCount
sampleCount =
makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_NUM_SAMPLES
-- | Contains the window system dependent format ID for the current layer of the
-- /current window/. On X11 GLUT implementations, this is the X visual ID. On
-- Win32 GLUT implementations, this is the Win32 Pixel Format Descriptor number.
-- This value is returned for debugging, benchmarking, and testing ease.
formatID :: GettableStateVar Int
formatID = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_FORMAT_ID
--------------------------------------------------------------------------------
-- | (/freeglut only/) Contains 'True' if the /current window/ is in full screen
-- mode, 'False' otherwise.
fullScreenMode :: StateVar Bool
fullScreenMode = makeStateVar getFullScreenMode setFullScreenMode
getFullScreenMode :: IO Bool
getFullScreenMode = simpleGet i2b glut_FULL_SCREEN
setFullScreenMode :: Bool -> IO ()
setFullScreenMode newMode = do
oldMode <- getFullScreenMode
unless (newMode == oldMode) fullScreenToggle
--------------------------------------------------------------------------------
-- | (/freeglut only/) Controls if vectors representing the normals should be
-- drawn, too, when objects are drawn.
geometryVisualizeNormals :: StateVar Bool
geometryVisualizeNormals =
makeStateVar
(simpleGet i2b glut_GEOMETRY_VISUALIZE_NORMALS)
(glutSetOption glut_GEOMETRY_VISUALIZE_NORMALS . b2i)
--------------------------------------------------------------------------------
-- | (/freeglut only/) If 'vertexAttribCoord3' and 'vertexAttribNormal' both
-- contain 'Nothing', the fixed function pipeline is used to draw
-- objects. Otherwise VBOs are used and the coordinates are passed via 'Just'
-- this attribute location (for a vec3).
vertexAttribCoord3 :: SettableStateVar (Maybe AttribLocation)
vertexAttribCoord3 = setVertexAttribWith glutSetVertexAttribCoord3
setVertexAttribWith :: (GLint -> IO ()) -> SettableStateVar (Maybe AttribLocation)
setVertexAttribWith f = makeSettableStateVar $ f . getLocation
where getLocation = maybe (-1) (\(AttribLocation l) -> fromIntegral l)
-- | (/freeglut only/) If 'vertexAttribCoord3' and 'vertexAttribNormal' both
-- contain 'Nothing', the fixed function pipeline is used to draw
-- objects. Otherwise VBOs are used and the normals are passed via 'Just' this
-- attribute location (for a vec3).
vertexAttribNormal :: SettableStateVar (Maybe AttribLocation)
vertexAttribNormal = setVertexAttribWith glutSetVertexAttribNormal
-- | (/freeglut only/) If VBOs are used to draw objects (controlled via
-- 'vertexAttribCoord3' and 'vertexAttribNormal'), the texture coordinates are
-- passed via 'Just' this attribute location (for a vec2).
vertexAttribTexCoord2 :: SettableStateVar (Maybe AttribLocation)
vertexAttribTexCoord2 = setVertexAttribWith glutSetVertexAttribTexCoord2
--------------------------------------------------------------------------------
-- | Contains the number of milliseconds since
-- 'Graphics.UI.GLUT.Initialization.initialize' was called.
elapsedTime :: GettableStateVar Int
elapsedTime = makeGettableStateVar $ simpleGet fromIntegral glut_ELAPSED_TIME
--------------------------------------------------------------------------------
-- | Contains 'True' if the given plane of the /current window/ has been
-- damaged (by window system activity) since the last display callback was
-- triggered. Calling 'Graphics.UI.GLUT.Window.postRedisplay' or
-- 'Graphics.UI.GLUT.Overlay.postOverlayRedisplay' will not set this 'True'.
damaged :: Layer -> GettableStateVar Bool
damaged l = makeGettableStateVar $ layerGet isDamaged (marshalDamagedLayer l)
where isDamaged d = d /= 0 && d /= -1
marshalDamagedLayer x = case x of
Normal -> glut_NORMAL_DAMAGED
Overlay -> glut_OVERLAY_DAMAGED
--------------------------------------------------------------------------------
-- $DeviceInformation
-- If a device is not available, the following state variables contain
-- 'Nothing', otherwise they return 'Just' the specific device information.
-- Only a screen is always assumed.
--------------------------------------------------------------------------------
-- | The size of the screen in pixels.
screenSize :: GettableStateVar Size
screenSize =
makeGettableStateVar $ do
wpx <- simpleGet fromIntegral glut_SCREEN_WIDTH
hpx <- simpleGet fromIntegral glut_SCREEN_HEIGHT
return $ Size wpx hpx
-- | The size of the screen in millimeters.
screenSizeMM :: GettableStateVar Size
screenSizeMM =
makeGettableStateVar $ do
wmm <- simpleGet fromIntegral glut_SCREEN_WIDTH_MM
hmm <- simpleGet fromIntegral glut_SCREEN_HEIGHT_MM
return $ Size wmm hmm
--------------------------------------------------------------------------------
-- | Contains 'True' if a keyboard is present, 'False' otherwise.
hasKeyboard :: GettableStateVar Bool
hasKeyboard = makeGettableStateVar $ deviceGet i2b glut_HAS_KEYBOARD
--------------------------------------------------------------------------------
-- | Number of buttons of an input device
type ButtonCount = Int
-- | Contains 'Just' the number of buttons of an attached mouse or 'Nothing' if
-- there is none.
numMouseButtons :: GettableStateVar (Maybe ButtonCount)
numMouseButtons =
getDeviceInfo glut_HAS_MOUSE $
deviceGet fromIntegral glut_NUM_MOUSE_BUTTONS
--------------------------------------------------------------------------------
-- | Contains 'Just' the number of buttons of the attached Spaceball or 'Nothing'
-- if there is none.
numSpaceballButtons :: GettableStateVar (Maybe ButtonCount)
numSpaceballButtons =
getDeviceInfo glut_HAS_SPACEBALL $
deviceGet fromIntegral glut_NUM_SPACEBALL_BUTTONS
--------------------------------------------------------------------------------
-- | Number of dials of a dial and button box
type DialCount = Int
-- | Contains 'Just' the number of dials and buttons of an attached dial &
-- button box or 'Nothing' if there is none.
numDialsAndButtons :: GettableStateVar (Maybe (DialCount, ButtonCount))
numDialsAndButtons =
getDeviceInfo glut_HAS_DIAL_AND_BUTTON_BOX $ do
d <- deviceGet fromIntegral glut_NUM_DIALS
b <- deviceGet fromIntegral glut_NUM_BUTTON_BOX_BUTTONS
return (d, b)
--------------------------------------------------------------------------------
-- | Contains 'Just' the number of buttons of an attached tablet or 'Nothing' if
-- there is none.
numTabletButtons :: GettableStateVar (Maybe ButtonCount)
numTabletButtons =
getDeviceInfo glut_HAS_TABLET $
deviceGet fromIntegral glut_NUM_TABLET_BUTTONS
--------------------------------------------------------------------------------
-- | Number of axes of a joystick
type AxisCount = Int
-- | The a rate at which a joystick is polled (in milliseconds)
type PollRate = Int
-- | Contains 'Just' the number of buttons of an attached joystick, the number
-- of joystick axes, and the rate at which the joystick is polled. Contains
-- 'Nothing' if there is no joystick attached.
joystickInfo :: GettableStateVar (Maybe (ButtonCount, PollRate, AxisCount))
joystickInfo =
getDeviceInfo glut_HAS_JOYSTICK $ do
b <- deviceGet fromIntegral glut_JOYSTICK_BUTTONS
a <- deviceGet fromIntegral glut_JOYSTICK_AXES
r <- deviceGet fromIntegral glut_JOYSTICK_POLL_RATE
return (b, a, r)
-----------------------------------------------------------------------------
-- | (/freeglut only/) Contains a list of the number of auxiliary buffers
-- supported, in increasing order.
supportedNumAuxBuffers :: GettableStateVar [Int]
supportedNumAuxBuffers = getModeValues glut_AUX
-- | (/freeglut only/) Contains a list of the number of samples per pixel
-- supported for multisampling, in increasing order.
supportedSamplesPerPixel :: GettableStateVar [SampleCount]
supportedSamplesPerPixel = getModeValues (fromIntegral glut_MULTISAMPLE)
getModeValues :: Integral a => GLenum -> GettableStateVar [a]
getModeValues what = makeGettableStateVar $
alloca $ \sizeBuffer -> do
valuesBuffer <- glutGetModeValues what sizeBuffer
size <- peek sizeBuffer
fmap (map fromIntegral) $ peekArray (fromIntegral size) valuesBuffer
--------------------------------------------------------------------------------
-- Convenience (un-)marshalers
i2b :: CInt -> Bool
i2b = (/= 0)
b2i :: Bool -> CInt
b2i False = 0
b2i True = 1
--------------------------------------------------------------------------------
getDeviceInfo :: GLenum -> IO a -> GettableStateVar (Maybe a)
getDeviceInfo dev act =
makeGettableStateVar $ do
hasDevice <- deviceGet i2b dev
if hasDevice then fmap Just act else return Nothing
-----------------------------------------------------------------------------
-- | Contains version of GLUT in the form of
-- @/flavour/ /major/./minor/./patchlevel/@, where @/flavour/@ is one of
-- @GLUT@, @freeglut@ or @OpenGLUT@.
glutVersion :: GettableStateVar String
glutVersion = makeGettableStateVar $ do
let isGLUT = isUnknown "glutSetOption"
isFreeglut = isUnknown "glutSetWindowStayOnTop"
isUnknown = fmap (== nullFunPtr) . getAPIEntryInternal
showVersionPart x = shows (x `mod` 100)
showVersion v = showVersionPart (v `div` 10000) . showChar '.' .
showVersionPart (v `div` 100) . showChar '.' .
showVersionPart v
g <- isGLUT
if g
then return "GLUT 3.7" -- ToDo: just guessing
else do f <- isFreeglut
v <- simpleGet id glut_VERSION
let prefix = if f then "freeglut" else "OpenGLUT"
return $ showString prefix . showChar ' ' . showVersion v $ ""
-----------------------------------------------------------------------------
-- | (/freeglut only/) Contains the thickness of the sizing border around the
-- perimeter of a window that can be resized, in pixels.
windowBorderWidth :: GettableStateVar Int
windowBorderWidth =
makeGettableStateVar (simpleGet fromIntegral glut_WINDOW_BORDER_WIDTH)
-----------------------------------------------------------------------------
-- | (/freeglut only/) Contains the height of the header\/caption area of a
-- window in pixels.
windowHeaderHeight :: GettableStateVar Int
windowHeaderHeight =
makeGettableStateVar (simpleGet fromIntegral glut_WINDOW_HEADER_HEIGHT)
-----------------------------------------------------------------------------
-- | (/freeglut on X11 only/) Controls if all but the last motion event should
-- be discarded.
skipStaleMotionEvents :: StateVar Bool
skipStaleMotionEvents =
makeStateVar
(simpleGet i2b glut_SKIP_STALE_MOTION_EVENTS)
(glutSetOption glut_SKIP_STALE_MOTION_EVENTS . b2i)
-----------------------------------------------------------------------------
-- | (/freeglut only/) Contains 'True' if GLUT has been initialized
-- with 'Graphics.UI.GLUT.Initialization.initialize' or
-- 'Graphics.UI.GLUT.Initialization.getArgsAndInitialize' has and not yet
-- been de-initialized with 'Graphics.UI.GLUT.Initialization.exit'. Contains
-- 'False' otherwise.
initState :: GettableStateVar Bool
initState = makeGettableStateVar$ simpleGet i2b glut_INIT_STATE