summaryrefslogtreecommitdiff
path: root/examples/Hello.hs
blob: cfe10537511c9ce45ac851eba0523bd2c5f86d4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
{-# LANGUAGE PackageImports, LambdaCase #-}
{-# LANGUAGE FlexibleContexts #-}
import "GLFW-b" Graphics.UI.GLFW as GLFW
import qualified Data.Map as Map
import qualified Data.Vector.Storable as SV

import "lambdacube-gl-ir" LambdaCube.GL as LambdaCubeGL -- renderer
import "lambdacube-gl-ir" LambdaCube.GL.Mesh as LambdaCubeGL

import Codec.Picture as Juicy

import LambdaCube.Compiler.Driver as LambdaCube -- compiler

----
import Control.Monad.Writer

{-
data ObjectArraySchema
    = ObjectArraySchema
    { primitive     :: FetchPrimitive
    , attributes    :: Map String StreamType
    }
    deriving Show

data PipelineSchema
    = PipelineSchema
    { objectArrays  :: Map String ObjectArraySchema
    , uniforms      :: Map String InputType
    }
-}


a @: b = tell [(a,b)]
defObjectArray n p m = tell [PipelineSchema (Map.singleton n $ ObjectArraySchema p $ Map.fromList $ execWriter m) mempty]
defUniforms m = tell [PipelineSchema mempty $ Map.fromList $ execWriter m]
makeSchema a = head $ execWriter a :: PipelineSchema

sch = makeSchema $ do
  defObjectArray "objects" Triangles $ do
    "position"  @: Attribute_V4F
    "uv"        @: Attribute_V2F
  defUniforms $ do
    "time"           @: Float
    "diffuseTexture" @: FTexture2D

-----
main :: IO ()
main = do
    -- compile hello.lc to graphics pipeline description
    pipelineDesc <- LambdaCube.compileMain ["."] OpenGL33 "hello" >>= \case
      Left err  -> fail $ "compile error:\n" ++ err
      Right pd  -> return pd

    win <- initWindow "LambdaCube 3D DSL Hello World" 640 480

    -- setup render data
    let inputSchema = makeSchema $ do
          defObjectArray "objects" Triangles $ do
            "position"  @: Attribute_V4F
            "uv"        @: Attribute_V2F
          defUniforms $ do
            "time"           @: Float
            "diffuseTexture" @: FTexture2D

    storage <- LambdaCubeGL.allocStorage inputSchema

    -- upload geometry to GPU and add to pipeline input
    LambdaCubeGL.uploadMeshToGPU triangleA >>= LambdaCubeGL.addMeshToObjectArray storage "objects" []
    LambdaCubeGL.uploadMeshToGPU triangleB >>= LambdaCubeGL.addMeshToObjectArray storage "objects" []

    -- load image and upload texture
    Right img <- Juicy.readImage "Panels_Diffuse.png"
    textureData <- LambdaCubeGL.uploadTexture2DToGPU img

    -- allocate GL pipeline
    renderer <- LambdaCubeGL.allocRenderer pipelineDesc
    LambdaCubeGL.setStorage renderer storage >>= \case -- check schema compatibility
      Just err -> putStrLn err
      Nothing  -> loop
        where loop = do
                -- update graphics input
                GLFW.getWindowSize win >>= \(w,h) -> LambdaCubeGL.setScreenSize storage (fromIntegral w) (fromIntegral h)
                {-
                LambdaCubeGL.updateUniforms storage $ do
                  "time" @= fromJust <$> GLFW.getTime
                  "diffuseTexture" @= return textureData
                -}
                -- render
                LambdaCubeGL.renderFrame renderer
                GLFW.swapBuffers win
                GLFW.pollEvents

                let keyIsPressed k = fmap (==KeyState'Pressed) $ GLFW.getKey win k
                escape <- keyIsPressed Key'Escape
                if escape then return () else loop

    LambdaCubeGL.disposeRenderer renderer
    LambdaCubeGL.disposeStorage storage
    GLFW.destroyWindow win
    GLFW.terminate

-- geometry data: triangles
triangleA :: LambdaCubeGL.Mesh
triangleA = Mesh
    { mAttributes   = Map.fromList
        [ ("position",  A_V2F $ SV.fromList [V2 1 1, V2 1 (-1), V2 (-1) (-1)])
        , ("uv",        A_V2F $ SV.fromList [V2 0 0, V2 0 1, V2 1 1])
        ]
    , mPrimitive    = P_Triangles
    , mGPUData      = Nothing
    }

triangleB :: LambdaCubeGL.Mesh
triangleB = Mesh
    { mAttributes   = Map.fromList
        [ ("position",  A_V2F $ SV.fromList [V2 1 1, V2 (-1) (-1), V2 (-1) 1])
        , ("uv",        A_V2F $ SV.fromList [V2 0 0, V2 1 1, V2 1 0])
        ]
    , mPrimitive    = P_Triangles
    , mGPUData      = Nothing
    }

initWindow :: String -> Int -> Int -> IO Window
initWindow title width height = do
    GLFW.init
    GLFW.defaultWindowHints
    mapM_ GLFW.windowHint
      [ WindowHint'ContextVersionMajor 3
      , WindowHint'ContextVersionMinor 3
      , WindowHint'OpenGLProfile OpenGLProfile'Core
      , WindowHint'OpenGLForwardCompat True
      ]
    Just win <- GLFW.createWindow width height title Nothing Nothing
    GLFW.makeContextCurrent $ Just win
    return win