hsqml-0.3.7.0: src/Graphics/QML/Canvas.hs
{-# LANGUAGE
ScopedTypeVariables,
TypeFamilies,
FlexibleInstances
#-}
{-| Facility for drawing OpenGL graphics into the QML scenegraph.
To use this facility, you must place a @HaskellCanvas@ item into your
QML scene. This item can be imported from the @HsQML.Canvas 1.0@ module using
an @import@ statement in your QML script. It has several properties which can
be set from QML:
[@displayMode@] Specifies how the canvas is rendered with respect to the
rest of the scene. Possible values are:
[@HaskellCanvas.Above@] The canvas shares a buffer with the scenegraph
and is painted top of other items.
[@HaskellCanvas.Inline@] The canvas has its own framebuffer object and the
contents of this buffer are painted inline with other items (default).
[@HaskellCanvas.Below@] The canvas shares a buffer with the scenegraph
and is painted underneath other items.
[@canvasWidth@] Width of the framebuffer object in pixels. Defaults to the
item width.
[@canvasHeight@] Height of the framebuffer object in pixels. Defaults to the
item height.
[@delegate@] A marshalled 'OpenGLDelegate' value which specifies the Haskell
functions used to render the canvas.
[@model@] A value passed to delegate's paint function. The canvas is
repainted whenever this value changes.
[@status@] Either @HaskellCanvas.Okay@ or an error code (read only).
The @HsQML.Canvas 1.0@ module also contains another type of item called
@OpenGLConextControl@ which can be used to configure the OpenGL context used by
your windows. When placed inside a QML window, it has several properties which
when read return the current state of that window's OpenGL context, and when
written to cause the window's context to be reconfigured with a request for the
supplied setting. Note that as reconfiguring the context may cause a visible
window to dis- and re-appear, it's recommended to supply the desired settings
at startup or otherwise before the corresponding window is made visible.
Available properties are as below:
[@majorVersion@] Major component of the OpenGL version.
[@minorVersion@] Minor component of the OpenGL version.
[@contextType@] The type of OpenGL context. One of:
@OpenGLContextControl.UnknownType@, @OpenGLContextControl.OpenGL@, or
@OpenGLContextControl.OpenGLES@.
[@contextProfile@] The OpenGL context's profile. One of:
@OpenGLContextControl.NoProfile@, @OpenGLContextControl.CoreProfile@, or
@OpenGLContextControl.CompatibilityProfile@.
[@deprecatedFunctions@] True if deprecated functions are available.
[@depthBufferSize@] Depth buffer size in bits.
[@stencilBufferSize@] Stencil buffer size in bits.
[@when@] Any changes to the OpenGL context while this property is set to false
will be deferred until it is true again. The default value is true.
-}
module Graphics.QML.Canvas (
OpenGLDelegate,
newOpenGLDelegate,
OpenGLType (
OpenGLDesktop,
OpenGLES),
OpenGLSetup,
openGLType,
openGLMajor,
openGLMinor,
OpenGLPaint,
OpenGLPaint',
setupData,
modelData,
matrixPtr,
itemWidth,
itemHeight
) where
import Graphics.QML.Internal.BindCanvas
import Graphics.QML.Internal.BindPrim
import Graphics.QML.Internal.Marshal
import Graphics.QML.Internal.Types
import Graphics.QML.Marshal
import Data.IORef
import Data.Maybe
import Data.Tagged
import Control.Monad.Trans.Maybe
import Foreign.Ptr (Ptr)
import Foreign.C.Types (CFloat)
-- | Delegate for painting OpenGL graphics.
newtype OpenGLDelegate = OpenGLDelegate HsQMLGLDelegateHandle
instance Marshal OpenGLDelegate where
type MarshalMode OpenGLDelegate c d = ModeBidi c
marshaller = Marshaller {
mTypeCVal_ = Tagged tyJSValue,
mFromCVal_ = jvalFromCVal,
mToCVal_ = jvalToCVal,
mWithCVal_ = jvalWithCVal,
mFromJVal_ = \_ ptr -> MaybeT $ do
hndl <- hsqmlCreateGldelegate
fromJVal Weak (hsqmlGldelegateFromJval hndl)
(const . return $ OpenGLDelegate hndl) ptr,
mWithJVal_ = \(OpenGLDelegate hndl) f ->
withJVal (flip hsqmlGldelegateToJval) hndl f,
mFromHndl_ = unimplFromHndl,
mToHndl_ = unimplToHndl}
-- | Represents the type of an OpenGL context.
data OpenGLType
-- | Desktop OpenGL context.
= OpenGLDesktop
-- | OpenGL ES context.
| OpenGLES
deriving (Eq, Show)
mapGLType :: HsQMLGLCanvasType -> OpenGLType
mapGLType HsqmlGlDesktop = OpenGLDesktop
mapGLType HsqmlGlEs = OpenGLES
-- | Encapsulates parameters for OpenGL setup.
data OpenGLSetup = OpenGLSetup {
-- | Type of OpenGL context.
openGLType :: OpenGLType,
-- | Major version number of OpenGL context.
openGLMajor :: Int,
-- | Minor version number of OpenGL context.
openGLMinor :: Int
}
-- | Encapsulates parameters for OpenGL paint.
data OpenGLPaint s m = OpenGLPaint {
-- | Gets the setup state.
setupData :: s,
-- | Gets the active model.
modelData :: m,
-- | Pointer to a 4 by 4 matrix which transform coordinates in the range
-- (-1, -1) to (1, 1) on to the target rectangle in the scene.
matrixPtr :: Ptr CFloat,
-- | Width of the canvas item in its local coordinate system.
itemWidth :: Float,
-- | Height of the canvas item in its local coordinate system.
itemHeight :: Float
}
-- | Specialised version of `OpenGLPaint` with no model.
type OpenGLPaint' s = OpenGLPaint s Ignored
newOpenGLCallbacks :: (Marshal m, CanGetFrom m ~ Yes) =>
(OpenGLSetup -> IO i) -> (OpenGLPaint i m -> IO ()) -> (i -> IO ()) ->
CallbacksFactory
newOpenGLCallbacks setupFn paintFn cleanupFn = do
iRef <- newIORef Nothing
mRef <- newIORef Nothing
let setupCb ctype major minor = do
iVal <- setupFn $ OpenGLSetup
(mapGLType $ cIntToEnum ctype)
(fromIntegral major) (fromIntegral minor)
writeIORef iRef $ Just iVal
cleanupCb = do
iVal <- readIORef iRef
cleanupFn $ fromJust iVal
syncCb ptr = do
mVal <- runMaybeT $ mFromJVal Strong ptr
writeIORef mRef mVal
return $ if isJust mVal then 1 else 0
paintCb mPtr w h = do
iVal <- readIORef iRef
mVal <- readIORef mRef
paintFn $ OpenGLPaint
(fromJust iVal) (fromJust mVal)
mPtr (realToFrac w) (realToFrac h)
return (setupCb, cleanupCb, syncCb, paintCb)
-- | Creates a new 'OpenGLDelegate' from setup, paint, and cleanup functions.
newOpenGLDelegate :: (Marshal m, CanGetFrom m ~ Yes) =>
(OpenGLSetup -> IO i) -> (OpenGLPaint i m -> IO ()) -> (i -> IO ()) ->
IO OpenGLDelegate
newOpenGLDelegate setupFn paintFn cleanupFn = do
hndl <- hsqmlCreateGldelegate
hsqmlGldelegateSetup hndl (newOpenGLCallbacks setupFn paintFn cleanupFn)
return $ OpenGLDelegate hndl