2011-02-11 4 views
6

У меня есть эта функция в Haskell (я использую Haskell-SDL библиотека):Функциональный эквивалент итерация 2D-массив

pixel :: Surface -> Int16 -> Int16 -> Pixel -> IO Bool

pixel screen x y color

Я хочу использовать это, чтобы занять 2D-массив (или какой-либо другой вид структуры данных) и нарисуйте его на экране по одному пикселю за раз. Я изучил это с помощью forM_, но не могу понять, как заставить его работать с аргументами x и y.

Я довольно новичок в Haskell и функциональном программировании в целом. Я прокладываю себе путь через еще один учебник Haskell, но эта проблема просто меня озадачила.

В случае, если это относится к решению, я пытаюсь написать raytracer. Он должен выполнить расчет для каждого пикселя, а затем записать этот пиксель на экран.

+0

Вы еще не поняли, как представить 2D-массив в Haskell? – Gabe

+0

Я считаю, что это можно сделать с помощью вложенных списков, например: [[1,2,3], [4,5,6], [7,8,9]] –

+0

Haskell имеет собственные массивы различных типов, используя Вложенный список пикселей не является хорошей идеей. Проверьте мой ответ ниже. –

ответ

1

Вам нужно разделить две проблемы здесь. Сначала вам нужно вычислить значение пикселя. Это должна быть чистая функция сцены и координаты луча, в который вы стреляете. Затем вам нужно записать это значение пикселя на экран.

Итак, сначала вы хотите функцию:

type Coord = (Int, Int) 

raytrace :: Scene -> Coord -> (Coord, Colour) 
    -- You will see why it returns this pair in a few lines 

Затем вы хотите позвонить эту функцию для каждого пиксела в вашей поверхности, чтобы получить список координат пар цветов:

allCoords :: Int -> Int -> [Coord] 
allCoords width height = [(x,y) | x <- [0..width], y <- [0..height]] 

allPixels :: Scene -> Int -> Int -> [(Coord, Colour)] 
allPixels scene w h = map (raytrace scene) (allCoords w h) 

И наконец, поместите список пикселей на поверхность дисплея, используя функцию «пиксель».

writeScene :: Surface -> Scene -> Int -> Int -> IO() 
writeScene surface scene w h = mapM_ writePixel (allPixels scene w h) 
    where writePixel ((x,y),c) = pixel surface x y c 

Единственная вещь, ваша функция «пикселей» возвращает «IO Bool». Я не знаю почему, поэтому я проигнорировал его, используя «mapM_», а не «mapM».

Похоже, что он создает ужасно неэффективный список пар координат и цветов, а затем выполняет итерацию, чтобы нарисовать изображение. Но на самом деле, благодаря ленивой природе Haskell, она фактически сводится к циклу, который генерирует каждый цвет, а затем вызывает «пиксель» на результат.

3

Если вы используете вложенные списки, сделайте следующее:

import Control.Monad 
plot :: Surface -> [[Pixel]] -> IO() 
plot surf = zipWithM_ (\ y -> zipWithM_ (\ x c -> pixel surf x y c) [0..]) [0..] 
2

Haskell имеет реальные массивы различных видов. Мне кажется, что вы делаете что-то довольно неэффективное, вы хотите создать буфер пикселей и разбить его на другой буфер? было бы гораздо эффективнее создать новую поверхность SDL (для которой вы можете получить/установить пиксели) и разбить ее на другую поверхность/экран или создать реальный массив пикселей и создать поверхность SDL, а затем использовать blut-процедуры SDL. Если вы объясните, что вы пытаетесь сделать, я думаю, что мы можем показать вам лучший способ.

+0

Я пытаюсь написать raytracer. Он должен выполнить расчет для каждого пикселя, а затем записать этот пиксель на экран. –

+1

@chuzzum Я предлагаю вам либо читать, либо записывать на задний буфер экрана, либо создавать пустую поверхность SDL, которая является всего лишь пиксельным буфером (для которого вы можете манипулировать пикселями) и blit (blitSurface), которые обращаются к заднему буферу или создают изменчивый unboxed array, для которого у вас есть различные параметры, такие как IOUArray, STUArray, StorableArray, Unboxed.MVector (http://hackage.haskell.org/package/vector), затем копируйте пиксели в задний буфер. SDL имеет функцию, которая может создавать поверхность SDL из массива, а также привязки haskell. Использование 2D-списка пикселей - это плохая идея. –

+0

Есть ли значительное преимущество в производительности для этого? Поскольку единственное, что я когда-либо собираюсь делать, это перебирать его, я не понимаю, почему список хуже или лучше, чем массив. В чем преимущество использования измененного массива над неизменными списками, например? Но я думаю, что писать прямо на экран, вероятно, лучшее решение. –

Смежные вопросы