/
RepaV3.hs
162 lines (138 loc) · 4.31 KB
/
RepaV3.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Mandelbrot.RepaV3 (mandelbrotImageGenerator) where
import Prelude hiding (map, zipWith)
import qualified Prelude as P
import Data.Array.Repa
import Data.Array.Repa.Eval
import Data.Array.Repa.Repr.ForeignPtr
import Data.Array.Repa.Repr.HintInterleave
import Data.IORef
import Data.Word
type R = Double
type Complex = (R, R)
type RGBA = Word32
type Bitmap r = Array r DIM2 RGBA
type MBitmap r = MVec r RGBA
type ComplexPlane r = Array r DIM2 Complex
type StepPlane r = Array r DIM2 (Complex, Int)
magnitude :: Complex -> R
magnitude (x,y) = x*x + y*y
instance Num Complex where
{-# INLINE (+) #-}
{-# INLINE (-) #-}
{-# INLINE (*) #-}
{-# INLINE negate #-}
{-# INLINE abs #-}
{-# INLINE signum #-}
{-# INLINE fromInteger #-}
(x,y) + (x',y') = (x+x', y+y')
(x,y) - (x',y') = (x-x', y-y')
(x,y) * (x',y') = (x*x'-y*y', x*y'+y*x')
negate (x,y) = (negate x, negate y)
abs z = (magnitude z, 0)
signum (0,0) = 0
signum z@(x,y) = (x/r, y/r) where r = magnitude z
fromInteger n = (fromInteger n, 0)
stepN :: Int -> ComplexPlane U -> StepPlane U -> IO (StepPlane U)
stepN n cs zs =
computeP $ hintInterleave $ zipWith (stepPoint n) cs zs
where
stepPoint :: Int -> Complex -> (Complex, Int) -> (Complex, Int)
{-# INLINE stepPoint #-}
stepPoint 0 !_ (!z,!i) =
(z, i)
stepPoint !k !c (!z,!i) =
if magnitude z' > 4.0
then (z, i)
else stepPoint (k-1) c (z', i+1)
where
z' = next c z
next :: Complex -> Complex -> Complex
{-# INLINE next #-}
next !c !z = c + (z * z)
genPlane :: R
-> R
-> R
-> R
-> Int
-> Int
-> ComplexPlane D
genPlane lowx lowy highx highy viewx viewy =
fromFunction (Z:.viewy:.viewx) $ \(Z:.(!y):.(!x)) ->
(lowx + (fromIntegral x*xsize)/fromIntegral viewx,
lowy + (fromIntegral y*ysize)/fromIntegral viewy)
where
xsize, ysize :: R
xsize = highx - lowx
ysize = highy - lowy
mkinit :: Source r Complex => ComplexPlane r -> StepPlane D
mkinit cs = map f cs
where
f :: Complex -> (Complex, Int)
{-# INLINE f #-}
f z = (z, 0)
mandelbrot :: R
-> R
-> R
-> R
-> Int
-> Int
-> Int
-> IO (StepPlane U)
mandelbrot lowx lowy highx highy viewx viewy depth = do
cs <- computeP $ genPlane lowx lowy highx highy viewx viewy
zs0 <- computeP $ mkinit cs
stepN depth cs zs0
prettyRGBA :: Int -> (Complex, Int) -> RGBA
{-# INLINE prettyRGBA #-}
prettyRGBA limit (_, s) = r + g + b + a
where
t = fromIntegral $ ((limit - s) * 255) `quot` limit
r = (t `mod` 128 + 64) * 0x1000000
g = (t * 2 `mod` 128 + 64) * 0x10000
b = (t * 3 `mod` 256 ) * 0x100
a = 0xFF
prettyMandelbrot :: Int -> StepPlane U -> MBitmap F -> IO ()
prettyMandelbrot limit zs mbmap =
loadP (map (prettyRGBA limit) zs) mbmap
type MandelFun = R
-> R
-> R
-> R
-> Int
-> Int
-> Int
-> IO (Bitmap F)
data MandelState = MandelState
{ manDim :: DIM2
, manMbmap :: MBitmap F
}
mandelbrotImageGenerator :: IO MandelFun
mandelbrotImageGenerator = do
mbmap <- newMVec 0
stateRef <- newIORef (MandelState (ix2 0 0) mbmap)
return $ mandelbrotImage stateRef
where
mandelbrotImage :: IORef MandelState -> MandelFun
mandelbrotImage stateRef lowx lowy highx highy viewx viewy depth = do
let sh = ix2 viewy viewx
state <- updateState stateRef sh
zs <- mandelbrot lowx lowy highx highy viewx viewy depth
prettyMandelbrot depth zs (manMbmap state)
unsafeFreezeMVec sh (manMbmap state)
updateState :: IORef MandelState -> DIM2 -> IO MandelState
updateState stateRef sh = do
state <- readIORef stateRef
if manDim state == sh
then return state
else newState
where
newState :: IO MandelState
newState = do
mbmap <- newMVec (size sh)
let state' = MandelState sh mbmap
writeIORef stateRef state'
return state'