画像とピクセルレンダリングがハスケルの最後のものの1つ私は効率的な十分に機能的なデータ構造を選ぶことができませんでした。簡潔にするため、1D
の画像については、n-d画像に簡単に拡張できるので、話をしてください。これは私が見つけたCPUレンダリングのための最もパフォーマンスの高いデザインです画像へのレンダリングを効率的に実装する純粋に機能的なデータ構造とは何ですか?
-- An 1D image is an unboxed vector of Pixels
type Position = Int
data Image = Image { size :: Position, buffer :: UV.Vector Pixel }
-- A sprite is a recipe to draw something to an Image
newtype Sprite = Sprite (forall s .
-> (Position -> Pixel -> ST s()) -- setPixel
-> ST s()) -- ST action that renders to Image
-- Things that can be rendered to screen provide a sprite
class Renderable a where
getSprite a :: a -> Sprite
-- `render` applies all sprites, mutably, in sequence. `O(P)` (where P = pixels to draw)
render :: [Sprite] -> Image -> Image
render draws (Image size buffer) = Image size $ runST $ do ...
、まだそれはかなり醜いです:私は、レンダリングのための表現とその可変ビューとして、非ボックス化ベクトルを使用しています。 render
を実装する純粋に機能的な構造の場合、明らかな答えは、マップを使用して画像を表現し、(Position, Pixel)
ペアのリストを使用してスプライトを表すことです。以下のようなもの:O(P * log(N))
ある
-- 1D for simplicity
type Position = Int
-- An image is a map from positions to colors
type Image = Map Position Pixel
-- A sprite is, too, a map from positions to colors
type Sprite = [(Position, Pixel)]
-- Rendering is just inserting each pixel in sequence
-- (Not tested.)
render :: [Sprite] -> Image -> Image
render sprites image = foldr renderSprite image sprites
where renderSprite sprite image = foldr (uncurry insert) image sprites
(P =レンダリングする画素、N画像のサイズ=)。 log(N)
は回避できないと思われるかもしれませんが、慎重に参照すると、Image
を通して同じパスを移動しています(つまり、位置0に挿入してから位置1に挿入すると、そして、すべての道を上にして、隣りの葉に至るまで)。それは正確に同じパターンのように見えるzippers
は、漸進性を改善することができ、私には疑いをもたらすrender
を改善することができます。 O(P*log N)
よりも、render
を実装することができる純粋に機能的なデータ構造はありますか?
注:「純粋に機能」によって、私は特に一人でHaskellの代数的データ型だけを使用しない構造を意味し、すなわち、そのようInt
やArray
などのネイティブのプリミティブなし(純粋なデータ構造は以下ネザーとしてそれらを技術的に提供されていても)。
どのように? –
これはあなたの質問に本当に答えるものではありませんが、とにかく質問したいと思います。あなたの最初のアプローチでは、Spriteは 'Position - > Pixel - > ST s()'への呼び出しのリストに相当します。同じパフォーマンスを維持しながら、それをより良くするために '[(Position、Pixel)]'に変更できませんでしたか? – madjar
私のスキルが行く限り、いいえ。問題は、Position - > Pixel - > ST()は常に一定のスペースを使用することです。リストを扱うためには、常にすべてのリストを融合し、一定のスペースループにコンパイルする必要があります。たぶん私だけだったかもしれませんが、シンプルなレンダリングパターンでも同じことをすることはできませんでした。 – MaiaVictor