clutterhs-0.1: Graphics/UI/Clutter/Texture.chs
-- -*-haskell-*-
-- Clutter Texture
--
-- Author : Matthew Arsenault
--
-- Created: 3 Oct 2009
--
-- Copyright (C) 2009 Matthew Arsenault
--
-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 3 of the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
{-# LANGUAGE ForeignFunctionInterface #-}
#include <clutter/clutter.h>
{# context lib="clutter" prefix="clutter" #}
module Graphics.UI.Clutter.Texture (
-- * Class Hierarchy
-- |
-- @
-- | 'GObject'
-- | +----'Actor'
-- | +----'Texture'
-- | +----'CairoTexture'
-- @
--
-- * Types
Texture,
TextureClass,
TextureFlags(..),
TextureQuality(..),
-- * Constructors
textureNew,
textureNewFromFile,
textureNewFromActor,
-- * Methods
textureSetFromFile,
textureSetFromRgbData, --TODO: RGB??? vs. Rgb
--textureSetFromYuvData,
--textureSetAreaFromRgbData,
textureGetBaseSize,
--textureGetPixelFormat,
textureGetMaxTileWaste,
textureGetFilterQuality,
textureSetFilterQuality,
--textureGetCoglTexture,
--textureSetCoglTexture,
--textureSetCoglMaterial,
--textureGetCoglMaterial,
textureGetSyncSize,
textureSetSyncSize,
textureGetRepeat,
textureSetRepeat,
textureSetKeepAspectRatio,
textureGetKeepAspectRatio,
textureGetLoadAsync,
textureSetLoadAsync,
textureGetLoadDataAsync,
textureSetLoadDataAsync,
-- * Attributes
--textureCoglMaterial,
--textureCoglTexture,
textureDisableSlicing,
textureFilename,
textureFilterQuality,
textureKeepAspectRatio,
textureLoadAsync,
textureLoadDataAsync,
--texturePixelFormat,
textureRepeatX,
textureRepeatY,
textureSyncSize,
textureTileWaste,
-- * Signals
onLoadFinished,
afterLoadFinished,
loadFinished,
onPixbufChange,
afterPixbufChange,
pixbufChange,
onSizeChange,
afterSizeChange,
sizeChange
) where
{# import Graphics.UI.Clutter.Types #}
{# import Graphics.UI.Clutter.Signals #}
{# import Graphics.UI.Clutter.Utility #}
import Data.Array.Base (getBounds)
import C2HS
import Control.Monad (liftM)
import System.Glib.Attributes
import System.Glib.Properties
import System.Glib.GError
import System.Glib.FFI
-- | Creates a new empty 'Texture' object.
--
-- [@Returns@] A newly created 'Texture' object.
--
{# fun unsafe texture_new as ^ { } -> `Texture' newTexture* #}
-- | Creates a new 'Texture' actor to display the image contained a
-- file. If the image failed to load then a GError exception is
-- thrown.
--
-- [@filename@] The name of an image file to load.
--
-- [@Returns@] A newly created 'Texture'
--
-- * Since 0.8
--
textureNewFromFile :: String -> IO Texture
textureNewFromFile filename = let func = {# call unsafe texture_new_from_file #}
in newTexture =<< (propagateGError $ \gerrorPtr ->
withCString filename $ \cstr -> do
func cstr gerrorPtr)
-- | Creates a new 'Texture' object with its source a prexisting actor
-- (and associated children). The textures content will contain
-- 'live' redirected output of the actors scene.
--
-- Note this function is intented as a utility call for uniformly
-- applying shaders to groups and other potential visual effects. It
-- requires that the CLUTTER_FEATURE_OFFSCREEN feature is supported by
-- the current backend and the target system.
--
-- Some tips on usage:
--
-- * The source actor must be made visible (i.e by calling 'actorShow').
--
-- * The source actor must have a parent in order for it to be
-- allocated a size from the layouting mechanism. If the source
-- actor does not have a parent when this function is called then
-- the 'Texture' will adopt it and allocate it at its preferred
-- size. Using this you can clone an actor that is otherwise not
-- displayed. Because of this feature if you do intend to display
-- the source actor then you must make sure that the actor is
-- parented before calling 'textureNewFromActor' or that you
-- unparent it before adding it to a container.
--
-- * When getting the image for the clone texture, Clutter will
-- attempt to render the source actor exactly as it would appear if
-- it was rendered on screen. The source actor's parent
-- transformations are taken into account. Therefore if your source
-- actor is rotated along the X or Y axes so that it has some depth,
-- the texture will appear differently depending on the on-screen
-- location of the source actor. While painting the source actor,
-- Clutter will set up a temporary asymmetric perspective matrix as
-- the projection matrix so that the source actor will be projected
-- as if a small section of the screen was being viewed. Before
-- version 0.8.2, an orthogonal identity projection was used which
-- meant that the source actor would be clipped if any part of it
-- was not on the zero Z-plane.
--
-- * Avoid reparenting the source with the created texture.
--
-- * A group can be padded with a transparent rectangle as to provide
-- a border to contents for shader output (blurring text for
-- example).
--
-- The texture will automatically resize to contain a further
-- transformed source. However, this involves overhead and can be
-- avoided by placing the source actor in a bounding group sized
-- large enough to contain any child tranformations.
--
-- * Uploading pixel data to the texture (e.g by using
-- 'textureSetFromFile') will destroy the offscreen texture data and
-- end redirection.
--
-- * 'coglTextureGetData' with the handle returned by
-- 'textureGetCoglTexture' can be used to read the offscreen texture
-- pixels into a pixbuf.
--
-- [@actor@] A source Actor
--
-- [@Returns@] @Just@ A newly created 'Texture' object, or @Nothing@ on failure.
--
-- * Since 0.6
--
{# fun unsafe texture_new_from_actor as ^
`(ActorClass a)' => { withActorClass* `a'} -> `Maybe Texture' maybeNewTexture* #}
--FIXME: Better description of gerror exception
-- | Sets the ClutterTexture image data from an image file. In case of
-- failure, @False@ is returned and a GError exception is thrown.
--
-- If "load-async" is set to @True@, this function will return as soon
-- as possible, and the actual image loading from disk will be
-- performed asynchronously. "size-change" will be emitten when the
-- size of the texture is available and "load-finished" will be
-- emitted when the image has been loaded or if an error occurred.
--
-- [@texture@] A 'Texture'
--
-- [@filename@] The filename of the image in GLib file name encoding
--
-- [@Returns@] @True@ if the image was successfully loaded and set
--
-- * Since 0.8
--
textureSetFromFile :: (TextureClass self) => self -> String -> IO Bool
textureSetFromFile txt fname = let func = {# call texture_set_from_file #}
in liftM cToBool $ propagateGError $ \gerrorPtr ->
withTextureClass txt $ \txtptr ->
withCString fname $ \cstr ->
func txtptr cstr (castPtr gerrorPtr)
--CHECKME: Generalized RGBData
--CHECKME: Rgb or RGB?
--FIXME: Proper rowstride
textureSetFromRgbData :: (TextureClass self) => self ->
RGBData Int Word8 ->
[TextureFlags] ->
IO Bool
textureSetFromRgbData txt dat flags =
let func = {# call texture_set_from_rgb_data #}
hasA = rgbDataHasAlpha dat
bpp = if hasA then 4 else 3
datPtr = rgbDataData dat
in withTextureClass txt $ \txtptr ->
propagateGError $ \gerrorPtr -> do
(w, h) <- getBounds dat
putStrLn $ "W: " ++ Prelude.show w ++ " H: " ++ Prelude.show h
let rowstride = w * 4 -- FIXME
liftM cToBool $ withForeignPtr datPtr $ \fPtr ->
func txtptr
(castPtr fPtr)
(cFromBool hasA)
(cIntConv w)
(cIntConv h)
(cIntConv rowstride)
(cIntConv bpp)
(cFromFlags flags)
(castPtr gerrorPtr)
{-
texture_set_from_yuv_data
texture_set_area_from_rgb_data
-}
-- | Gets the size in pixels of the untransformed underlying image
--
-- [@texture@] a 'Texture'
--
-- [@Returns@] (width, height)
--
{# fun unsafe texture_get_base_size as ^ `(TextureClass self)' =>
{ withTextureClass* `self',
alloca- `Int' peekIntConv*,
alloca- `Int' peekIntConv* } -> `()' #}
{- TODO: Requires cogl
{# fun unsafe texture_get_pixel_format as ^
{ withTexture* `Texture' } -> `CoglPixelFormat' cToEnum #}
-}
--CHECKME: Wrap the -1 thing somehow?
-- | Gets the maximum waste that will be used when creating a texture
-- or -1 if slicing is disabled.
--
-- [@texture@] A 'Texture'
--
-- [@Returns@] The maximum waste or -1 if the texture waste is
-- unlimited.
--
-- * Since 0.8
--
{# fun unsafe texture_get_max_tile_waste as ^ `(TextureClass self)' =>
{ withTextureClass* `self' } -> `Int' #}
-- | Gets the filter quality used when scaling a texture.
--
-- [@texture@] A 'Texture
--
-- [@Returns @] The filter quality value.
--
-- * Since 0.8
--
{# fun unsafe texture_get_filter_quality as ^ `(TextureClass self)' =>
{ withTextureClass* `self' } -> `TextureQuality' cToEnum #}
-- | Sets the filter quality when scaling a texture. The quality is an
-- enumeration currently the following values are supported:
-- 'TextureQualityLow' which is fast but only uses nearest neighbour
-- interpolation. 'TextureQualityMedium' which is computationally a
-- bit more expensive (bilinear interpolation), and
-- 'TextureQualityHigh' which uses extra texture memory resources to
-- improve scaled down rendering as well (by using mipmaps). The
-- default value is 'TextureQualityMedium'.
--
-- [@texture@] a 'Texture'
--
-- [@filter_quality@] new filter quality value
--
-- * Since 0.8
--
{# fun unsafe texture_set_filter_quality as ^ `(TextureClass self)' =>
{ withTextureClass* `self', cFromEnum `TextureQuality' } -> `()' #}
{-
{# fun unsafe texture_get_cogl_texture as ^ `(TextureClass self)' =>
{ withTexture* `Texture' } -> `CoglTexture' newCoglTexture #}
{# fun unsafe texture_set_cogl_texture as ^ `(TextureClass self)' =>
{ withTexture* `Texture', withCoglTexture `CoglTexture' } -> `()' #}
{# fun unsafe texture_get_cogl_material as ^ `(TextureClass self)' =>
{ withTexture* `Texture' } -> `CoglMaterial' newCoglMaterial #}
{# fun unsafe texture_set_cogl_material as ^ `(TextureClass self)' =>
{ withTexture* `Texture', withCoglMaterial `CoglMaterial' } -> `()' #}
-}
-- | Retrieves the value set with 'textureGetSyncSize'
--
-- [@texture@] a 'Texture'
--
-- [@Returns@] @True@ if the 'Texture' should have the same preferred
-- size of the underlying image data
--
-- * Since 1.0
--
{# fun unsafe texture_get_sync_size as ^ `(TextureClass self)' => { withTextureClass* `self' } -> `Bool' #}
-- | Sets whether texture should have the same preferred size as the
-- underlying image data.
--
-- [@texture@] a 'Texture'
--
-- [@sync_size@] @True@ if the texture should have the same size of
-- the underlying image data
--
-- * Since 1.0
--
{# fun unsafe texture_set_sync_size as ^ `(TextureClass self)' =>
{ withTextureClass* `self', `Bool' } -> `()' #}
-- | Retrieves the horizontal and vertical repeat values set using
-- 'textureSetRepeat'
--
-- [@texture@] a 'Texture'
--
-- [@Returns@] (horizontal (x) repeat, vertical (y) repeat)
--
-- * Since 1.0
--
{# fun unsafe texture_get_repeat as ^ `(TextureClass self)' =>
{ withTextureClass* `self', alloca- `Bool' peekBool*, alloca- `Bool' peekBool* } -> `()' #}
-- | Sets whether the texture should repeat horizontally or vertically
-- when the actor size is bigger than the image size
--
-- [@texture@] a 'Texture'
--
-- [@repeat_x@] @True@ if the texture should repeat horizontally
--
-- [@repeat_y@] @True@ if the texture should repeat vertically
--
-- * Since 1.0
--
{# fun unsafe texture_set_repeat as ^ `(TextureClass self)' =>
{ withTextureClass* `self', `Bool', `Bool' } -> `()' #}
-- | Retrieves the value set using 'textureGetKeepAspectRatio'
--
-- [@texture@] a 'Texture'
--
-- [@Returns@] @True@ if the 'Texture' should maintain the aspect
-- ratio of the underlying image
--
-- * Since 1.0
--
{# fun unsafe texture_get_keep_aspect_ratio as ^ `(TextureClass self)' =>
{ withTextureClass* `self' } -> `Bool' #}
-- | Sets whether texture should have a preferred size maintaining the
-- aspect ratio of the underlying image
--
-- [@texture@] a 'Texture'
--
-- [@keep_aspect@] @True@ to maintain aspect ratio
--
-- * Since 1.0
--
{# fun unsafe texture_set_keep_aspect_ratio as ^ `(TextureClass self)' =>
{ withTextureClass* `self', `Bool'} -> `()' #}
-- | Retrieves the value set using 'textureSetLoadAsync'
--
-- [@texture@] a 'Texture'
--
-- [@Returns@] @True@ if the 'Texture' should load the data from disk
-- asynchronously
--
-- * Since 1.0
--
{# fun unsafe texture_get_load_async as ^ `(TextureClass self)' =>
{ withTextureClass* `self' } -> `Bool' #}
-- | Sets whether texture should use a worker thread to load the data
-- from disk asynchronously. Setting load_async to @True@ will make
-- 'textureSetFromFile' return immediately.
--
-- See the 'textureLoadAsync' property documentation, and
-- 'textureSetLoadDataAsync'.
--
-- [@texture@] a 'Texture'
--
-- [@load_async@] @True@ if the texture should asynchronously load
-- data from a filename
--
-- * Since 1.0
--
{# fun unsafe texture_set_load_async as ^ `(TextureClass self)' =>
{ withTextureClass* `self', `Bool'} -> `()' #}
-- | Retrieves the value set by 'textureSetLoadDataAsync'
--
-- [@texture@] a 'Texture'
--
-- [@Returns@] @True@ if the 'Texture' should load the image data from
-- a file asynchronously
--
-- * Since 1.0
--
{# fun unsafe texture_get_load_data_async as ^ `(TextureClass self)' =>
{ withTextureClass* `self' } -> `Bool' #}
-- | Sets whether texture should use a worker thread to load the data
-- from disk asynchronously. Setting load_async to @True@ will make
-- 'textureSetFromFile' block until the 'Texture' has determined the
-- width and height of the image data.
--
-- See the "load-async" property documentation, and
-- 'textureSetLoadAsync'.
--
-- [@texture@] a 'Texture'
--
-- [@load_async@] @True@ if the texture should asynchronously load
-- data from a filename
--
-- * Since 1.0
--
{# fun unsafe texture_set_load_data_async as ^ `(TextureClass self)' =>
{ withTextureClass* `self', `Bool'} -> `()' #}
-- attributes
-- | The underlying COGL material handle used to draw this actor.
--textureCoglMaterial :: (TextureClass self) => Attr self CoglMaterial
--textureCoglMaterial = newAttr textureGetCoglMaterial textureSetCoglMaterial
-- | The underlying COGL texture handle used to draw this actor.
--textureCoglTexture :: (TextureClass self) => Attr self CoglTexture
--textureCoglTexture = newAttr textureGetCoglTexture textureSetCoglTexture
-- | Force the underlying texture to be singlularand not made of of
-- smaller space saving inidivual textures.
--
-- Default value: @False@
--
textureDisableSlicing :: (TextureClass self) => Attr self Bool
textureDisableSlicing = newAttrFromBoolProperty "disable-slicing"
-- | The full path of the file containing the texture.
--
-- Default value: @Nothing@
--
textureFilename :: (TextureClass self) => WriteAttr self (Maybe String)
textureFilename = writeAttrFromMaybeStringProperty "filename"
-- | Rendering quality used when drawing the texture.
--
-- Default value: 'TextureQualityMedium'
--
textureFilterQuality :: (TextureClass self) => Attr self TextureQuality
textureFilterQuality = newNamedAttr "filter-quality" textureGetFilterQuality textureSetFilterQuality
-- | Keep the aspect ratio of the texture when requesting the
-- preferred width or height.
--
-- Default value: @False@
--
textureKeepAspectRatio :: (TextureClass self) => Attr self Bool
textureKeepAspectRatio = newNamedAttr "keep-aspect-ratio" textureGetKeepAspectRatio textureSetKeepAspectRatio
--CHECKME: Threading stuff
-- | Tries to load a texture from a filename by using a local thread
-- to perform the read operations. The initially created texture has
-- dimensions 0x0 when the true size becomes available the
-- "size-change" signal is emitted and when the image has completed
-- loading the "load-finished" signal is emitted.
--
-- Threading is only enabled if g_thread_init() has been called prior
-- to clutter_init(), otherwise 'Texture' will use the main loop to
-- load the image.
--
-- The upload of the texture data on the GL pipeline is not
-- asynchronous, as it must be performed from within the same thread
-- that called clutter_main().
--
-- Default value: @False@
--
-- * Since 1.0
--
textureLoadAsync :: (TextureClass self) => Attr self Bool
textureLoadAsync = newNamedAttr "load-async" textureGetLoadAsync textureSetLoadAsync
-- | Like 'textureLoadAsync' but loads the width and height
-- synchronously causing some blocking.
--
-- Default value: @False@
--
-- Since 1.0
--
textureLoadDataAsync :: (TextureClass self) => Attr self Bool
textureLoadDataAsync = newAttr textureGetLoadDataAsync textureSetLoadDataAsync
-- | CoglPixelFormat to use.
--
-- Default value: CoglPixelFormatRgba8888
--
--textureCoglPixelFormat :: (TextureClass self) => Attr self CoglPixelFormat
--textureCoglPixelFormat = newAttr textureGetCoglPixelFormat textureSetCoglPixelFormat
-- | Repeat underlying pixbuf rather than scale in x direction.
--
-- Default value: @False@
--
textureRepeatX :: (TextureClass self) => Attr self Bool
textureRepeatX = newAttrFromBoolProperty "repeat-x"
-- | Repeat underlying pixbuf rather than scale in y direction.
--
-- Default value: @False@
--
textureRepeatY :: (TextureClass self) => Attr self Bool
textureRepeatY = newAttrFromBoolProperty "repeat-y"
-- | Auto sync size of actor to underlying pixbuf dimensions.
--
-- Default value: @True@
--
textureSyncSize :: (TextureClass self) => Attr self Bool
textureSyncSize = newNamedAttr "sync-size" textureGetSyncSize textureSetSyncSize
--CHECKME:
-- | Maximum waste area of a sliced texture.
--
-- Allowed values: >= -1
--
-- Default value: 127
--
textureTileWaste :: (TextureClass self) => ReadAttr self Int
textureTileWaste = readNamedAttr "tile-waste" textureGetMaxTileWaste
-- signals
--CHECKME: Exception in handler?
onLoadFinished, afterLoadFinished :: Texture -> (Maybe GError -> IO ()) -> IO (ConnectId Texture)
onLoadFinished = connect_BOXED__NONE "load-finished" maybeNullPeek False
afterLoadFinished = connect_BOXED__NONE "load-finished" maybeNullPeek True
-- | The ::'loadFinished' signal is emitted when a texture load has
-- completed. If there was an error during loading, error will be set,
-- otherwise it will be @Nothing@
--
-- [@error@] A set error, or @Nothing@
--
-- * Since 1.0
--
loadFinished :: (TextureClass self) => Signal self (GError -> IO ())
loadFinished = Signal (connect_BOXED__NONE "load-finished" peek)
onPixbufChange, afterPixbufChange :: Texture -> IO () -> IO (ConnectId Texture)
onPixbufChange = connect_NONE__NONE "pixbuf-change" False
afterPixbufChange = connect_NONE__NONE "pixbuf-change" True
-- | The ::pixbuf-change signal is emitted each time the pixbuf used
-- by texture changes.
--
pixbufChange :: (TextureClass self) => Signal self (IO ())
pixbufChange = Signal (connect_NONE__NONE "pixbuf-change")
onSizeChange, afterSizeChange :: Texture -> (Int -> Int -> IO ()) -> IO (ConnectId Texture)
onSizeChange = connect_INT_INT__NONE "size-change" False
afterSizeChange = connect_INT_INT__NONE "size-change" True
-- | The ::size-change signal is emitted each time the size of the
-- pixbuf used by texture changes. The new size is given as argument
-- to the callback.
--
-- [@width@] the width of the new texture
--
-- [@height@] the height of the new texture
--
sizeChange :: (TextureClass self) => Signal self (Int -> Int -> IO ())
sizeChange = Signal (connect_INT_INT__NONE "size-change")