从OpenGL/GLUT应用程序中读取像素

Sam*_*ern 8 opengl haskell pointers pixels

我有一个使用OpenGL和GLUT在屏幕上显示一些内容的应用程序.我想访问"逐个像素"显示的颜色,但我无法理解所提供的方法.

似乎访问这些数据的方法是使用函数: readPixels :: Position -> Size -> PixelData a -> IO () 这肯定是非Haskelly,因为它使用C模式获取目标指针并写入该指针.

第三个参数是重要的部分,它的构造就像PixelData PixelFormat DataType (Ptr a). PixelFormat并且DataType都是枚举,前者采取的价值观RGBAInteger, RGBA, CMYK, etc和后者采取的价值如UnsignedByte, Short, Float, etc. 选择令我困惑,但这不是真正的问题.我真正在努力使用指针.我不知道要创建指针的Storable数据类型malloc,或者如果我选择使用要分配多少字节mallocBytes.

我有一个我正在搞乱的功能,目前看起来像这样:

pixels :: IO ()
pixels = do
    pointer <- mallocBytes 50000
    let pdata = PixelData RGBA Int pointer
    let pos = Position 0 0
    let siz = Size 10 10
    readPixels pos siz pdata
    print pdata
    mypixels <- peek pointer
    -- TODO, what kind of data is mypixels?
    free pointer 
Run Code Online (Sandbox Code Playgroud)

它运行正常我只是不知道如何使用我从中得到的数据Ptr.也许我不完全理解文档,但是如何确定指针的数据类型以及如何在程序中使用它?请注意,我选择的参数RGBA并且Int是随意的,它们听起来足够无害.我真正想要的是一些格式的RGBA像素值的列表或多维列表(Color 4或者那种性质的东西).任何帮助将不胜感激,我似乎在我的脑海里.

Cat*_*lus 7

你正在使用低级绑定,不要惊讶他们是低级别的.readPixels直接对应glReadPixels(他们使用MathML,所以使用支持它的浏览器来查看它).

你得到的是一个32位整数数组,每个整数都包含RGBA颜色值.你只需要width * height * 4字节就可以了,你要分配很多东西.

FFI机器peekArray可以很容易地从中读取它 - 它可以用来将像素数据提取到Haskell列表中.您还需要使用正确类型的指针.mallocBytes返回对应的特殊类型的指针void*.我正在使用ForeignPtr运行时负责最终确定它(mallocBytes您需要使用castPtr并且还要bracket考虑异常).

import Data.Word
import Foreign
import Graphics.Rendering.OpenGL

readPixelArray :: Int -> Int -> Int -> Int -> IO [Word32]
readPixelArray x y w h = do
    let arraySize = w * h
    array <- mallocForeignPtrArray arraySize :: IO (ForeignPtr Word32)
    withForeignPtr array $ \ptr -> do
        -- ptr :: Ptr Word32
        -- fromIntegral is needed because Position and Size store GLints not Ints
        let position = Position (fromIntegral x) (fromIntegral y)
        let size = Size (fromIntegral w) (fromIntegral h)
        readPixels position size $ PixelData RGBA UnsignedInt ptr
        peekArray arraySize ptr
Run Code Online (Sandbox Code Playgroud)

现在你有了一维的颜色值数组.我们可以把它分成这样的类型:

import Data.Bits

data Pixel = Pixel {
    red :: Word8, green :: Word8, blue :: Word8, alpha :: Word8
} deriving (Eq, Show)

readPixels' :: Int -> Int -> Int -> Int -> IO [Pixel]
readPixels' x y w h = do
    rawPixels <- readPixelArray x y w h
    return $ map pixelFromWord32 rawPixels

-- pixelFromWord32 0xAABBCCDD = Pixel 0xAA 0xBB 0xCC 0xDD
pixelFromWord32 :: Word32 -> Pixel
pixelFromWord32 colour = Pixel (extract 3) (extract 2) (extract 1) (extract 0)
    where extract idx = fromIntegral $ (colour `shiftR` (idx * 8)) .&. 0xFF
Run Code Online (Sandbox Code Playgroud)