summaryrefslogtreecommitdiff
path: root/main.hs
blob: dff82632dc411387596283dbbb0d5764a8e5bc25 (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
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
module Main where

import Codec.Picture             as Juicy
import Control.Concurrent
import Data.Word
import Data.Function
import qualified Data.Map.Strict as Map
import qualified Data.Vector     as V
import GI.Gdk.Objects
import GI.GLib.Constants
import GI.Gtk                    as Gtk hiding (main)
import LambdaCube.GL             as LC
import LambdaCube.GL.Mesh        as LC
import System.IO
import System.IO.Error

import GLWidget
import LambdaCubeWidget
import TimeKeeper

type State = (TextureData, TimeKeeper, TickCallbackHandle)

uploadState :: IsWidget glarea => DynamicImage -> glarea -> GLStorage -> IO State
uploadState img glarea storage = do
    -- upload geometry to GPU and add to pipeline input
    LC.uploadMeshToGPU triangleA >>= LC.addMeshToObjectArray storage "objects" []
    LC.uploadMeshToGPU triangleB >>= LC.addMeshToObjectArray storage "objects" []
    -- load image and upload texture
    texture <- LC.uploadTexture2DToGPU img
    -- setup FrameClock
    tm <- newTimeKeeper
    tickcb <- widgetAddTickCallback glarea (tick tm)
    return (texture,tm,tickcb)

destroyState :: GLArea -> State -> IO ()
destroyState glarea (texture,tm,tickcb) = do
    widgetRemoveTickCallback glarea tickcb

setUniforms :: glctx -> GLStorage -> State -> IO ()
setUniforms gl storage (texture,tm,_) = do
    t <- withMVar (tmSeconds tm) return
    LC.updateUniforms storage $ do
      "diffuseTexture" @= return texture
      "time" @= return (realToFrac t :: Float)

main :: IO ()
main = do
    m <- do
        mimg <- Juicy.readImage "logo.png" `catchIOError` \e -> return $ Left (show e)
        mpipeline <- loadPipeline "hello.json" $ do
                        defObjectArray "objects" Triangles $ do
                            "position"  @: Attribute_V2F
                            "uv"        @: Attribute_V2F
                        defUniforms $ do
                            "time"           @: Float
                            "diffuseTexture" @: FTexture2D
        return $ (,) <$> mimg <*> mpipeline
    either (\e _ -> hPutStrLn stderr e) (&) m $ \(logo,pipeline) -> do
        app <- do
            mvar <- newEmptyMVar
            return $ \glarea -> LCMethods
                { lcRealized     = mvar
                , lcUploadState  = uploadState logo glarea
                , lcDestroyState = destroyState glarea
                , lcSetUniforms  = setUniforms
                , lcPipeline     = pipeline
                }

        runGLApp return (lambdaRender app glmethods)

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

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