    -- #hide
    --------------------------------------------------------------------------------
    -- |
    -- Module      :  Sound.OpenAL.AL.BufferInternal
    -- Copyright   :  (c) Sven Panne 2003-2005
    -- License     :  BSD-style (see the file libraries/OpenAL/LICENSE)
    --
    -- Maintainer  :  sven.panne@aedion.de
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- This is a purely internal module for (un-)marshaling Buffer.
    --
    --------------------------------------------------------------------------------

    module Sound.OpenAL.AL.BufferInternal (
       Buffer, marshalBuffer, unmarshalBuffer
    ) where

    import Foreign.Marshal.Array ( withArrayLen, peekArray, allocaArray )
    import Foreign.Ptr ( Ptr, castPtr )
    import Foreign.Storable ( Storable(..) )
    import Graphics.Rendering.OpenGL.GL.BufferObjects ( ObjectName(..) )
    import Sound.OpenAL.AL.ALboolean ( unmarshalALboolean )
    import Sound.OpenAL.AL.BasicTypes ( ALboolean, ALuint, ALsizei )
    import Sound.OpenAL.AL.PeekPoke ( peek1, poke1 )

    --------------------------------------------------------------------------------

    -- | The abstract buffer type.

    newtype Buffer = Buffer { bufferID :: ALuint }
       deriving ( Eq, Ord, Show )

    -- | A dummy buffer.

    nullBuffer :: Buffer
    nullBuffer = Buffer 0

    marshalBuffer :: Maybe Buffer -> ALuint
    marshalBuffer = bufferID . maybe nullBuffer id

    unmarshalBuffer :: ALuint -> Maybe Buffer
    unmarshalBuffer b =
       if b == bufferID nullBuffer then Nothing else Just (Buffer b)

    instance Storable Buffer where
       sizeOf    ~(Buffer b) = sizeOf b
       alignment ~(Buffer b) = alignment b
       peek                  = peek1 Buffer . castPtr
       poke ptr   (Buffer b) = poke1 (castPtr ptr) b

    --------------------------------------------------------------------------------
    -- This should really be in Sound.OpenAL.AL.Buffer, but we have it here to
    -- avoid an orphan module.

    instance ObjectName Buffer where
       genObjectNames n =
          allocaArray n $ \buf -> do
            alGenBuffers (fromIntegral n) buf
            peekArray n buf

       deleteObjectNames buffers =
          withArrayLen buffers $ alDeleteBuffers . fromIntegral

       isObjectName = fmap unmarshalALboolean . alIsBuffer

    foreign import CALLCONV unsafe "alGenBuffers"
       alGenBuffers :: ALsizei -> Ptr Buffer -> IO ()

    foreign import CALLCONV unsafe "alDeleteBuffers"
       alDeleteBuffers :: ALsizei -> Ptr Buffer -> IO ()

    foreign import CALLCONV unsafe "alIsBuffer"
       alIsBuffer :: Buffer -> IO ALboolean