-
Notifications
You must be signed in to change notification settings - Fork 0
/
SPUtil.hs
121 lines (95 loc) · 3.73 KB
/
SPUtil.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
module SPUtil where
import Graphics.Rendering.OpenGL
import VertexUtil
import SP
-- TODO: Split into base utilities / geometry utilities / shapes
putL :: (Monad m) => [b] -> SP m a b -> SP m a b
putL [] r = r
putL (a:b) r = Put a (putL b r)
rPutL :: (Monad m) => [b] -> SP m a b
rPutL l = rPutL'
where rPutL' = putL l rPutL'
partOfAng ang n x = fromIntegral x * ang / fromIntegral n
(..&) :: (Monad m) => Int -> Int -> SP m a Int
s ..& e = rPutL [s..e]
circleGen :: (Monad m, Floating b) => Int -> SP m a (Vertex3 b)
circleGen n = 0 ..& (n-1) >>> arr (partOfAng (2 * pi) n) >>>
v3Fun cos sin (\a -> 0)
batch :: (Monad m) => Int-> SP m a [a]
batch n = batch' n [] (batch n)
batch' 0 l r = Put l r
batch' n l r = Get (\a -> batch' (n - 1) (l ++ [a]) r)
unbatch :: (Monad m) => SP m [a] a
unbatch = Get (\a -> unbatch' a)
unbatch' [] = unbatch
unbatch' (h:t) = Put h (unbatch' t)
concatA :: (Monad m) => SP m [[a]] [a]
concatA = arr concat
sphereLineGen :: (Monad m, Floating b) => Int -> SP m a (Vertex3 b)
sphereLineGen n = 0 ..& (n - 1) >>> arr (partOfAng pi (n - 1)) >>>
v3Fun (\a -> 0) (\a -> 0) cos
sphereSliceSizeGen :: (Monad m, Floating b) => Int -> SP m a b
sphereSliceSizeGen n = 0 ..& (n - 1) >>> arr (partOfAng pi (n - 1)) >>> arr sin
scaleF (shape, scale) = map (\a -> scale -.- a) shape
scaleA :: Monad m => SP m ([Vertex3 Float], Float) [Vertex3 Float]
scaleA = arr scaleF
translateF (shape, loc) = map (loc +!+) shape
translateA :: Monad m => SP m ([Vertex3 Float], Vertex3 Float) [Vertex3 Float]
translateA = arr translateF
-- TODO: recast in terms of vertex algebra
-- TODO rename these as "SP" versions (or Prim or something)
scaleExtrude :: Monad m
=> SP m ((Vertex3 Float, Float), [Vertex3 Float]) [Vertex3 Float]
--scaleExtrude = arr (\((Vertex3 px py pz, scale), shape) ->
-- map (\(Vertex3 x y z) -> Vertex3 (px+scale*x) (py+scale*y) (pz+scale*z))
-- shape)
scaleExtrude = arr (\((a,b),c) -> ((c,b),a)) >>> first scaleA >>> translateA
pairwise :: Monad m => (a -> a -> b) -> SP m a b
pairwise f = Get (\a1 -> pairwise' f a1)
pairwise' f a1 = Get (\a2 -> Put (f a1 a2) (pairwise' f a2))
toQuadLoop :: [a] -> [a] -> [a]
toQuadLoop l1 l2 = concat (zipWith toQuad ll1 ll2)
where
ll1 = zip l1 ((tail l1) ++ [head l1])
ll2 = zip l2 ((tail l2) ++ [head l2])
toQuad (a,b) (c,d) = [a,b,d,c]
-- This relies on zip ignoring the end value in l1 and l2 because the
-- second list is shorter
toQuads :: [a] -> [a] -> [a]
toQuads l1 l2 = concat (zipWith toQuad ll1 ll2)
where
ll1 = zip l1 (tail l1)
ll2 = zip l2 (tail l2)
toQuad (a,b) (c,d) = [a,b,d,c]
pairwiseL :: (a -> a -> b) -> [a] -> [b]
pairwiseL f [a] = []
pairwiseL f (a:b:l) = (f a b):(pairwiseL f (b:l))
sphere :: (Monad m) => Int -> Int -> SP m i [Vertex3 Float]
--sphere slices segments = ((sphereLineGen slices &&& sphereSliceSizeGen slices) &&& (circleGen segments >>> batch segments)) >>> scaleExtrude >>> (pairwise toQuadLoop) >>> batch (slices - 1) >>> concatA
sphere slices segments =
(
(
(
(circleGen segments >>> batch segments)
&&&
sphereSliceSizeGen slices
) >>> scaleA
)
&&&
sphereLineGen slices
) >>> translateA >>> (pairwise toQuadLoop) >>> batch (slices - 1) >>> concatA
liftSP :: Monad m => (a -> SP m b c) -> SP m (Either a b) c
liftSP f = lift' onlyGet where
lift' (Put v sp) = Put v (lift' sp)
lift' sp = Get (lift'' sp)
lift'' sp (Left a) = lift' (f a)
lift'' (Get fsp) (Right b) = lift' (fsp b)
onlyGet = Get (\_ -> onlyGet)
printTaggedSP :: Show a => String -> SP IO a a
printTaggedSP s = Get (\a -> Block(do
putStrLn $ s ++ ": " ++ (show a)
return (Put a $ printTaggedSP s)))
printSP :: Show a => SP IO a a
printSP = Get (\a -> Block(do
putStrLn (show a)
return (Put a printSP)))