diff options
author | Joe Crayne <joe@jerkface.net> | 2019-04-07 02:53:16 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-04-07 02:53:16 -0400 |
commit | 483ffac7da055342598b44800e69ee5217cb47cd (patch) | |
tree | f2c5780ea4bbcbfd443a3c77cd789d34905e2d90 |
initial commit
-rw-r--r-- | GtkHello.hs | 46 | ||||
-rw-r--r-- | Hello-glfw.hs | 101 | ||||
-rw-r--r-- | Hello-glut.hs | 129 | ||||
-rw-r--r-- | Tut.hs | 32 | ||||
-rw-r--r-- | hello.json | 1 | ||||
-rw-r--r-- | hello.lc | 16 |
6 files changed, 325 insertions, 0 deletions
diff --git a/GtkHello.hs b/GtkHello.hs new file mode 100644 index 0000000..9b29ba7 --- /dev/null +++ b/GtkHello.hs | |||
@@ -0,0 +1,46 @@ | |||
1 | {-# LANGUAGE OverloadedLabels #-} | ||
2 | {-# LANGUAGE OverloadedLists #-} | ||
3 | {-# LANGUAGE OverloadedStrings #-} | ||
4 | module Main where | ||
5 | |||
6 | import qualified GI.Gtk as Gtk | ||
7 | import GI.Gtk.Declarative | ||
8 | import GI.Gtk.Declarative.App.Simple | ||
9 | |||
10 | import qualified Data.Map as Map | ||
11 | import qualified Data.Vector as V | ||
12 | |||
13 | import LambdaCube.GL as LambdaCubeGL -- renderer | ||
14 | import LambdaCube.GL.Mesh as LambdaCubeGL | ||
15 | |||
16 | import Codec.Picture as Juicy | ||
17 | |||
18 | import Data.Aeson | ||
19 | import qualified Data.ByteString as SB | ||
20 | |||
21 | type State = () | ||
22 | |||
23 | data Event = Closed | ||
24 | |||
25 | view' :: State -> AppView Gtk.Window Event | ||
26 | view' _ = bin | ||
27 | Gtk.Window | ||
28 | [ #title := "LambdaCube 3D DSL Hello World" | ||
29 | , on #deleteEvent $ {- GI.Gdk.Unions.Event.Event -> (Bool, Event) -} \_ -> (True,Closed) | ||
30 | ] | ||
31 | $ widget Gtk.Label [#label := "Hello, World!"] | ||
32 | |||
33 | update' :: State -> Event -> Transition State Event | ||
34 | update' _ Closed = Exit | ||
35 | |||
36 | main :: IO () | ||
37 | main = do | ||
38 | Just pipelineDesc <- decodeStrict <$> SB.readFile "hello.json" | ||
39 | |||
40 | run App | ||
41 | -- :: App Gtk.Window State Event | ||
42 | { view = view' | ||
43 | , update = update' | ||
44 | , inputs = [] | ||
45 | , initialState = () | ||
46 | } | ||
diff --git a/Hello-glfw.hs b/Hello-glfw.hs new file mode 100644 index 0000000..c93136b --- /dev/null +++ b/Hello-glfw.hs | |||
@@ -0,0 +1,101 @@ | |||
1 | {-# LANGUAGE PackageImports, LambdaCase, OverloadedStrings #-} | ||
2 | import "GLFW-b" Graphics.UI.GLFW as GLFW | ||
3 | import qualified Data.Map as Map | ||
4 | import qualified Data.Vector as V | ||
5 | |||
6 | import LambdaCube.GL as LambdaCubeGL -- renderer | ||
7 | import LambdaCube.GL.Mesh as LambdaCubeGL | ||
8 | |||
9 | import Codec.Picture as Juicy | ||
10 | |||
11 | import Data.Aeson | ||
12 | import qualified Data.ByteString as SB | ||
13 | |||
14 | ---------------------------------------------------- | ||
15 | -- See: http://lambdacube3d.com/getting-started | ||
16 | ---------------------------------------------------- | ||
17 | |||
18 | main :: IO () | ||
19 | main = do | ||
20 | Just pipelineDesc <- decodeStrict <$> SB.readFile "hello.json" | ||
21 | |||
22 | win <- initWindow "LambdaCube 3D DSL Hello World" 640 640 | ||
23 | |||
24 | -- setup render data | ||
25 | let inputSchema = makeSchema $ do | ||
26 | defObjectArray "objects" Triangles $ do | ||
27 | "position" @: Attribute_V2F | ||
28 | "uv" @: Attribute_V2F | ||
29 | defUniforms $ do | ||
30 | "time" @: Float | ||
31 | "diffuseTexture" @: FTexture2D | ||
32 | |||
33 | storage <- LambdaCubeGL.allocStorage inputSchema | ||
34 | |||
35 | -- upload geometry to GPU and add to pipeline input | ||
36 | LambdaCubeGL.uploadMeshToGPU triangleA >>= LambdaCubeGL.addMeshToObjectArray storage "objects" [] | ||
37 | LambdaCubeGL.uploadMeshToGPU triangleB >>= LambdaCubeGL.addMeshToObjectArray storage "objects" [] | ||
38 | |||
39 | -- load image and upload texture | ||
40 | Right img <- Juicy.readImage "logo.png" | ||
41 | textureData <- LambdaCubeGL.uploadTexture2DToGPU img | ||
42 | |||
43 | -- allocate GL pipeline | ||
44 | renderer <- LambdaCubeGL.allocRenderer pipelineDesc | ||
45 | LambdaCubeGL.setStorage renderer storage >>= \case -- check schema compatibility | ||
46 | Just err -> putStrLn err | ||
47 | Nothing -> loop | ||
48 | where loop = do | ||
49 | -- update graphics input | ||
50 | GLFW.getWindowSize win >>= \(w,h) -> LambdaCubeGL.setScreenSize storage (fromIntegral w) (fromIntegral h) | ||
51 | LambdaCubeGL.updateUniforms storage $ do | ||
52 | "diffuseTexture" @= return textureData | ||
53 | "time" @= do | ||
54 | Just t <- GLFW.getTime | ||
55 | return (realToFrac t :: Float) | ||
56 | -- render | ||
57 | LambdaCubeGL.renderFrame renderer | ||
58 | GLFW.swapBuffers win | ||
59 | GLFW.pollEvents | ||
60 | |||
61 | let keyIsPressed k = fmap (==KeyState'Pressed) $ GLFW.getKey win k | ||
62 | escape <- keyIsPressed Key'Escape | ||
63 | if escape then return () else loop | ||
64 | |||
65 | LambdaCubeGL.disposeRenderer renderer | ||
66 | LambdaCubeGL.disposeStorage storage | ||
67 | GLFW.destroyWindow win | ||
68 | GLFW.terminate | ||
69 | |||
70 | -- geometry data: triangles | ||
71 | triangleA :: LambdaCubeGL.Mesh | ||
72 | triangleA = Mesh | ||
73 | { mAttributes = Map.fromList | ||
74 | [ ("position", A_V2F $ V.fromList [V2 1 1, V2 1 (-1), V2 (-1) (-1)]) | ||
75 | , ("uv", A_V2F $ V.fromList [V2 1 1, V2 0 1, V2 0 0]) | ||
76 | ] | ||
77 | , mPrimitive = P_Triangles | ||
78 | } | ||
79 | |||
80 | triangleB :: LambdaCubeGL.Mesh | ||
81 | triangleB = Mesh | ||
82 | { mAttributes = Map.fromList | ||
83 | [ ("position", A_V2F $ V.fromList [V2 1 1, V2 (-1) (-1), V2 (-1) 1]) | ||
84 | , ("uv", A_V2F $ V.fromList [V2 1 1, V2 0 0, V2 1 0]) | ||
85 | ] | ||
86 | , mPrimitive = P_Triangles | ||
87 | } | ||
88 | |||
89 | initWindow :: String -> Int -> Int -> IO Window | ||
90 | initWindow title width height = do | ||
91 | GLFW.init | ||
92 | GLFW.defaultWindowHints | ||
93 | mapM_ GLFW.windowHint | ||
94 | [ WindowHint'ContextVersionMajor 3 | ||
95 | , WindowHint'ContextVersionMinor 3 | ||
96 | , WindowHint'OpenGLProfile OpenGLProfile'Core | ||
97 | , WindowHint'OpenGLForwardCompat True | ||
98 | ] | ||
99 | Just win <- GLFW.createWindow width height title Nothing Nothing | ||
100 | GLFW.makeContextCurrent $ Just win | ||
101 | return win | ||
diff --git a/Hello-glut.hs b/Hello-glut.hs new file mode 100644 index 0000000..9ffa92c --- /dev/null +++ b/Hello-glut.hs | |||
@@ -0,0 +1,129 @@ | |||
1 | {-# LANGUAGE PackageImports, LambdaCase, OverloadedStrings #-} | ||
2 | import Control.Concurrent | ||
3 | |||
4 | -- import "GLFW-b" Graphics.UI.GLFW as GLFW | ||
5 | import qualified Graphics.UI.GLUT as GLFW -- lie | ||
6 | import qualified Graphics.UI.GLUT as GLUT -- truth | ||
7 | import Graphics.UI.GLUT (Window) | ||
8 | import qualified Data.Map as Map | ||
9 | import qualified Data.Vector as V | ||
10 | |||
11 | import LambdaCube.GL as LambdaCubeGL -- renderer | ||
12 | import LambdaCube.GL.Mesh as LambdaCubeGL | ||
13 | |||
14 | import Codec.Picture as Juicy | ||
15 | |||
16 | import Data.Aeson | ||
17 | import qualified Data.ByteString as SB | ||
18 | |||
19 | ---------------------------------------------------- | ||
20 | -- See: http://lambdacube3d.com/getting-started | ||
21 | ---------------------------------------------------- | ||
22 | |||
23 | main :: IO () | ||
24 | main = do | ||
25 | Just pipelineDesc <- decodeStrict <$> SB.readFile "hello.json" | ||
26 | |||
27 | win <- initWindow "LambdaCube 3D DSL Hello World" 640 640 | ||
28 | |||
29 | -- setup render data | ||
30 | let inputSchema = makeSchema $ do | ||
31 | defObjectArray "objects" Triangles $ do | ||
32 | "position" @: Attribute_V2F | ||
33 | "uv" @: Attribute_V2F | ||
34 | defUniforms $ do | ||
35 | "time" @: Float | ||
36 | "diffuseTexture" @: FTexture2D | ||
37 | |||
38 | storage <- LambdaCubeGL.allocStorage inputSchema | ||
39 | |||
40 | -- upload geometry to GPU and add to pipeline input | ||
41 | LambdaCubeGL.uploadMeshToGPU triangleA >>= LambdaCubeGL.addMeshToObjectArray storage "objects" [] | ||
42 | LambdaCubeGL.uploadMeshToGPU triangleB >>= LambdaCubeGL.addMeshToObjectArray storage "objects" [] | ||
43 | |||
44 | -- load image and upload texture | ||
45 | Right img <- Juicy.readImage "logo.png" | ||
46 | textureData <- LambdaCubeGL.uploadTexture2DToGPU img | ||
47 | |||
48 | -- allocate GL pipeline | ||
49 | renderer <- LambdaCubeGL.allocRenderer pipelineDesc | ||
50 | LambdaCubeGL.setStorage renderer storage >>= \case -- check schema compatibility | ||
51 | Just err -> putStrLn err | ||
52 | Nothing -> do qsig <- newMVar False | ||
53 | GLUT.keyboardMouseCallback GLUT.$= Just (keyCB qsig) | ||
54 | loop qsig | ||
55 | where loop qsig = do | ||
56 | -- update graphics input | ||
57 | -- GLFW.getWindowSize win >>= \(w,h) -> LambdaCubeGL.setScreenSize storage (fromIntegral w) (fromIntegral h) | ||
58 | GLUT.get GLUT.windowSize >>= \(GLUT.Size w h) -> LambdaCubeGL.setScreenSize storage (fromIntegral w) (fromIntegral h) | ||
59 | LambdaCubeGL.updateUniforms storage $ do | ||
60 | "diffuseTexture" @= return textureData | ||
61 | "time" @= do | ||
62 | -- Just t <- GLFW.getTime | ||
63 | Just t <- Just . (* (1000.0 :: Double)) . fromIntegral <$> GLUT.elapsedTime | ||
64 | return (realToFrac t :: Float) | ||
65 | -- render | ||
66 | LambdaCubeGL.renderFrame renderer | ||
67 | -- GLFW.swapBuffers win | ||
68 | GLUT.swapBuffers | ||
69 | -- GLFW.pollEvents | ||
70 | GLUT.mainLoopEvent | ||
71 | |||
72 | -- let keyIsPressed k = fmap (==KeyState'Pressed) $ GLFW.getKey win k | ||
73 | -- escape <- keyIsPressed Key'Escape | ||
74 | escape <- withMVar qsig return | ||
75 | if escape then return () else loop qsig | ||
76 | |||
77 | keyCB :: MVar Bool -> GLUT.KeyboardMouseCallback | ||
78 | keyCB qsig key keyState mods pos= do | ||
79 | cw <- GLUT.get GLUT.currentWindow | ||
80 | case (keyState,key,cw) of | ||
81 | (GLUT.Down,GLUT.Char 'q',Just cw) -> do | ||
82 | modifyMVar_ qsig (const $ return True) | ||
83 | GLUT.destroyWindow cw | ||
84 | (GLUT.Down,_,_)-> GLUT.postRedisplay Nothing | ||
85 | _ -> return () | ||
86 | |||
87 | LambdaCubeGL.disposeRenderer renderer | ||
88 | LambdaCubeGL.disposeStorage storage | ||
89 | GLFW.destroyWindow win | ||
90 | -- GLFW.terminate | ||
91 | |||
92 | -- geometry data: triangles | ||
93 | triangleA :: LambdaCubeGL.Mesh | ||
94 | triangleA = Mesh | ||
95 | { mAttributes = Map.fromList | ||
96 | [ ("position", A_V2F $ V.fromList [V2 1 1, V2 1 (-1), V2 (-1) (-1)]) | ||
97 | , ("uv", A_V2F $ V.fromList [V2 1 1, V2 0 1, V2 0 0]) | ||
98 | ] | ||
99 | , mPrimitive = P_Triangles | ||
100 | } | ||
101 | |||
102 | triangleB :: LambdaCubeGL.Mesh | ||
103 | triangleB = Mesh | ||
104 | { mAttributes = Map.fromList | ||
105 | [ ("position", A_V2F $ V.fromList [V2 1 1, V2 (-1) (-1), V2 (-1) 1]) | ||
106 | , ("uv", A_V2F $ V.fromList [V2 1 1, V2 0 0, V2 1 0]) | ||
107 | ] | ||
108 | , mPrimitive = P_Triangles | ||
109 | } | ||
110 | |||
111 | initWindow :: String -> Int -> Int -> IO Window | ||
112 | initWindow title width height = do | ||
113 | {- | ||
114 | GLFW.init | ||
115 | GLFW.defaultWindowHints | ||
116 | mapM_ GLFW.windowHint | ||
117 | [ WindowHint'ContextVersionMajor 3 | ||
118 | , WindowHint'ContextVersionMinor 3 | ||
119 | , WindowHint'OpenGLProfile OpenGLProfile'Core | ||
120 | , WindowHint'OpenGLForwardCompat True | ||
121 | ] | ||
122 | Just win <- GLFW.createWindow width height title Nothing Nothing | ||
123 | GLFW.makeContextCurrent $ Just win | ||
124 | -} | ||
125 | (progname,args) <- GLUT.getArgsAndInitialize | ||
126 | win <- GLUT.createWindow title | ||
127 | GLUT.actionOnWindowClose GLUT.$=! GLUT.MainLoopReturns | ||
128 | return win | ||
129 | |||
@@ -0,0 +1,32 @@ | |||
1 | {-# LANGUAGE OverloadedLabels #-} | ||
2 | {-# LANGUAGE OverloadedLists #-} | ||
3 | {-# LANGUAGE OverloadedStrings #-} | ||
4 | module Main where | ||
5 | |||
6 | import qualified GI.Gtk as Gtk | ||
7 | import GI.Gtk.Declarative | ||
8 | import GI.Gtk.Declarative.App.Simple | ||
9 | |||
10 | type State = () | ||
11 | |||
12 | data Event = Closed | ||
13 | |||
14 | view' :: State -> AppView Gtk.Window Event | ||
15 | view' _ = bin | ||
16 | Gtk.Window | ||
17 | [ #title := "Demo" | ||
18 | , on #deleteEvent $ {- GI.Gdk.Unions.Event.Event -> (Bool, Event) -} \_ -> (True,Closed) | ||
19 | ] | ||
20 | $ widget Gtk.Label [#label := "Hello, World!"] | ||
21 | |||
22 | update' :: State -> Event -> Transition State Event | ||
23 | update' _ Closed = Exit | ||
24 | |||
25 | main :: IO () | ||
26 | main = run App | ||
27 | -- :: App Gtk.Window State Event | ||
28 | { view = view' | ||
29 | , update = update' | ||
30 | , inputs = [] | ||
31 | , initialState = () | ||
32 | } | ||
diff --git a/hello.json b/hello.json new file mode 100644 index 0000000..22f3ff1 --- /dev/null +++ b/hello.json | |||
@@ -0,0 +1 @@ | |||
{"textures":[],"commands":[{"tag":"SetRenderTarget","arg0":0},{"tag":"ClearRenderTarget","arg0":[{"tag":"ClearImage","clearValue":{"tag":"VV4F","arg0":{"w":1,"z":0.4,"x":0.0,"y":0.0}},"imageSemantic":{"tag":"Color"}}]},{"tag":"SetProgram","arg0":0},{"tag":"SetSamplerUniform","arg0":"diffuseTexture","arg1":0},{"tag":"SetRasterContext","arg0":{"arg3":{"tag":"LastVertex"},"tag":"TriangleCtx","arg0":{"tag":"CullNone"},"arg1":{"tag":"PolygonFill"},"arg2":{"tag":"NoOffset"}}},{"tag":"SetAccumulationContext","arg0":{"accViewportName":null,"tag":"AccumulationContext","accOperations":[{"tag":"ColorOp","arg0":{"tag":"NoBlending"},"arg1":{"tag":"VV4B","arg0":{"w":true,"z":true,"x":true,"y":true}}}]}},{"tag":"RenderSlot","arg0":0}],"slots":[{"tag":"Slot","slotPrimitive":{"tag":"Triangles"},"slotStreams":{"uv":{"tag":"V2F"},"position":{"tag":"V2F"}},"slotName":"objects","slotUniforms":{"time":{"tag":"Float"},"diffuseTexture":{"tag":"FTexture2D"}},"slotPrograms":[0]}],"programs":[{"programInTextures":{"diffuseTexture":{"tag":"FTexture2D"}},"tag":"Program","programOutput":[{"tag":"Parameter","ty":{"tag":"V4F"},"name":"f0"}],"programStreams":{"vi2":{"tag":"Parameter","ty":{"tag":"V2F"},"name":"uv"},"vi1":{"tag":"Parameter","ty":{"tag":"V2F"},"name":"position"}},"fragmentShader":"#version 330 core\nvec4 texture2D(sampler2D s\n ,vec2 uv) {\n return texture(s,uv);\n}\nuniform sampler2D diffuseTexture;\nsmooth in vec2 vo1;\nout vec4 f0;\nvoid main() {\n f0 = texture2D (diffuseTexture\n ,vo1);\n}","vertexShader":"#version 330 core\nvec4 texture2D(sampler2D s\n ,vec2 uv) {\n return texture(s,uv);\n}\nuniform float time;\nin vec2 vi1;\nin vec2 vi2;\nsmooth out vec2 vo1;\nmat4 rotMatrixZ(float z0) {\n return mat4 (vec4 (cos (z0)\n ,sin (z0)\n ,0.0\n ,0.0)\n ,vec4 ((0.0) - (sin (z0))\n ,cos (z0)\n ,0.0\n ,0.0)\n ,vec4 (0.0,0.0,1.0,0.0)\n ,vec4 (0.0,0.0,0.0,1.0));\n}\nvoid main() {\n gl_Position = (rotMatrixZ\n (time)) * (vec4 ((vi1).x\n ,(vi1).y\n ,-1.0\n ,1.0));\n vo1 = vi2;\n}","geometryShader":null,"programUniforms":{"time":{"tag":"Float"},"diffuseTexture":{"tag":"FTexture2D"}}}],"samplers":[],"tag":"Pipeline","backend":{"tag":"OpenGL33"},"streams":[],"targets":[{"tag":"RenderTarget","renderTargets":[{"tag":"TargetItem","targetSemantic":{"tag":"Color"},"targetRef":{"tag":"Framebuffer","arg0":{"tag":"Color"}}}]}],"info":"generated by lambdacube-compiler 0.5.0.0"} \ No newline at end of file | |||
diff --git a/hello.lc b/hello.lc new file mode 100644 index 0000000..5837a82 --- /dev/null +++ b/hello.lc | |||
@@ -0,0 +1,16 @@ | |||
1 | makeFrame (time :: Float) | ||
2 | (texture :: Texture) | ||
3 | (prims :: PrimitiveStream Triangle (Vec 2 Float, Vec 2 Float)) | ||
4 | |||
5 | = imageFrame ((emptyColorImage (V4 0 0 0.4 1))) | ||
6 | `overlay` | ||
7 | prims | ||
8 | & mapPrimitives (\(p,uv) -> (rotMatrixZ time *. (V4 p%x p%y (-1) 1), uv)) | ||
9 | & rasterizePrimitives (TriangleCtx CullNone PolygonFill NoOffset LastVertex) ((Smooth)) | ||
10 | & mapFragments (\((uv)) -> ((texture2D (Sampler PointFilter MirroredRepeat texture) uv))) | ||
11 | & accumulateWith ((ColorOp NoBlending (V4 True True True True))) | ||
12 | |||
13 | main = renderFrame $ | ||
14 | makeFrame (Uniform "time") | ||
15 | (Texture2DSlot "diffuseTexture") | ||
16 | (fetch "objects" (Attribute "position", Attribute "uv")) | ||