views:

339

answers:

1

I wish to draw individual pixels on a screen in a window or something for real-time display in haskell.

I'm just getting started with haskell (but not functional programming, and not graphics), so I'm trying to create some rudimentary graphics things with it.

I have tried to use SDL, but the following code gives me a blank screen:

import Prelude
import Graphics.UI.SDL as SDL

createColor screen r g b = SDL.mapRGB (SDL.surfaceGetPixelFormat screen) r g b

drawGrad screen = SDL.setColors screen [SDL.Color x y 255 | x <- [0..255], y <- [0..255]] 800

main = do
  SDL.init [InitEverything]
  setVideoMode 256 256 32 []
  screen <- getVideoSurface
  drawGrad screen
  SDL.flip screen
  quitHandler

quitHandler :: IO ()
quitHandler = do
  e <- waitEvent
  case e of
    Quit -> return ()
    otherwise -> quitHandler
+2  A: 

It looks to me like you aren't actually drawing anything there. Are you sure setColors does what you think it does? If memory serves me, it's for setting the color palette for an 8-bit surface, whereas you're explicitly setting a 32-bit video mode.

As an aside, if you've done graphics programming before I'm sure you know the difference, but for the benefit of others reading this: 8-bit video modes store pixel colors as an 8-bit index into a table of 256 colors chosen from a much larger set of potential colors; in higher color depths, the palette table is dispensed with and each pixel color is stored directly as a packed RGB triple, typically of 8 bits each (32-bit pixels either have an 8-bit alpha channel as well, or just 8 bits of padding for better memory alignment, I can't recall).

Either way, if I'm guessing correctly what you were attempting to do, try adding this to your program:

import Ix

-- Given coordinates, create a 1x1 rectangle containing that pixel
getPix x y = SDL.Rect (fromIntegral x) (fromIntegral y) 1 1

-- Draw a pixel on a surface with color determined by position
drawPixel surf (x, y) = do
    let pixRect = Just (getPix x y)
    pixColor <- createColor surf x y 255
    SDL.fillRect surf pixRect pixColor

-- Apply drawPixel to each coordinate on the screen
drawGrad screen = mapM_ (drawPixel screen) $ range ((0,0),(255,255))

Warning: That's almost certainly horrible and inefficient code, and it has been tested only in a Win32 environment. I am not a qualified Haskell programmer and my advice should not be taken as indicative of correct use of the language. For external use only. Do not taunt the Happy Fun IO Monad.

Either way, I think your problem lies with use of SDL, not Haskell. Graphics.UI.SDL is pretty raw, little more than wrapping the C API in appropriate Haskell types. If you've not used SDL before, or used it only with slightly more elaborate bindings (e.g., PyGame), you may want to consider looking for SDL examples in C as reference material.

camccann
I guess this is good enough while I'm learning even if its slow, I can figure out how to do it faster later.