Как бы я мог представить пиксельный рендеринг в Haskell? - PullRequest
7 голосов
/ 03 сентября 2011

Представьте себе императивный движок рендеринга, который перетаскивает спрайты в растровое изображение, которое затем отображается. Это в значительной степени зависит от способности эффективно изменять отдельные пиксели в указанном растровом изображении. Как бы я сделал такую ​​вещь на языке без побочных эффектов? Я полагаю, нужна совершенно другая структура данных?

Ответы [ 3 ]

5 голосов
/ 03 сентября 2011

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

Хотя мне кажется, что базовая операция блита может быть выполнена в более функциональном стиле. Вы в основном комбинируете два растровых изображения для создания нового растрового изображения с помощью пиксель за пикселем. Это звучит очень функционально для меня.

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

4 голосов
/ 03 сентября 2011

У Haskell есть побочные эффекты, и вы должны использовать их, когда они уместны.Высокоскоростная процедура blit, которая будет в вашем внутреннем цикле (и, следовательно, критичная для производительности), безусловно, является одним из мест, где мутация является подходящей, поэтому используйте ее!У вас есть несколько вариантов:

  • Бросьте свои собственные в Haskell, используя ST (U) Array или IO (U) Array.Не рекомендуется.
  • Сверните свое собственное в C и позвоните в FFI.Не рекомендуется.
  • Используйте один из множества графических наборов инструментов, который уже предлагает этот вид операций и на которые уходит сотни часов программиста на создание хорошего интерфейса с высокой производительностью, такого как Gtk или OpenGL.Настоятельно рекомендуется.

Наслаждайтесь!

1 голос
/ 03 сентября 2011

Естественным функциональным способом представления изображения является использование индексной функции:

Image :: (Int,Int) -> Color

. При таком представлении будет выполнено перетаскивание области от одного изображения к другому с помощью

blit area a b = \(x,y) -> if (x,y) `isInsideOf` area then a (x,y) else b (x,y)  
*.1006 * Если требуется перевод или другое преобразование, его можно напрямую применить к координатам:
translate (dx,dy) image = \(x,y) ->  b (x+dx,y+dy)  

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

quadraticInterpolation :: ((Int,Int) -> Color) -> ((Double,Double) -> Color)

В некоторых случаях производительность может пострадатьслучаи, например, когда вы объединяете несколько изображений в одно, а затем выполняете вычисления с результатом.Это приводит к цепочке тестов для каждого пикселя для каждого последующего расчета.Однако, применяя памятку, мы можем временно преобразовать функциональное представление в массив и преобразовать его обратно в его индексную функцию, тем самым устраняя снижение производительности для последовательных операций.

Обратите внимание, что памятка также может использоваться дляввести параллелизм в процесс.

...