{-# 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