-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Overlay -- Copyright : (c) Sven Panne 2002-2013 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- When overlay hardware is available, GLUT provides a set of routines for -- establishing, using, and removing an overlay for GLUT windows. When an -- overlay is established, a separate OpenGL context is also established. A -- window\'s overlay OpenGL state is kept distinct from the normal planes\' -- OpenGL state. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Overlay ( -- * Overlay creation and destruction hasOverlay, overlayPossible, -- * Showing and hiding an overlay overlayVisible, -- * Changing the /layer in use/ Layer(..), layerInUse, -- * Re-displaying postOverlayRedisplay ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.StateVar ( GettableStateVar, makeGettableStateVar , SettableStateVar, makeSettableStateVar , StateVar, makeStateVar ) import Graphics.Rendering.OpenGL ( GLenum ) import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- | Controls the overlay for the /current window/. The requested display mode -- for the overlay is determined by the /initial display mode/. -- 'overlayPossible' can be used to determine if an overlay is possible for the -- /current window/ with the current /initial display mode/. Do not attempt to -- establish an overlay when one is not possible; GLUT will terminate the -- program. -- -- When 'hasOverlay' is set to 'True' when an overlay already exists, the -- existing overlay is first removed, and then a new overlay is established. The -- state of the old overlay\'s OpenGL context is discarded. Implicitly, the -- window\'s /layer in use/ changes to the overlay immediately after the overlay -- is established. -- -- The initial display state of an overlay is shown, however the overlay is only -- actually shown if the overlay\'s window is shown. -- -- Setting 'hasOverlay' to 'False' is safe even if no overlay is currently -- established, nothing happens in this case. Implicitly, the window\'s /layer -- in use/ changes to the normal plane immediately once the overlay is removed. -- -- If the program intends to re-establish the overlay later, it is typically -- faster and less resource intensive to use 'overlayVisible' to simply change -- the display status of the overlay. -- -- /X Implementation Notes:/ GLUT for X uses the @SERVER_OVERLAY_VISUALS@ -- convention to determine if overlay visuals are available. While the -- convention allows for opaque overlays (no transparency) and overlays with the -- transparency specified as a bitmask, GLUT overlay management only provides -- access to transparent pixel overlays. -- -- Until RGBA overlays are better understood, GLUT only supports color index -- overlays. hasOverlay :: StateVar Bool hasOverlay = makeStateVar getHasOverlay setHasOverlay setHasOverlay :: Bool -> IO () setHasOverlay False = glutRemoveOverlay setHasOverlay True = glutEstablishOverlay getHasOverlay :: IO Bool getHasOverlay = layerGet (/= 0) glut_HAS_OVERLAY -------------------------------------------------------------------------------- -- | Contains 'True' if an overlay could be established for the /current window/ -- given the current /initial display mode/. If it contains 'False', setting -- 'hasOverlay' will fail with a fatal error. overlayPossible :: GettableStateVar Bool overlayPossible = makeGettableStateVar $ layerGet (/= 0) glut_OVERLAY_POSSIBLE -------------------------------------------------------------------------------- -- | Controls the visibility of the overlay of the /current window/. -- -- The effect of showing or hiding an overlay takes place immediately. Note that -- setting 'overlayVisible' to 'True' will not actually display the overlay -- unless the window is also shown (and even a shown window may be obscured by -- other windows, thereby obscuring the overlay). It is typically faster and -- less resource intensive to use the routines below to control the display -- status of an overlay as opposed to removing and re-establishing the overlay. overlayVisible :: SettableStateVar Bool overlayVisible = makeSettableStateVar $ \flag -> if flag then glutShowOverlay else glutHideOverlay -------------------------------------------------------------------------------- -- | The /layer in use/. data Layer = Normal -- ^ The normal plane. | Overlay -- ^ The overlay. deriving ( Eq, Ord, Show ) marshalLayer :: Layer -> GLenum marshalLayer x = case x of Normal -> glut_NORMAL Overlay -> glut_OVERLAY unmarshalLayer :: GLenum -> Layer unmarshalLayer x | x == glut_NORMAL = Normal | x == glut_OVERLAY = Overlay | otherwise = error ("unmarshalLayer: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | Controls the per-window /layer in use/ for the /current window/, which can -- either be the normal plane or the overlay. Selecting the overlay should only -- be done if an overlay exists, however windows without an overlay may still -- set the /layer in use/ to 'Normal'. OpenGL commands for the window are -- directed to the current /layer in use/. layerInUse :: StateVar Layer layerInUse = makeStateVar getLayerInUse setLayerInUse setLayerInUse :: Layer -> IO () setLayerInUse = glutUseLayer . marshalLayer getLayerInUse :: IO Layer getLayerInUse = layerGet (unmarshalLayer . fromIntegral) glut_LAYER_IN_USE -------------------------------------------------------------------------------- -- | Mark the overlay of the given window (or the /current window/, if none is -- supplied) as needing to be redisplayed. The next iteration through -- 'Graphics.UI.GLUT.Begin.mainLoop', the window\'s overlay display callback -- (or simply the display callback if no overlay display callback is registered) -- will be called to redisplay the window\'s overlay plane. Multiple calls to -- 'postOverlayRedisplay' before the next display callback opportunity (or -- overlay display callback opportunity if one is registered) generate only a -- single redisplay. 'postOverlayRedisplay' may be called within a window\'s -- display or overlay display callback to re-mark that window for redisplay. -- -- Logically, overlay damage notification for a window is treated as a -- 'postOverlayRedisplay' on the damaged window. Unlike damage reported by the -- window system, 'postOverlayRedisplay' will not set to true the overlay\'s -- damaged status (see 'Graphics.UI.GLUT.State.damaged'). -- -- Also, see 'Graphics.UI.GLUT.Window.postRedisplay'. postOverlayRedisplay :: MonadIO m => Maybe Window -> m () postOverlayRedisplay = maybe glutPostOverlayRedisplay (\(Window win) -> glutPostWindowOverlayRedisplay win)