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 /main.hs | |
parent | 3899b660b11bf1d3179965ac92a039b8d449306f (diff) |
Refactored spinning-logo demo.
Diffstat (limited to 'main.hs')
-rw-r--r-- | main.hs | 92 |
1 files changed, 92 insertions, 0 deletions
@@ -0,0 +1,92 @@ | |||
1 | {-# LANGUAGE OverloadedLabels #-} | ||
2 | {-# LANGUAGE OverloadedStrings #-} | ||
3 | {-# LANGUAGE LambdaCase #-} | ||
4 | module Main where | ||
5 | |||
6 | import Codec.Picture as Juicy | ||
7 | import Control.Concurrent | ||
8 | import Data.Word | ||
9 | import Data.Function | ||
10 | import qualified Data.Map.Strict as Map | ||
11 | import qualified Data.Vector as V | ||
12 | import GI.Gdk.Objects | ||
13 | import GI.GLib.Constants | ||
14 | import GI.Gtk as Gtk hiding (main) | ||
15 | import LambdaCube.GL as LC | ||
16 | import LambdaCube.GL.Mesh as LC | ||
17 | import System.IO | ||
18 | import System.IO.Error | ||
19 | |||
20 | import GLWidget | ||
21 | import LambdaCubeWidget | ||
22 | import TimeKeeper | ||
23 | |||
24 | type State = (TextureData, TimeKeeper, TickCallbackHandle) | ||
25 | |||
26 | uploadState :: IsWidget glarea => DynamicImage -> glarea -> GLStorage -> IO State | ||
27 | uploadState img glarea storage = do | ||
28 | -- upload geometry to GPU and add to pipeline input | ||
29 | LC.uploadMeshToGPU triangleA >>= LC.addMeshToObjectArray storage "objects" [] | ||
30 | LC.uploadMeshToGPU triangleB >>= LC.addMeshToObjectArray storage "objects" [] | ||
31 | -- load image and upload texture | ||
32 | texture <- LC.uploadTexture2DToGPU img | ||
33 | -- setup FrameClock | ||
34 | tm <- newTimeKeeper | ||
35 | tickcb <- widgetAddTickCallback glarea (tick tm) | ||
36 | return (texture,tm,tickcb) | ||
37 | |||
38 | destroyState :: GLArea -> State -> IO () | ||
39 | destroyState glarea (texture,tm,tickcb) = do | ||
40 | widgetRemoveTickCallback glarea tickcb | ||
41 | |||
42 | setUniforms :: glctx -> GLStorage -> State -> IO () | ||
43 | setUniforms gl storage (texture,tm,_) = do | ||
44 | t <- withMVar (tmSeconds tm) return | ||
45 | LC.updateUniforms storage $ do | ||
46 | "diffuseTexture" @= return texture | ||
47 | "time" @= return (realToFrac t :: Float) | ||
48 | |||
49 | main :: IO () | ||
50 | main = do | ||
51 | m <- do | ||
52 | mimg <- Juicy.readImage "logo.png" `catchIOError` \e -> return $ Left (show e) | ||
53 | mpipeline <- loadPipeline "hello.json" $ do | ||
54 | defObjectArray "objects" Triangles $ do | ||
55 | "position" @: Attribute_V2F | ||
56 | "uv" @: Attribute_V2F | ||
57 | defUniforms $ do | ||
58 | "time" @: Float | ||
59 | "diffuseTexture" @: FTexture2D | ||
60 | return $ (,) <$> mimg <*> mpipeline | ||
61 | either (\e _ -> hPutStrLn stderr e) (&) m $ \(logo,pipeline) -> do | ||
62 | app <- do | ||
63 | mvar <- newEmptyMVar | ||
64 | return $ \glarea -> LCMethods | ||
65 | { lcRealized = mvar | ||
66 | , lcUploadState = uploadState logo glarea | ||
67 | , lcDestroyState = destroyState glarea | ||
68 | , lcSetUniforms = setUniforms | ||
69 | , lcPipeline = pipeline | ||
70 | } | ||
71 | |||
72 | runGLApp return (lambdaRender app glmethods) | ||
73 | |||
74 | -- geometry data: triangles | ||
75 | triangleA :: LC.Mesh | ||
76 | triangleA = Mesh | ||
77 | { mAttributes = Map.fromList | ||
78 | [ ("position", A_V2F $ V.fromList [V2 1 1, V2 1 (-1), V2 (-1) (-1)]) | ||
79 | , ("uv", A_V2F $ V.fromList [V2 1 1, V2 0 1, V2 0 0]) | ||
80 | ] | ||
81 | , mPrimitive = P_Triangles | ||
82 | } | ||
83 | |||
84 | triangleB :: LC.Mesh | ||
85 | triangleB = Mesh | ||
86 | { mAttributes = Map.fromList | ||
87 | [ ("position", A_V2F $ V.fromList [V2 1 1, V2 (-1) (-1), V2 (-1) 1]) | ||
88 | , ("uv", A_V2F $ V.fromList [V2 1 1, V2 0 0, V2 1 0]) | ||
89 | ] | ||
90 | , mPrimitive = P_Triangles | ||
91 | } | ||
92 | |||