diff options
author | Joe Crayne <joe@jerkface.net> | 2019-06-19 02:28:58 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-06-19 02:28:58 -0400 |
commit | 5024860293943ad598d4d89331bdc1615a862d25 (patch) | |
tree | def28134dd1b9e20d2189d6a6f71067d43df9bbc | |
parent | 4e615656484dfe4347b0a2ccbdf38c2e609162df (diff) |
Load mesh in background.
-rw-r--r-- | GPURing.hs | 3 | ||||
-rw-r--r-- | MeshSketch.hs | 79 | ||||
-rw-r--r-- | lambda-gtk.cabal | 1 |
3 files changed, 58 insertions, 25 deletions
@@ -20,9 +20,6 @@ import LambdaCube.GL.Input.Type | |||
20 | import LambdaCube.GL.Input hiding (createObjectCommands) | 20 | import LambdaCube.GL.Input hiding (createObjectCommands) |
21 | 21 | ||
22 | 22 | ||
23 | -- | Typical usage: | ||
24 | -- | ||
25 | -- > ringBuffer <- newRing capacity (VectorRing.new capacity) | ||
26 | type Update keys = (keys -> Writer [DSum AttributeKey GLUniformValue] ()) | 23 | type Update keys = (keys -> Writer [DSum AttributeKey GLUniformValue] ()) |
27 | 24 | ||
28 | new :: Data keys => Primitive -> String -> GLStorage -> (String -> String) -> Int -> IO (TargetBuffer (Update keys)) | 25 | new :: Data keys => Primitive -> String -> GLStorage -> (String -> String) -> Int -> IO (TargetBuffer (Update keys)) |
diff --git a/MeshSketch.hs b/MeshSketch.hs index 8c18b67..87d9763 100644 --- a/MeshSketch.hs +++ b/MeshSketch.hs | |||
@@ -176,8 +176,8 @@ xzPlaneVector :: Vector Float | |||
176 | xzPlaneVector = fromList [ 0,1,0 -- unit normal | 176 | xzPlaneVector = fromList [ 0,1,0 -- unit normal |
177 | , 0 ] -- distance from origin | 177 | , 0 ] -- distance from origin |
178 | 178 | ||
179 | uploadState :: MeshData -> MeshSketch -> GLStorage -> IO State | 179 | stateChangeMesh :: MeshData -> MeshSketch -> GLStorage -> State -> IO State |
180 | uploadState obj mm storage = do | 180 | stateChangeMesh obj mm storage st = do |
181 | let glarea = mmWidget mm | 181 | let glarea = mmWidget mm |
182 | -- load OBJ geometry and material descriptions | 182 | -- load OBJ geometry and material descriptions |
183 | let workarea = BoundingBox (-2.5) (2.5) (-2.5) 2.5 (-2.5) (2.5) | 183 | let workarea = BoundingBox (-2.5) (2.5) (-2.5) 2.5 (-2.5) (2.5) |
@@ -191,23 +191,26 @@ uploadState obj mm storage = do | |||
191 | let gs = Map.keys $ foldr (\a ms -> Map.union (groupMasks a) ms) Map.empty bufs | 191 | let gs = Map.keys $ foldr (\a ms -> Map.union (groupMasks a) ms) Map.empty bufs |
192 | forM_ gs $ \groupname -> do | 192 | forM_ gs $ \groupname -> do |
193 | addToGroupsPane (mmListStore mm) True groupname | 193 | addToGroupsPane (mmListStore mm) True groupname |
194 | objsRef <- newIORef bufs | 194 | writeIORef (stObjects st) bufs |
195 | masksRef <- newIORef $ map (objSpan . maskableObject) bufs | 195 | writeIORef (stMasks st) $ map (objSpan . maskableObject) bufs |
196 | return st | ||
196 | 197 | ||
198 | initializeState :: MeshSketch -> GLStorage -> IO State | ||
199 | initializeState mm storage = do | ||
200 | let glarea = mmWidget mm | ||
201 | objsRef <- newIORef [] | ||
202 | masksRef <- newIORef [] | ||
197 | -- grid plane | 203 | -- grid plane |
198 | uploadMeshToGPU xzplane >>= addMeshToObjectArray storage "plane" [] | 204 | uploadMeshToGPU xzplane >>= addMeshToObjectArray storage "plane" [] |
199 | |||
200 | let bufsize = 1000 | 205 | let bufsize = 1000 |
201 | v <- MV.unsafeNew bufsize | 206 | v <- MV.unsafeNew bufsize |
202 | pts <- newRing bufsize (Vector.new v) | 207 | pts <- newRing bufsize (Vector.new v) |
203 | ring <- newRing bufsize (GPU.new LineStrip "Curve" storage ringPointAttr bufsize) | 208 | ring <- newRing bufsize (GPU.new LineStrip "Curve" storage ringPointAttr bufsize) |
204 | cpts <- newRing 100 (GPU.new PointList "Points" storage ringPointAttr 100) | 209 | cpts <- newRing 100 (GPU.new PointList "Points" storage ringPointAttr 100) |
205 | |||
206 | -- setup FrameClock | 210 | -- setup FrameClock |
207 | w <- toWidget glarea | 211 | w <- toWidget glarea |
208 | tm <- newAnimator w | 212 | tm <- newAnimator w |
209 | cam <- newIORef initCamera | 213 | cam <- newIORef initCamera |
210 | |||
211 | Just pwidget <- get w #parent | 214 | Just pwidget <- get w #parent |
212 | Just parent <- get pwidget #window | 215 | Just parent <- get pwidget #window |
213 | toggle <- mkFullscreenToggle parent | 216 | toggle <- mkFullscreenToggle parent |
@@ -225,14 +228,12 @@ uploadState obj mm storage = do | |||
225 | skytex <- newIORef skybox_id | 228 | skytex <- newIORef skybox_id |
226 | mi <- LC.uploadMeshToGPU cubeMesh | 229 | mi <- LC.uploadMeshToGPU cubeMesh |
227 | LC.addMeshToObjectArray storage "SkyCube" [] mi | 230 | LC.addMeshToObjectArray storage "SkyCube" [] mi |
228 | |||
229 | drag <- newIORef Nothing | 231 | drag <- newIORef Nothing |
230 | dragPlane <- newIORef Nothing | 232 | dragPlane <- newIORef Nothing |
231 | pendown <- newIORef False | 233 | pendown <- newIORef False |
232 | plane <- newIORef $ Just (xzPlaneVector G.// [(3,-1)]) | 234 | plane <- newIORef $ Just (xzPlaneVector G.// [(3,-1)]) |
233 | recentPts <- newIORef Give0 | 235 | recentPts <- newIORef Give0 |
234 | angle <- newIORef 0 | 236 | angle <- newIORef 0 |
235 | |||
236 | let st = State | 237 | let st = State |
237 | { stAnimator = tm | 238 | { stAnimator = tm |
238 | , stCamera = cam | 239 | , stCamera = cam |
@@ -254,10 +255,8 @@ uploadState obj mm storage = do | |||
254 | , stMasks = masksRef | 255 | , stMasks = masksRef |
255 | } | 256 | } |
256 | -- _ <- addAnimation tm (whirlingCamera st) | 257 | -- _ <- addAnimation tm (whirlingCamera st) |
257 | |||
258 | return st | 258 | return st |
259 | 259 | ||
260 | |||
261 | destroyState :: GLArea -> State -> IO () | 260 | destroyState :: GLArea -> State -> IO () |
262 | destroyState glarea st = do | 261 | destroyState glarea st = do |
263 | -- widgetRemoveTickCallback glarea (stTickCallback st) | 262 | -- widgetRemoveTickCallback glarea (stTickCallback st) |
@@ -313,6 +312,21 @@ data Realized = Realized | |||
313 | , stSigs :: [SignalHandlerId] -- Signals attached by onRealize. | 312 | , stSigs :: [SignalHandlerId] -- Signals attached by onRealize. |
314 | } | 313 | } |
315 | 314 | ||
315 | -- | Assumes the executable is nested somewhere in the source tree like so: | ||
316 | -- | ||
317 | -- <src-tree>/<dist>/build/.../<executable> | ||
318 | -- | ||
319 | -- If a "build" directory was not found, an empty string is returned. | ||
320 | findSrcTree :: IO FilePath | ||
321 | findSrcTree = do | ||
322 | exe <- getExecutablePath | ||
323 | let ps = reverse . drop 2 | ||
324 | . dropWhile (/="build") | ||
325 | . reverse | ||
326 | . splitDirectories | ||
327 | . takeDirectory $ exe | ||
328 | return $ foldr (</>) "" ps | ||
329 | |||
316 | findModule :: FilePath -> IO FilePath | 330 | findModule :: FilePath -> IO FilePath |
317 | findModule fn = do | 331 | findModule fn = do |
318 | let checkPath action next = do | 332 | let checkPath action next = do |
@@ -321,16 +335,19 @@ findModule fn = do | |||
321 | found <- doesFileExist f | 335 | found <- doesFileExist f |
322 | if found then return f | 336 | if found then return f |
323 | else next | 337 | else next |
324 | foldr checkPath (return fn) [getExecutablePath,getCurrentDirectory] | 338 | foldr checkPath (return fn) [getExecutablePath,findSrcTree,getCurrentDirectory] |
339 | |||
340 | loadInitialMesh kont = do | ||
341 | objName <- head . (++ ["cube.obj"]) <$> getArgs | ||
342 | putStrLn $ "Loading object "++objName++"..." | ||
343 | mobj <- loadOBJ objName | ||
344 | putStrLn $ "Finisehd loading object "++objName++"." | ||
345 | kont mobj | ||
325 | 346 | ||
326 | new :: IO Gtk.Paned | 347 | new :: IO Gtk.Paned |
327 | new = do | 348 | new = do |
328 | putStrLn "new!" | 349 | putStrLn "new!" |
329 | m <- do | 350 | m <- do |
330 | objName <- head . (++ ["cube.obj"]) <$> getArgs | ||
331 | putStrLn $ "Loading object "++objName++"..." | ||
332 | mobj <- loadOBJ objName | ||
333 | putStrLn $ "Finisehd loading object "++objName++"." | ||
334 | -- mpipeline <- (\s -> return (Right (DynamicPipeline savedPipeline (makeSchema s)))) $ do | 351 | -- mpipeline <- (\s -> return (Right (DynamicPipeline savedPipeline (makeSchema s)))) $ do |
335 | ppath <- findModule "hello_obj2.json" | 352 | ppath <- findModule "hello_obj2.json" |
336 | mpipeline <- loadPipeline ppath $ do | 353 | mpipeline <- loadPipeline ppath $ do |
@@ -358,8 +375,8 @@ new = do | |||
358 | "PointsStart" @: Int | 375 | "PointsStart" @: Int |
359 | "diffuseTexture" @: FTexture2D | 376 | "diffuseTexture" @: FTexture2D |
360 | "diffuseColor" @: V4F | 377 | "diffuseColor" @: V4F |
361 | return $ (,) <$> mobj <*> mpipeline | 378 | return mpipeline |
362 | either (\e _ -> hPutStrLn stderr e >> throwIO (userError e)) (&) m $ \(obj,pipeline) -> do | 379 | either (\e _ -> hPutStrLn stderr e >> throwIO (userError e)) (&) m $ \pipeline -> do |
363 | mapM_ (putStrLn . ppShow) (targets $ dynamicPipeline pipeline) | 380 | mapM_ (putStrLn . ppShow) (targets $ dynamicPipeline pipeline) |
364 | ref <- newIORef Nothing | 381 | ref <- newIORef Nothing |
365 | g <- gLAreaNew | 382 | g <- gLAreaNew |
@@ -368,7 +385,7 @@ new = do | |||
368 | let mm = MeshSketch g panes groups liststore ref | 385 | let mm = MeshSketch g panes groups liststore ref |
369 | gLAreaSetHasDepthBuffer g True | 386 | gLAreaSetHasDepthBuffer g True |
370 | st <- return g | 387 | st <- return g |
371 | _ <- on g #realize $ withCurrentGL g (onRealize obj (dynamicPipeline pipeline) (dynamicSchema pipeline) mm) | 388 | _ <- on g #realize $ withCurrentGL g (onRealize (dynamicPipeline pipeline) (dynamicSchema pipeline) mm) |
372 | _ <- on g #unrealize $ onUnrealize mm | 389 | _ <- on g #unrealize $ onUnrealize mm |
373 | _ <- on g #createContext $ nullableContext (onCreateContext g) | 390 | _ <- on g #createContext $ nullableContext (onCreateContext g) |
374 | panedPack1 panes g True True | 391 | panedPack1 panes g True True |
@@ -441,8 +458,22 @@ onUnrealize mm = do | |||
441 | -- lcDestroyState lc x | 458 | -- lcDestroyState lc x |
442 | writeIORef (mmRealized mm) Nothing | 459 | writeIORef (mmRealized mm) Nothing |
443 | 460 | ||
444 | onRealize :: MeshData -> Pipeline -> PipelineSchema -> MeshSketch -> IO () | 461 | onLoadedMesh :: MeshSketch -> Either String MeshData -> IO Bool |
445 | onRealize mesh pipeline schema mm = do | 462 | onLoadedMesh mm mmesh = do |
463 | case mmesh of | ||
464 | Left e -> putStrLn e | ||
465 | Right mesh -> do | ||
466 | mr <- readIORef (mmRealized mm) | ||
467 | forM_ mr $ \r -> do | ||
468 | x <- stateChangeMesh mesh mm (stStorage r) (stState r) | ||
469 | writeIORef (mmRealized mm) $ Just r { stState = x } | ||
470 | mwin <- widgetGetWindow (mmWidget mm) | ||
471 | forM_ mwin $ \win -> | ||
472 | windowInvalidateRect win Nothing False | ||
473 | return False | ||
474 | |||
475 | onRealize :: Pipeline -> PipelineSchema -> MeshSketch -> IO () | ||
476 | onRealize pipeline schema mm = do | ||
446 | putStrLn "onRealize!" | 477 | putStrLn "onRealize!" |
447 | onUnrealize mm | 478 | onUnrealize mm |
448 | setupGLDebugging | 479 | setupGLDebugging |
@@ -452,7 +483,7 @@ onRealize mesh pipeline schema mm = do | |||
452 | renderer <- LC.allocRenderer pipeline | 483 | renderer <- LC.allocRenderer pipeline |
453 | compat <- LC.setStorage renderer storage -- check schema compatibility | 484 | compat <- LC.setStorage renderer storage -- check schema compatibility |
454 | -- putStrLn $ "setStorage compat = " ++ show compat | 485 | -- putStrLn $ "setStorage compat = " ++ show compat |
455 | x <- uploadState mesh mm storage | 486 | x <- initializeState mm storage |
456 | let r = Realized | 487 | let r = Realized |
457 | { stStorage = storage | 488 | { stStorage = storage |
458 | , stRenderer = renderer | 489 | , stRenderer = renderer |
@@ -484,6 +515,10 @@ onRealize mesh pipeline schema mm = do | |||
484 | panedSetPosition (mmPaned mm) (panedW * 8 `div` 10) | 515 | panedSetPosition (mmPaned mm) (panedW * 8 `div` 10) |
485 | -- widgetQueueAllocate (mmPaned mm) | 516 | -- widgetQueueAllocate (mmPaned mm) |
486 | writeIORef (mmRealized mm) $ Just r { stSigs = [sige,sigr,sigs] } | 517 | writeIORef (mmRealized mm) $ Just r { stSigs = [sige,sigr,sigs] } |
518 | forkOS $ loadInitialMesh $ \mmesh -> do | ||
519 | sid <- threadsAddIdle PRIORITY_DEFAULT_IDLE $ onLoadedMesh mm mmesh | ||
520 | return () | ||
521 | return () | ||
487 | 522 | ||
488 | onRender :: w -> Realized -> GLContext -> IO Bool | 523 | onRender :: w -> Realized -> GLContext -> IO Bool |
489 | onRender w realized gl = do | 524 | onRender w realized gl = do |
diff --git a/lambda-gtk.cabal b/lambda-gtk.cabal index 24340d8..02dbc85 100644 --- a/lambda-gtk.cabal +++ b/lambda-gtk.cabal | |||
@@ -66,3 +66,4 @@ executable meshsketch | |||
66 | gi-gdk , gi-glib , gi-gobject , gi-gtk , haskell-gi-base | 66 | gi-gdk , gi-glib , gi-gobject , gi-gtk , haskell-gi-base |
67 | 67 | ||
68 | default-language: Haskell2010 | 68 | default-language: Haskell2010 |
69 | ghc-options: -threaded | ||