sdl2-2.3.0.1: src/SDL/Video/OpenGL.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
module SDL.Video.OpenGL
( -- * Creating and Configuring OpenGL Contexts
defaultOpenGL
, OpenGLConfig(..)
, GLContext
, glCreateContext
, Profile(..)
, Mode(..)
, glMakeCurrent
, glDeleteContext
-- * Querying for the drawable size without a Renderer
, glGetDrawableSize
-- * Swapping
-- | The process of \"swapping\" means to move the back-buffer into the window contents itself.
, glSwapWindow
, SwapInterval(..)
, swapInterval
-- * Function Loading
, Raw.glGetProcAddress
) where
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Data (Data)
import Data.StateVar
import Data.Typeable
import Foreign hiding (void, throwIfNull, throwIfNeg, throwIfNeg_)
import Foreign.C.Types
import GHC.Generics (Generic)
import SDL.Vect
import SDL.Internal.Exception
import SDL.Internal.Numbered
import SDL.Internal.Types
import qualified SDL.Raw as Raw
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative
#endif
-- | A set of default options for 'OpenGLConfig'
--
-- @
-- 'defaultOpenGL' = 'OpenGLConfig'
-- { 'glColorPrecision' = V4 8 8 8 0
-- , 'glDepthPrecision' = 24
-- , 'glStencilPrecision' = 8
-- , 'glMultisampleSamples' = 1
-- , 'glProfile' = 'Compatibility' 'Normal' 2 1
-- }
-- @
defaultOpenGL :: OpenGLConfig
defaultOpenGL = OpenGLConfig
{ glColorPrecision = V4 8 8 8 0
, glDepthPrecision = 24
, glStencilPrecision = 8
, glMultisampleSamples = 1
, glProfile = Compatibility Normal 2 1
}
-- | Configuration used when creating an OpenGL rendering context.
data OpenGLConfig = OpenGLConfig
{ glColorPrecision :: V4 CInt -- ^ Defaults to 'V4' @8 8 8 0@.
, glDepthPrecision :: CInt -- ^ Defaults to @24@.
, glStencilPrecision :: CInt -- ^ Defaults to @8@.
, glMultisampleSamples :: CInt -- ^ Defaults to @1@.
, glProfile :: Profile -- ^ Defaults to 'Compatibility' 'Normal' @2 1@.
} deriving (Eq, Generic, Ord, Read, Show, Typeable)
-- | The profile a driver should use when creating an OpenGL context.
data Profile
= Core Mode CInt CInt
-- ^ Use the OpenGL core profile, with a given major and minor version
| Compatibility Mode CInt CInt
-- ^ Use the compatibilty profile with a given major and minor version. The compatibility profile allows you to use deprecated functions such as immediate mode
| ES Mode CInt CInt
-- ^ Use an OpenGL profile for embedded systems
deriving (Eq, Generic, Ord, Read, Show, Typeable)
-- | The mode a driver should use when creating an OpenGL context.
data Mode
= Normal
-- ^ A normal profile with no special debugging support
| Debug
-- ^ Use a debug context, allowing the usage of extensions such as @GL_ARB_debug_output@
deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)
-- | A created OpenGL context.
newtype GLContext = GLContext Raw.GLContext
deriving (Eq, Typeable)
-- | Create a new OpenGL context and makes it the current context for the
-- window.
--
-- Throws 'SDLException' if the window wasn't configured with OpenGL
-- support, or if context creation fails.
--
-- See @<https://wiki.libsdl.org/SDL_GL_CreateContext SDL_GL_CreateContext>@ for C documentation.
glCreateContext :: (Functor m, MonadIO m) => Window -> m GLContext
glCreateContext (Window w) =
GLContext <$> throwIfNull "SDL.Video.glCreateContext" "SDL_GL_CreateContext"
(Raw.glCreateContext w)
-- | Set up an OpenGL context for rendering into an OpenGL window.
--
-- Throws 'SDLException' on failure.
--
-- See @<https://wiki.libsdl.org/SDL_GL_MakeCurrent SDL_GL_MakeCurrent>@ for C documentation.
glMakeCurrent :: (Functor m, MonadIO m) => Window -> GLContext -> m ()
glMakeCurrent (Window w) (GLContext ctx) =
throwIfNeg_ "SDL.Video.OpenGL.glMakeCurrent" "SDL_GL_MakeCurrent" $
Raw.glMakeCurrent w ctx
-- | Delete the given OpenGL context.
--
-- You /must/ make sure that there are no pending commands in the OpenGL
-- command queue, the driver may still be processing commands even if you have
-- stopped issuing them!
--
-- The @glFinish@ command will block until the command queue has been fully
-- processed. You should call that function before deleting a context.
--
-- See @<https://wiki.libsdl.org/SDL_GL_DeleteContext SDL_GL_DeleteContext>@ for C documentation.
glDeleteContext :: MonadIO m => GLContext -> m ()
glDeleteContext (GLContext ctx) = Raw.glDeleteContext ctx
-- | Replace the contents of the front buffer with the back buffer's. The
-- contents of the back buffer are undefined, clear them with @glClear@ or
-- equivalent before drawing to them again.
--
-- See @<https://wiki.libsdl.org/SDL_GL_SwapWindow SDL_GL_SwapWindow>@ for C documentation.
glSwapWindow :: MonadIO m => Window -> m ()
glSwapWindow (Window w) = Raw.glSwapWindow w
-- | The swap interval for the current OpenGL context.
data SwapInterval
= ImmediateUpdates
-- ^ No vertical retrace synchronization
| SynchronizedUpdates
-- ^ The buffer swap is synchronized with the vertical retrace
| LateSwapTearing
deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)
instance ToNumber SwapInterval CInt where
toNumber ImmediateUpdates = 0
toNumber SynchronizedUpdates = 1
toNumber LateSwapTearing = -1
instance FromNumber SwapInterval CInt where
fromNumber n' =
case n' of
0 -> ImmediateUpdates
1 -> SynchronizedUpdates
-1 -> LateSwapTearing
_ ->
error ("Unknown SwapInterval: " ++ show n')
-- | Get or set the swap interval for the current OpenGL context.
--
-- This 'StateVar' can be modified using '$=' and the current value retrieved with 'get'.
--
-- See @<https://wiki.libsdl.org/SDL_GL_SetSwapInterval SDL_GL_SetSwapInterval>@ and @<https://wiki.libsdl.org/SDL_GL_GetSwapInterval SDL_GL_GetSwapInterval>@ for C documentation.
swapInterval :: StateVar SwapInterval
swapInterval = makeStateVar glGetSwapInterval glSetSwapInterval
where
glGetSwapInterval = fmap fromNumber $ Raw.glGetSwapInterval
glSetSwapInterval i =
throwIfNeg_ "SDL.Video.glSetSwapInterval" "SDL_GL_SetSwapInterval" $
Raw.glSetSwapInterval (toNumber i)
-- | Get the size of a window's underlying drawable area in pixels (for use
-- with glViewport).
--
-- It may differ from 'SDL.Video.windowSize' if window was created with 'SDL.Video.windowHighDPI' flag.
glGetDrawableSize :: MonadIO m => Window -> m (V2 CInt)
glGetDrawableSize (Window w) =
liftIO $
alloca $ \wptr ->
alloca $ \hptr -> do
Raw.glGetDrawableSize w wptr hptr
V2 <$> peek wptr <*> peek hptr