diff options
author | Joe Crayne <joe@jerkface.net> | 2019-04-17 14:18:12 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-04-17 18:36:53 -0400 |
commit | 64f1a100fc887fb2a8bc87e2ac6975e872010ef5 (patch) | |
tree | 71e96856bf8a0ebcd14f7ab87124184cb15d868b /LambdaCubeWidget.hs | |
parent | 3899b660b11bf1d3179965ac92a039b8d449306f (diff) |
Refactored spinning-logo demo.
Diffstat (limited to 'LambdaCubeWidget.hs')
-rw-r--r-- | LambdaCubeWidget.hs | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/LambdaCubeWidget.hs b/LambdaCubeWidget.hs new file mode 100644 index 0000000..17bb361 --- /dev/null +++ b/LambdaCubeWidget.hs | |||
@@ -0,0 +1,98 @@ | |||
1 | {-# LANGUAGE LambdaCase #-} | ||
2 | module LambdaCubeWidget where | ||
3 | |||
4 | import Control.Monad | ||
5 | import Control.Concurrent | ||
6 | import Data.Function | ||
7 | import Data.Int | ||
8 | import GI.Gdk.Objects | ||
9 | import GI.Gtk.Objects (GLArea,widgetGetWindow) | ||
10 | import GLWidget | ||
11 | import LambdaCube.GL as LC | ||
12 | import LambdaCube.IR as LC | ||
13 | import LambdaCube.Gtk | ||
14 | import qualified Data.Aeson as JSON | ||
15 | import qualified Data.ByteString as SB | ||
16 | import System.IO.Error | ||
17 | import Control.Monad.Writer | ||
18 | |||
19 | data LCRealized x = LCRealized GLStorage GLRenderer x | ||
20 | |||
21 | data LCMethods x = LCMethods | ||
22 | { lcRealized :: MVar (LCRealized x) | ||
23 | , lcUploadState :: GLStorage -> IO x -- implements realize | ||
24 | , lcDestroyState :: x -> IO () | ||
25 | , lcSetUniforms :: GLContext -> GLStorage -> x -> IO () -- implements render | ||
26 | , lcPipeline :: DynamicPipeline | ||
27 | } | ||
28 | |||
29 | data DynamicPipeline = DynamicPipeline | ||
30 | { dynamicPipeline :: Pipeline | ||
31 | , dynamicSchema :: PipelineSchema | ||
32 | } | ||
33 | |||
34 | loadPipeline :: FilePath -> Writer PipelineSchema a -> IO (Either String DynamicPipeline) | ||
35 | loadPipeline fname schema = do | ||
36 | pipelineDesc <- do | ||
37 | maybe (Left $ "Unable to parse " ++ fname) Right . JSON.decodeStrict <$> SB.readFile fname | ||
38 | `catchIOError` \e -> return $ Left (show e) | ||
39 | return $ do | ||
40 | p <- pipelineDesc | ||
41 | Right DynamicPipeline | ||
42 | { dynamicPipeline = p | ||
43 | , dynamicSchema = makeSchema schema | ||
44 | } | ||
45 | |||
46 | lambdaRender :: (GLArea -> LCMethods x) -> WidgetMethods GLArea -> WidgetMethods GLArea | ||
47 | lambdaRender f m = m | ||
48 | { glRender = lcrender . f | ||
49 | , glUnrealize = lcunrealize . f | ||
50 | , glRealize = lcrealize . f | ||
51 | , glResize = \glarea -> lcresize glarea (f glarea) | ||
52 | } | ||
53 | |||
54 | tryWithMVar :: IO b -> MVar a -> (a -> IO b) -> IO b | ||
55 | tryWithMVar failed mvar f = do | ||
56 | mr <- tryTakeMVar mvar | ||
57 | maybe failed f mr | ||
58 | |||
59 | lcrender :: LCMethods x -> GLContext -> IO Bool | ||
60 | lcrender lc gl = do | ||
61 | mr <- tryTakeMVar (lcRealized lc) | ||
62 | maybe (\_ -> oops "Not realized!") (&) mr $ \realized-> do | ||
63 | let LCRealized s r0 x = realized | ||
64 | r <- fixupRenderTarget r0 | ||
65 | lcSetUniforms lc gl s x | ||
66 | LC.renderFrame r | ||
67 | putMVar (lcRealized lc) realized | ||
68 | return True | ||
69 | |||
70 | lcunrealize :: LCMethods x -> IO () | ||
71 | lcunrealize lc = do | ||
72 | m <- tryTakeMVar $ lcRealized lc | ||
73 | mapM_ (\(LCRealized _ _ x) -> lcDestroyState lc x) m | ||
74 | |||
75 | lcrealize :: LCMethods x -> IO () | ||
76 | lcrealize lc = do | ||
77 | _ <- tryTakeMVar (lcRealized lc) | ||
78 | storage <- LC.allocStorage (dynamicSchema $ lcPipeline lc) | ||
79 | x <- lcUploadState lc storage | ||
80 | renderer <- LC.allocRenderer (dynamicPipeline $ lcPipeline lc) | ||
81 | compat <- LC.setStorage renderer storage -- check schema compatibility | ||
82 | putMVar (lcRealized lc) $ LCRealized storage renderer x | ||
83 | |||
84 | lcresize :: GLArea -> LCMethods x -> Int32 -> Int32 -> IO () | ||
85 | lcresize glarea lc w h = do | ||
86 | tryTakeMVar (lcRealized lc) >>= \case | ||
87 | Nothing -> return () | ||
88 | Just r@(LCRealized storage _ _) -> do | ||
89 | -- Plenty of options here. I went with the last one. | ||
90 | -- 1. gLContextGetWindow :: HasCallStack => GLContext -> IO (Maybe Window) | ||
91 | -- 2. getGLContextWindow :: GLContext -> IO (Maybe Window) | ||
92 | -- 3. widgetGetWindow :: HasCallStack => GLArea -> IO (Maybe Window) | ||
93 | widgetGetWindow glarea >>= mapM_ (\win -> do | ||
94 | (wd,ht) <- do wd <- windowGetWidth win | ||
95 | ht <- windowGetHeight win | ||
96 | return (fromIntegral wd,fromIntegral ht) | ||
97 | LC.setScreenSize storage wd ht) | ||
98 | putMVar (lcRealized lc) r | ||