summaryrefslogtreecommitdiff
path: root/src/LambdaCube/GL/Mesh.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/LambdaCube/GL/Mesh.hs')
-rw-r--r--src/LambdaCube/GL/Mesh.hs218
1 files changed, 218 insertions, 0 deletions
diff --git a/src/LambdaCube/GL/Mesh.hs b/src/LambdaCube/GL/Mesh.hs
new file mode 100644
index 0000000..f8a0bb9
--- /dev/null
+++ b/src/LambdaCube/GL/Mesh.hs
@@ -0,0 +1,218 @@
1{-# LANGUAGE TupleSections #-}
2module LambdaCube.GL.Mesh (
3 loadMesh',
4 loadMesh,
5 saveMesh,
6 addMeshToObjectArray,
7 uploadMeshToGPU,
8 updateMesh,
9 Mesh(..),
10 MeshPrimitive(..),
11 MeshAttribute(..),
12 GPUData
13) where
14
15import Control.Applicative
16import Control.Monad
17import Data.Binary
18import Data.ByteString.Char8 (ByteString)
19import Foreign.Ptr
20import Data.Int
21import Foreign.Storable
22import Foreign.Marshal.Utils
23import System.IO.Unsafe
24import qualified Data.ByteString.Char8 as SB
25import qualified Data.ByteString.Lazy as LB
26import qualified Data.Trie as T
27import qualified Data.Vector.Storable as V
28import qualified Data.Vector.Storable.Mutable as MV
29
30import LambdaCube.GL
31import LambdaCube.GL.Type as T
32import IR as IR
33import Linear as IR
34
35fileVersion :: Int32
36fileVersion = 1
37
38data MeshAttribute
39 = A_Float (V.Vector Float)
40 | A_V2F (V.Vector V2F)
41 | A_V3F (V.Vector V3F)
42 | A_V4F (V.Vector V4F)
43 | A_M22F (V.Vector M22F)
44 | A_M33F (V.Vector M33F)
45 | A_M44F (V.Vector M44F)
46 | A_Int (V.Vector Int32)
47 | A_Word (V.Vector Word32)
48
49data MeshPrimitive
50 = P_Points
51 | P_TriangleStrip
52 | P_Triangles
53 | P_TriangleStripI (V.Vector Int32)
54 | P_TrianglesI (V.Vector Int32)
55
56data Mesh
57 = Mesh
58 { mAttributes :: T.Trie MeshAttribute
59 , mPrimitive :: MeshPrimitive
60 , mGPUData :: Maybe GPUData
61 }
62
63data GPUData
64 = GPUData
65 { dPrimitive :: Primitive
66 , dStreams :: T.Trie (Stream Buffer)
67 , dIndices :: Maybe (IndexStream Buffer)
68 }
69
70loadMesh' :: String -> IO Mesh
71loadMesh' n = decode <$> LB.readFile n
72
73loadMesh :: String -> IO Mesh
74loadMesh n = uploadMeshToGPU =<< loadMesh' n
75
76saveMesh :: String -> Mesh -> IO ()
77saveMesh n m = LB.writeFile n (encode m)
78
79addMeshToObjectArray :: GLStorage -> ByteString -> [ByteString] -> Mesh -> IO Object
80addMeshToObjectArray input slotName objUniNames (Mesh _ _ (Just (GPUData prim streams indices))) = do
81 -- select proper attributes
82 let Just (SlotSchema slotPrim slotStreams) = T.lookup slotName $! T.slots $! T.schema input
83 filterStream n s
84 | T.member n slotStreams = Just s
85 | otherwise = Nothing
86 addObject input slotName prim indices (T.mapBy filterStream streams) objUniNames
87addMeshToObjectArray _ _ _ _ = fail "addMeshToObjectArray: only compiled mesh with GPUData is supported"
88
89withV w a f = w a (\p -> f $ castPtr p)
90
91meshAttrToArray :: MeshAttribute -> Array
92meshAttrToArray (A_Float v) = Array ArrFloat (1 * V.length v) $ withV V.unsafeWith v
93meshAttrToArray (A_V2F v) = Array ArrFloat (2 * V.length v) $ withV V.unsafeWith v
94meshAttrToArray (A_V3F v) = Array ArrFloat (3 * V.length v) $ withV V.unsafeWith v
95meshAttrToArray (A_V4F v) = Array ArrFloat (4 * V.length v) $ withV V.unsafeWith v
96meshAttrToArray (A_M22F v) = Array ArrFloat (4 * V.length v) $ withV V.unsafeWith v
97meshAttrToArray (A_M33F v) = Array ArrFloat (9 * V.length v) $ withV V.unsafeWith v
98meshAttrToArray (A_M44F v) = Array ArrFloat (16 * V.length v) $ withV V.unsafeWith v
99meshAttrToArray (A_Int v) = Array ArrInt32 (1 * V.length v) $ withV V.unsafeWith v
100meshAttrToArray (A_Word v) = Array ArrWord32 (1 * V.length v) $ withV V.unsafeWith v
101
102meshAttrToStream :: Buffer -> Int -> MeshAttribute -> Stream Buffer
103meshAttrToStream b i (A_Float v) = Stream Attribute_Float b i 0 (V.length v)
104meshAttrToStream b i (A_V2F v) = Stream Attribute_V2F b i 0 (V.length v)
105meshAttrToStream b i (A_V3F v) = Stream Attribute_V3F b i 0 (V.length v)
106meshAttrToStream b i (A_V4F v) = Stream Attribute_V4F b i 0 (V.length v)
107meshAttrToStream b i (A_M22F v) = Stream Attribute_M22F b i 0 (V.length v)
108meshAttrToStream b i (A_M33F v) = Stream Attribute_M33F b i 0 (V.length v)
109meshAttrToStream b i (A_M44F v) = Stream Attribute_M44F b i 0 (V.length v)
110meshAttrToStream b i (A_Int v) = Stream Attribute_Int b i 0 (V.length v)
111meshAttrToStream b i (A_Word v) = Stream Attribute_Word b i 0 (V.length v)
112
113updateMesh :: Mesh -> [(ByteString,MeshAttribute)] -> Maybe MeshPrimitive -> IO ()
114updateMesh (Mesh dMA dMP (Just (GPUData _ dS dI))) al mp = do
115 -- check type match
116 let arrayChk (Array t1 s1 _) (Array t2 s2 _) = t1 == t2 && s1 == s2
117 ok = and [T.member n dMA && arrayChk (meshAttrToArray a1) (meshAttrToArray a2) | (n,a1) <- al, let Just a2 = T.lookup n dMA]
118 if not ok then putStrLn "updateMesh: attribute mismatch!"
119 else do
120 forM_ al $ \(n,a) -> do
121 case T.lookup n dS of
122 Just (Stream _ b i _ _) -> updateBuffer b [(i,meshAttrToArray a)]
123 _ -> return ()
124{-
125 case mp of
126 Nothing -> return ()
127 Just p -> do
128 let ok2 = case (dMP,p) of
129 (Just (P_TriangleStripI v1, P_TriangleStripI v2) -> V.length v1 == V.length v2
130 (P_TrianglesI v1, P_TrianglesI v2) -> V.length v1 == V.length v2
131 (a,b) -> a == b
132-}
133
134uploadMeshToGPU :: Mesh -> IO Mesh
135uploadMeshToGPU (Mesh attrs mPrim Nothing) = do
136 let mkIndexBuf v = do
137 iBuf <- compileBuffer [Array ArrWord32 (V.length v) $ withV V.unsafeWith v]
138 return $! Just $! IndexStream iBuf 0 0 (V.length v)
139 vBuf <- compileBuffer [meshAttrToArray a | a <- T.elems attrs]
140 (indices,prim) <- case mPrim of
141 P_Points -> return (Nothing,PointList)
142 P_TriangleStrip -> return (Nothing,TriangleStrip)
143 P_Triangles -> return (Nothing,TriangleList)
144 P_TriangleStripI v -> (,TriangleStrip) <$> mkIndexBuf v
145 P_TrianglesI v -> (,TriangleList) <$> mkIndexBuf v
146 let streams = T.fromList $! zipWith (\i (n,a) -> (n,meshAttrToStream vBuf i a)) [0..] (T.toList attrs)
147 gpuData = GPUData prim streams indices
148 return $! Mesh attrs mPrim (Just gpuData)
149
150uploadMeshToGPU mesh = return mesh
151
152sblToV :: Storable a => [SB.ByteString] -> V.Vector a
153sblToV ls = v
154 where
155 offs o (s:xs) = (o,s):offs (o + SB.length s) xs
156 offs _ [] = []
157 cnt = sum (map SB.length ls) `div` (sizeOf $ V.head v)
158 v = unsafePerformIO $ do
159 mv <- MV.new cnt
160 MV.unsafeWith mv $ \dst -> forM_ (offs 0 ls) $ \(o,s) ->
161 SB.useAsCStringLen s $ \(src,len) -> moveBytes (plusPtr dst o) src len
162 V.unsafeFreeze mv
163
164vToSB :: Storable a => V.Vector a -> SB.ByteString
165vToSB v = unsafePerformIO $ do
166 let len = V.length v * sizeOf (V.head v)
167 V.unsafeWith v $ \p -> SB.packCStringLen (castPtr p,len)
168
169instance Storable a => Binary (V.Vector a) where
170 put v = put $ vToSB v
171 get = do s <- get ; return $ sblToV [s]
172
173instance Binary MeshAttribute where
174 put (A_Float a) = putWord8 0 >> put a
175 put (A_V2F a) = putWord8 1 >> put a
176 put (A_V3F a) = putWord8 2 >> put a
177 put (A_V4F a) = putWord8 3 >> put a
178 put (A_M22F a) = putWord8 4 >> put a
179 put (A_M33F a) = putWord8 5 >> put a
180 put (A_M44F a) = putWord8 6 >> put a
181 put (A_Int a) = putWord8 7 >> put a
182 put (A_Word a) = putWord8 8 >> put a
183 get = do
184 tag_ <- getWord8
185 case tag_ of
186 0 -> A_Float <$> get
187 1 -> A_V2F <$> get
188 2 -> A_V3F <$> get
189 3 -> A_V4F <$> get
190 4 -> A_M22F <$> get
191 5 -> A_M33F <$> get
192 6 -> A_M44F <$> get
193 7 -> A_Int <$> get
194 8 -> A_Word <$> get
195 _ -> fail "no parse"
196
197instance Binary MeshPrimitive where
198 put P_Points = putWord8 0
199 put P_TriangleStrip = putWord8 1
200 put P_Triangles = putWord8 2
201 put (P_TriangleStripI a) = putWord8 3 >> put a
202 put (P_TrianglesI a) = putWord8 4 >> put a
203 get = do
204 tag_ <- getWord8
205 case tag_ of
206 0 -> return P_Points
207 1 -> return P_TriangleStrip
208 2 -> return P_Triangles
209 3 -> P_TriangleStripI <$> get
210 4 -> P_TrianglesI <$> get
211 _ -> fail "no parse"
212
213instance Binary Mesh where
214 put (Mesh a b _) = put (T.toList a) >> put b
215 get = do
216 a <- get
217 b <- get
218 return $! Mesh (T.fromList a) b Nothing