diff options
author | Joe Crayne <joe@jerkface.net> | 2019-07-28 00:16:13 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-07-28 00:17:11 -0400 |
commit | 5aba33b6f801910a8f5e1587c13678e237e31782 (patch) | |
tree | 67e71c9161dc23e1fe120e2e51074cd9f69b96f5 | |
parent | 175e4a0ee82e4db1fade4fbd8b5e55e88c21a826 (diff) |
Render curve from obj file.
-rw-r--r-- | Bezier.hs | 2 | ||||
-rw-r--r-- | LoadMesh.hs | 60 | ||||
-rw-r--r-- | MeshSketch.hs | 40 |
3 files changed, 89 insertions, 13 deletions
@@ -32,6 +32,8 @@ data Curve = Curve | |||
32 | , curveSegments :: Maybe Polygonization | 32 | , curveSegments :: Maybe Polygonization |
33 | } | 33 | } |
34 | 34 | ||
35 | -- Although this function accepts an index, 'subdivideCurve' increases the | ||
36 | -- index by one after each call, so it is safe to ignore the index passed. | ||
35 | type StorePoint m = BufferID -> Int -> Vector Float {- 3d -} -> m () | 37 | type StorePoint m = BufferID -> Int -> Vector Float {- 3d -} -> m () |
36 | 38 | ||
37 | xz :: Vector Float -> (Float,Float) | 39 | xz :: Vector Float -> (Float,Float) |
diff --git a/LoadMesh.hs b/LoadMesh.hs index aaf0e06..cd7a8ad 100644 --- a/LoadMesh.hs +++ b/LoadMesh.hs | |||
@@ -18,6 +18,7 @@ import Data.Maybe | |||
18 | import Data.Map (Map) | 18 | import Data.Map (Map) |
19 | import qualified Data.Map as Map | 19 | import qualified Data.Map as Map |
20 | import qualified Data.Vector as V | 20 | import qualified Data.Vector as V |
21 | import qualified Data.Vector.Storable as StorableV | ||
21 | import qualified Data.ByteString as SB | 22 | import qualified Data.ByteString as SB |
22 | import qualified Data.ByteString.Lazy.Char8 as L | 23 | import qualified Data.ByteString.Lazy.Char8 as L |
23 | import Data.Text (unpack,Text,pack) | 24 | import Data.Text (unpack,Text,pack) |
@@ -37,10 +38,19 @@ data MaterialMesh m = MaterialMesh | |||
37 | , materialMasks :: Map Text Mask | 38 | , materialMasks :: Map Text Mask |
38 | } | 39 | } |
39 | 40 | ||
40 | type MeshData = ( [MaterialMesh Mesh] -- List of uniform-material meshes (and the name of the material). | 41 | data CurveData = CurveData |
41 | , ( V.Vector MtlLib -- Material definitions. | 42 | { curves :: [Curve] |
42 | , FilePath ) -- Path to wavefront obj file. | 43 | , curvePt :: Int -> Location |
43 | ) | 44 | , curveMax :: Int |
45 | } | ||
46 | |||
47 | |||
48 | data MeshData = MeshData | ||
49 | { matMeshes :: [MaterialMesh Mesh] -- List of uniform-material meshes (and the name of the material). | ||
50 | , matLib :: ( V.Vector MtlLib -- Material definitions. | ||
51 | , FilePath ) -- Path to wavefront obj file. | ||
52 | , matCurves :: CurveData | ||
53 | } | ||
44 | 54 | ||
45 | relativeFrom :: FilePath -> FilePath -> FilePath | 55 | relativeFrom :: FilePath -> FilePath -> FilePath |
46 | relativeFrom path file | isAbsolute file = file | 56 | relativeFrom path file | isAbsolute file = file |
@@ -51,7 +61,12 @@ loadOBJ fname = L.readFile fname >>= \bs -> do | |||
51 | let obj@OBJ{..} = Wavefront.parse bs | 61 | let obj@OBJ{..} = Wavefront.parse bs |
52 | -- load materials | 62 | -- load materials |
53 | mtlLib <- mapM (readMtlWithFallback . relativeFrom fname . unpack) objMtlLibs | 63 | mtlLib <- mapM (readMtlWithFallback . relativeFrom fname . unpack) objMtlLibs |
54 | return $ Right (objToMesh obj,(mtlLib,fname)) | 64 | return $ Right MeshData |
65 | { matMeshes = objToMesh obj | ||
66 | , matLib = (mtlLib,fname) | ||
67 | , matCurves = objToCurveData obj | ||
68 | } | ||
69 | |||
55 | 70 | ||
56 | 71 | ||
57 | data BoundingBox = BoundingBox | 72 | data BoundingBox = BoundingBox |
@@ -122,22 +137,37 @@ transformMesh t m = m | |||
122 | { mAttributes = Map.adjust (tranformAttribute t) "position" (mAttributes m) | 137 | { mAttributes = Map.adjust (tranformAttribute t) "position" (mAttributes m) |
123 | } | 138 | } |
124 | 139 | ||
125 | uploadOBJToGPU :: Maybe BoundingBox -> MeshData -> IO ([MaterialMesh GPUMesh],Matrix Float) | 140 | transformLocation :: Matrix Float -> Location -> Location |
126 | uploadOBJToGPU scalebb (subModels,(mtlLib,objpath)) = do | 141 | transformLocation t (Location x y z w) = Location xx yy zz ww |
127 | let meshbb = foldMap (attribBoundingBox . mAttributes . materialMesh) subModels :: BoundingBox | 142 | where |
143 | [xx,yy,zz,ww] = toList $ t #> fromList [x,y,z,w] | ||
144 | |||
145 | locationBoundingBox :: Location -> BoundingBox | ||
146 | locationBoundingBox (Location x y z w) = BoundingBox x x y y z z | ||
147 | |||
148 | uploadOBJToGPU :: Maybe BoundingBox -> MeshData -> IO (([MaterialMesh GPUMesh],CurveData),Matrix Float) | ||
149 | uploadOBJToGPU scalebb (MeshData subModels (mtlLib,objpath) curveData) = do | ||
150 | let meshbb = foldMap (attribBoundingBox . mAttributes . materialMesh) subModels | ||
151 | <> foldMap (foldMap (locationBoundingBox . curvePt curveData) . curvePoints) | ||
152 | (curves curveData) | ||
128 | m = maybe (ident 4) (scaleWithin meshbb) scalebb | 153 | m = maybe (ident 4) (scaleWithin meshbb) scalebb |
154 | curveData' = case scalebb of | ||
155 | Just _ -> curveData { curvePt = transformLocation m . curvePt curveData } | ||
156 | Nothing -> curveData | ||
129 | putStrLn $ show meshbb | 157 | putStrLn $ show meshbb |
130 | gpuSubModels <- forM subModels $ \matmesh -> do | 158 | gpuSubModels <- forM subModels $ \matmesh -> do |
131 | a <- LambdaCubeGL.uploadMeshToGPU (transformMesh m (materialMesh matmesh)) | 159 | a <- LambdaCubeGL.uploadMeshToGPU (transformMesh m (materialMesh matmesh)) |
132 | return matmesh { materialMesh = a } | 160 | return matmesh { materialMesh = a } |
133 | return (gpuSubModels,m) | 161 | return ((gpuSubModels,curveData'),m) |
134 | 162 | ||
135 | uploadMtlLib :: (V.Vector MtlLib,FilePath) -> IO (V.Vector (Map Text (ObjMaterial,TextureData))) | 163 | uploadMtlLib :: (V.Vector MtlLib,FilePath) -> IO (V.Vector (Map Text (ObjMaterial,TextureData))) |
136 | uploadMtlLib (mtlLib,objpath) = do | 164 | uploadMtlLib (mtlLib,objpath) = do |
137 | -- collect used textures | 165 | -- collect used textures |
138 | let usedTextures = nub . concatMap (maybeToList . mtl_map_Kd) $ concatMap Map.elems $ V.toList mtlLib | 166 | let usedTextures = nub . concatMap (maybeToList . mtl_map_Kd) $ concatMap Map.elems $ V.toList mtlLib |
139 | whiteImage = Juicy.ImageRGB8 $ Juicy.generateImage (\_ _ -> Juicy.PixelRGB8 255 255 255) 1 1 | 167 | whiteImage = Juicy.ImageRGB8 $ Juicy.generateImage (\_ _ -> Juicy.PixelRGB8 255 255 255) 1 1 |
140 | checkerImage = Juicy.ImageRGB8 $ Juicy.generateImage (\x y -> if mod (x + y) 2 == 0 then Juicy.PixelRGB8 0 0 0 else Juicy.PixelRGB8 255 255 0) 2 2 | 168 | checkerImage = Juicy.ImageRGB8 $ Juicy.generateImage mkchecker 2 2 |
169 | where mkchecker x y = if mod (x + y) 2 == 0 then Juicy.PixelRGB8 0 0 0 | ||
170 | else Juicy.PixelRGB8 255 255 0 | ||
141 | checkerTex <- LC.uploadTexture2DToGPU checkerImage | 171 | checkerTex <- LC.uploadTexture2DToGPU checkerImage |
142 | -- load images and upload to gpu | 172 | -- load images and upload to gpu |
143 | textureLib <- forM (Map.fromList $ zip usedTextures usedTextures) $ \fname -> Juicy.readImage (relativeFrom objpath fname) >>= \case | 173 | textureLib <- forM (Map.fromList $ zip usedTextures usedTextures) $ \fname -> Juicy.readImage (relativeFrom objpath fname) >>= \case |
@@ -147,6 +177,16 @@ uploadMtlLib (mtlLib,objpath) = do | |||
147 | -- pair textures and materials | 177 | -- pair textures and materials |
148 | return $ fmap (\a -> (a, maybe whiteTex (fromMaybe checkerTex . flip Map.lookup textureLib) . mtl_map_Kd $ a)) <$> mtlLib | 178 | return $ fmap (\a -> (a, maybe whiteTex (fromMaybe checkerTex . flip Map.lookup textureLib) . mtl_map_Kd $ a)) <$> mtlLib |
149 | 179 | ||
180 | vecLocation :: Location -> StorableV.Vector Float | ||
181 | vecLocation (Location x y z w) = StorableV.fromList [x,y,z,w] | ||
182 | |||
183 | objToCurveData :: WavefrontOBJ -> CurveData | ||
184 | objToCurveData OBJ{..} = CurveData | ||
185 | { curves = map elValue $ V.toList $ objCurves | ||
186 | , curvePt = (objLocations V.!) | ||
187 | , curveMax = V.length objLocations | ||
188 | } | ||
189 | |||
150 | objToMesh :: WavefrontOBJ -> [MaterialMesh Mesh] | 190 | objToMesh :: WavefrontOBJ -> [MaterialMesh Mesh] |
151 | objToMesh OBJ{..} = [ toMesh faceGroup | faceGroup <- faces ] | 191 | objToMesh OBJ{..} = [ toMesh faceGroup | faceGroup <- faces ] |
152 | where | 192 | where |
diff --git a/MeshSketch.hs b/MeshSketch.hs index a51cd3d..a2e4cbe 100644 --- a/MeshSketch.hs +++ b/MeshSketch.hs | |||
@@ -54,6 +54,10 @@ import Text.Printf | |||
54 | import qualified Foreign.C.Types | 54 | import qualified Foreign.C.Types |
55 | import System.FilePath | 55 | import System.FilePath |
56 | import System.Directory | 56 | import System.Directory |
57 | import Wavefront.Types | ||
58 | import Wavefront.Util | ||
59 | |||
60 | |||
57 | 61 | ||
58 | import CubeMap | 62 | import CubeMap |
59 | import GLWidget (nullableContext, withCurrentGL) | 63 | import GLWidget (nullableContext, withCurrentGL) |
@@ -160,8 +164,8 @@ stateChangeMesh obj mm storage st = do | |||
160 | let glarea = mmWidget mm | 164 | let glarea = mmWidget mm |
161 | -- load OBJ geometry and material descriptions | 165 | -- load OBJ geometry and material descriptions |
162 | let workarea = BoundingBox (-2.5) (2.5) (-2.5) 2.5 (-2.5) (2.5) | 166 | let workarea = BoundingBox (-2.5) (2.5) (-2.5) 2.5 (-2.5) (2.5) |
163 | mtlLib = snd obj | 167 | mtlLib = matLib obj |
164 | (objMesh,objscale) <- uploadOBJToGPU (Just workarea) obj | 168 | ((objMesh,curveData),objscale) <- uploadOBJToGPU (Just workarea) obj |
165 | putStrLn $ "Using object scale:\n" ++ show objscale | 169 | putStrLn $ "Using object scale:\n" ++ show objscale |
166 | -- load materials textures | 170 | -- load materials textures |
167 | gpuMtlLib <- uploadMtlLib mtlLib | 171 | gpuMtlLib <- uploadMtlLib mtlLib |
@@ -172,6 +176,36 @@ stateChangeMesh obj mm storage st = do | |||
172 | addToGroupsPane (mmListStore mm) True groupname | 176 | addToGroupsPane (mmListStore mm) True groupname |
173 | writeIORef (stObjects st) bufs | 177 | writeIORef (stObjects st) bufs |
174 | writeIORef (stMasks st) $ map (objSpan . maskableObject) bufs | 178 | writeIORef (stMasks st) $ map (objSpan . maskableObject) bufs |
179 | forM_ (take 1 $ curves curveData) $ \c -> do | ||
180 | let mn = minimum $ curvePoints c | ||
181 | mx = maximum $ curvePoints c | ||
182 | bs = decomposeCurve (curvePt curveData) c | ||
183 | mapM_ (putStrLn . show) bs | ||
184 | clearRing (stRingBuffer st) | ||
185 | forM_ bs $ \(BezierSegment [a,b,c,d]) -> do | ||
186 | let cv = Bezier.Curve Nothing (vecLocation a) | ||
187 | (vecLocation b) | ||
188 | (vecLocation c) | ||
189 | (vecLocation d) | ||
190 | Nothing | ||
191 | δ = 0.005 -- TODO | ||
192 | range = Polygonization | ||
193 | { curveBufferID = error "curveBufferID" | ||
194 | , curveStartIndex = 0 | ||
195 | , curveSegmentCount = ringCapacity (stRingBuffer st) | ||
196 | } | ||
197 | r <- subdivideCurve δ cv range $ \_ _ v -> do | ||
198 | RingBuffer.pushBack (stRingBuffer st) $ \RingPoint{..} -> do | ||
199 | rpPosition @<- v | ||
200 | rpColor @<- yellow | ||
201 | putStrLn $ "Subdivided "++show (curveSegmentCount r)++" poly-lines." | ||
202 | return () | ||
203 | {- | ||
204 | RingBuffer.pushBack (stRingBuffer st) $ \RingPoint{..} -> do | ||
205 | rpPosition @<- V3 0 0 (0::Float) | ||
206 | rpColor @<- red -} | ||
207 | return () | ||
208 | putStrLn $ "Returning from stateChangeMesh." | ||
175 | return st | 209 | return st |
176 | 210 | ||
177 | initializeState :: MeshSketch -> GLStorage -> IO State | 211 | initializeState :: MeshSketch -> GLStorage -> IO State |
@@ -321,7 +355,7 @@ loadInitialMesh kont = do | |||
321 | objName <- head . (++ ["cube.obj"]) <$> getArgs | 355 | objName <- head . (++ ["cube.obj"]) <$> getArgs |
322 | putStrLn $ "Loading object "++objName++"..." | 356 | putStrLn $ "Loading object "++objName++"..." |
323 | mobj <- loadOBJ objName | 357 | mobj <- loadOBJ objName |
324 | putStrLn $ "Finisehd loading object "++objName++"." | 358 | putStrLn $ "Finished loading object "++objName++"." |
325 | kont mobj | 359 | kont mobj |
326 | 360 | ||
327 | new :: IO Gtk.Paned | 361 | new :: IO Gtk.Paned |