Here you need to separate the two problems. First you need to calculate the pixel value. This should be a pure function of the scene and the coordinates of the beam you are shooting at. Then you need to write this value to the screen.
So first you need a function:
type Coord = (Int, Int) raytrace :: Scene -> Coord -> (Coord, Colour) -- You will see why it returns this pair in a few lines
Then you want to call this function for each pixel on your surface to get a list of coordinate pairs:
allCoords :: Int -> Int -> [Coord] allCoords width height = [(x,y) | x <- [0..width], y <- [0..height]] allPixels :: Scene -> Int -> Int -> [(Coord, Colour)] allPixels scene wh = map (raytrace scene) (allCoords wh)
Finally, place the list of pixels on the display surface using the pixel function.
writeScene :: Surface -> Scene -> Int -> Int -> IO () writeScene surface scene wh = mapM_ writePixel (allPixels scene wh) where writePixel ((x,y),c) = pixel surface xyc
The only thing your pixel function returns is โIO Boolโ. I donโt know why, so I ignored it using "mapM_" and not "mapM".
It looks like it creates a terribly inefficient list of coordinate pairs and colors, and then iterates to draw an image. But actually, thanks to the lazy nature of Haskell, it actually comes down to a loop that generates each color and then calls a โpixelโ on the result.
Paul johnson
source share