summaryrefslogtreecommitdiff
path: root/LambdaCubeWidget.hs
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-04-17 14:18:12 -0400
committerJoe Crayne <joe@jerkface.net>2019-04-17 18:36:53 -0400
commit64f1a100fc887fb2a8bc87e2ac6975e872010ef5 (patch)
tree71e96856bf8a0ebcd14f7ab87124184cb15d868b /LambdaCubeWidget.hs
parent3899b660b11bf1d3179965ac92a039b8d449306f (diff)
Refactored spinning-logo demo.
Diffstat (limited to 'LambdaCubeWidget.hs')
-rw-r--r--LambdaCubeWidget.hs98
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 #-}
2module LambdaCubeWidget where
3
4import Control.Monad
5import Control.Concurrent
6import Data.Function
7import Data.Int
8import GI.Gdk.Objects
9import GI.Gtk.Objects (GLArea,widgetGetWindow)
10import GLWidget
11import LambdaCube.GL as LC
12import LambdaCube.IR as LC
13import LambdaCube.Gtk
14import qualified Data.Aeson as JSON
15import qualified Data.ByteString as SB
16import System.IO.Error
17import Control.Monad.Writer
18
19data LCRealized x = LCRealized GLStorage GLRenderer x
20
21data 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
29data DynamicPipeline = DynamicPipeline
30 { dynamicPipeline :: Pipeline
31 , dynamicSchema :: PipelineSchema
32 }
33
34loadPipeline :: FilePath -> Writer PipelineSchema a -> IO (Either String DynamicPipeline)
35loadPipeline 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
46lambdaRender :: (GLArea -> LCMethods x) -> WidgetMethods GLArea -> WidgetMethods GLArea
47lambdaRender f m = m
48 { glRender = lcrender . f
49 , glUnrealize = lcunrealize . f
50 , glRealize = lcrealize . f
51 , glResize = \glarea -> lcresize glarea (f glarea)
52 }
53
54tryWithMVar :: IO b -> MVar a -> (a -> IO b) -> IO b
55tryWithMVar failed mvar f = do
56 mr <- tryTakeMVar mvar
57 maybe failed f mr
58
59lcrender :: LCMethods x -> GLContext -> IO Bool
60lcrender 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
70lcunrealize :: LCMethods x -> IO ()
71lcunrealize lc = do
72 m <- tryTakeMVar $ lcRealized lc
73 mapM_ (\(LCRealized _ _ x) -> lcDestroyState lc x) m
74
75lcrealize :: LCMethods x -> IO ()
76lcrealize 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
84lcresize :: GLArea -> LCMethods x -> Int32 -> Int32 -> IO ()
85lcresize 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