summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCsaba Hruska <csaba.hruska@gmail.com>2016-01-29 15:24:25 +0100
committerCsaba Hruska <csaba.hruska@gmail.com>2016-01-29 15:24:25 +0100
commit0d46a5cda433fe1a97f3c35002c192d8050e747a (patch)
treeb8b131a793fcc09ea16b98271099955065ec848f
parenteee4ea0d259394c1dde883be3f2528def93207c5 (diff)
intial version of backend test client
-rw-r--r--Monkey.lcmeshbin371791 -> 0 bytes
-rw-r--r--testclient/TestData.hs213
-rw-r--r--testclient/client.hs187
3 files changed, 400 insertions, 0 deletions
diff --git a/Monkey.lcmesh b/Monkey.lcmesh
deleted file mode 100644
index b651d61..0000000
--- a/Monkey.lcmesh
+++ /dev/null
Binary files differ
diff --git a/testclient/TestData.hs b/testclient/TestData.hs
new file mode 100644
index 0000000..a48dc42
--- /dev/null
+++ b/testclient/TestData.hs
@@ -0,0 +1,213 @@
1-- generated file, do not modify!
2-- 2016-01-28T13:15:31.27456Z
3
4{-# LANGUAGE OverloadedStrings, RecordWildCards #-}
5module TestData where
6
7import Data.Int
8import Data.Word
9import Data.Map
10import Data.Vector (Vector(..))
11import LambdaCube.Linear
12
13import Data.Text
14import Data.Aeson hiding (Value,Bool)
15import Data.Aeson.Types hiding (Value,Bool)
16import Control.Monad
17
18import LambdaCube.IR
19import LambdaCube.Mesh
20import LambdaCube.PipelineSchema
21
22data ClientInfo
23 = ClientInfo
24 { clientName :: String
25 , clientBackend :: Backend
26 }
27
28 deriving (Show, Eq, Ord)
29
30data Frame
31 = Frame
32 { renderCount :: Int
33 , frameUniforms :: Map String Value
34 , frameTextures :: Map String Int
35 }
36
37 deriving (Show, Eq, Ord)
38
39data Scene
40 = Scene
41 { objectArrays :: Map String (Vector Int)
42 , renderTargetWidth :: Int
43 , renderTargetHeight :: Int
44 , frames :: Vector Frame
45 }
46
47 deriving (Show, Eq, Ord)
48
49data RenderJob
50 = RenderJob
51 { meshes :: Vector Mesh
52 , textures :: Vector String
53 , schema :: PipelineSchema
54 , scenes :: Vector Scene
55 , pipelines :: Vector Pipeline
56 }
57
58 deriving (Show, Eq, Ord)
59
60data FrameResult
61 = FrameResult
62 { frRenderTimes :: Vector Float
63 , frImageWidth :: Int
64 , frImageHeight :: Int
65 }
66
67 deriving (Show, Eq, Ord)
68
69data RenderJobResult
70 = RenderJobResult FrameResult
71 | RenderJobError String
72 deriving (Show, Eq, Ord)
73
74
75instance ToJSON ClientInfo where
76 toJSON v = case v of
77 ClientInfo{..} -> object
78 [ "tag" .= ("ClientInfo" :: Text)
79 , "clientName" .= clientName
80 , "clientBackend" .= clientBackend
81 ]
82
83instance FromJSON ClientInfo where
84 parseJSON (Object obj) = do
85 tag <- obj .: "tag"
86 case tag :: Text of
87 "ClientInfo" -> do
88 clientName <- obj .: "clientName"
89 clientBackend <- obj .: "clientBackend"
90 pure $ ClientInfo
91 { clientName = clientName
92 , clientBackend = clientBackend
93 }
94 parseJSON _ = mzero
95
96instance ToJSON Frame where
97 toJSON v = case v of
98 Frame{..} -> object
99 [ "tag" .= ("Frame" :: Text)
100 , "renderCount" .= renderCount
101 , "frameUniforms" .= frameUniforms
102 , "frameTextures" .= frameTextures
103 ]
104
105instance FromJSON Frame where
106 parseJSON (Object obj) = do
107 tag <- obj .: "tag"
108 case tag :: Text of
109 "Frame" -> do
110 renderCount <- obj .: "renderCount"
111 frameUniforms <- obj .: "frameUniforms"
112 frameTextures <- obj .: "frameTextures"
113 pure $ Frame
114 { renderCount = renderCount
115 , frameUniforms = frameUniforms
116 , frameTextures = frameTextures
117 }
118 parseJSON _ = mzero
119
120instance ToJSON Scene where
121 toJSON v = case v of
122 Scene{..} -> object
123 [ "tag" .= ("Scene" :: Text)
124 , "objectArrays" .= objectArrays
125 , "renderTargetWidth" .= renderTargetWidth
126 , "renderTargetHeight" .= renderTargetHeight
127 , "frames" .= frames
128 ]
129
130instance FromJSON Scene where
131 parseJSON (Object obj) = do
132 tag <- obj .: "tag"
133 case tag :: Text of
134 "Scene" -> do
135 objectArrays <- obj .: "objectArrays"
136 renderTargetWidth <- obj .: "renderTargetWidth"
137 renderTargetHeight <- obj .: "renderTargetHeight"
138 frames <- obj .: "frames"
139 pure $ Scene
140 { objectArrays = objectArrays
141 , renderTargetWidth = renderTargetWidth
142 , renderTargetHeight = renderTargetHeight
143 , frames = frames
144 }
145 parseJSON _ = mzero
146
147instance ToJSON RenderJob where
148 toJSON v = case v of
149 RenderJob{..} -> object
150 [ "tag" .= ("RenderJob" :: Text)
151 , "meshes" .= meshes
152 , "textures" .= textures
153 , "schema" .= schema
154 , "scenes" .= scenes
155 , "pipelines" .= pipelines
156 ]
157
158instance FromJSON RenderJob where
159 parseJSON (Object obj) = do
160 tag <- obj .: "tag"
161 case tag :: Text of
162 "RenderJob" -> do
163 meshes <- obj .: "meshes"
164 textures <- obj .: "textures"
165 schema <- obj .: "schema"
166 scenes <- obj .: "scenes"
167 pipelines <- obj .: "pipelines"
168 pure $ RenderJob
169 { meshes = meshes
170 , textures = textures
171 , schema = schema
172 , scenes = scenes
173 , pipelines = pipelines
174 }
175 parseJSON _ = mzero
176
177instance ToJSON FrameResult where
178 toJSON v = case v of
179 FrameResult{..} -> object
180 [ "tag" .= ("FrameResult" :: Text)
181 , "frRenderTimes" .= frRenderTimes
182 , "frImageWidth" .= frImageWidth
183 , "frImageHeight" .= frImageHeight
184 ]
185
186instance FromJSON FrameResult where
187 parseJSON (Object obj) = do
188 tag <- obj .: "tag"
189 case tag :: Text of
190 "FrameResult" -> do
191 frRenderTimes <- obj .: "frRenderTimes"
192 frImageWidth <- obj .: "frImageWidth"
193 frImageHeight <- obj .: "frImageHeight"
194 pure $ FrameResult
195 { frRenderTimes = frRenderTimes
196 , frImageWidth = frImageWidth
197 , frImageHeight = frImageHeight
198 }
199 parseJSON _ = mzero
200
201instance ToJSON RenderJobResult where
202 toJSON v = case v of
203 RenderJobResult arg0 -> object [ "tag" .= ("RenderJobResult" :: Text), "arg0" .= arg0]
204 RenderJobError arg0 -> object [ "tag" .= ("RenderJobError" :: Text), "arg0" .= arg0]
205
206instance FromJSON RenderJobResult where
207 parseJSON (Object obj) = do
208 tag <- obj .: "tag"
209 case tag :: Text of
210 "RenderJobResult" -> RenderJobResult <$> obj .: "arg0"
211 "RenderJobError" -> RenderJobError <$> obj .: "arg0"
212 parseJSON _ = mzero
213
diff --git a/testclient/client.hs b/testclient/client.hs
new file mode 100644
index 0000000..236320c
--- /dev/null
+++ b/testclient/client.hs
@@ -0,0 +1,187 @@
1{-# LANGUAGE PackageImports, LambdaCase, OverloadedStrings, RecordWildCards #-}
2
3import Control.Concurrent
4import Control.Concurrent.MVar
5import Control.Monad
6import Control.Monad.Catch
7import Data.Text (Text)
8import Data.Vector (Vector,(!))
9import Data.ByteString.Char8 (unpack,pack)
10import qualified Data.ByteString as SB
11import qualified Data.Vector as V
12import qualified Data.Map as Map
13import qualified Data.ByteString.Base64 as B64
14
15import System.Exit
16import Data.Time.Clock
17import Data.Aeson
18import Foreign
19
20import qualified Network.WebSockets as WS
21import Network.Socket
22
23import "GLFW-b" Graphics.UI.GLFW as GLFW
24import "OpenGLRaw" Graphics.GL.Core33
25import Codec.Picture as Juicy
26
27import LambdaCube.IR
28import LambdaCube.PipelineSchema
29import LambdaCube.Mesh
30import LambdaCube.GL
31import LambdaCube.GL.Mesh
32import TestData
33
34main = do
35 win <- initWindow "LambdaCube 3D OpenGL 3.3 Backend" 256 256
36
37 GLFW.setWindowCloseCallback win $ Just $ \_ -> do
38 GLFW.destroyWindow win
39 GLFW.terminate
40 exitSuccess
41
42 -- connect to the test server
43 forever $ catchAll (setupConnection win) $ \_ -> do
44 GLFW.pollEvents
45 threadDelay 100000
46
47setupConnection win = withSocketsDo $ WS.runClient "192.168.0.12" 9160 "/" $ \conn -> do
48 putStrLn "Connected!"
49 -- register backend
50 WS.sendTextData conn . encode $ ClientInfo
51 { clientName = "Haskell OpenGL 3.3"
52 , clientBackend = OpenGL33
53 }
54 chan <- newEmptyMVar :: IO (MVar RenderJob)
55 -- wait for incoming render jobs
56 _ <- forkIO $ forever $ do
57 -- get the pipeline from the server
58 decodeStrict <$> WS.receiveData conn >>= \case
59 Nothing -> putStrLn "unknown message"
60 Just renderJob -> putMVar chan renderJob
61 -- process render jobs
62 forever $ do
63 tryTakeMVar chan >>= \case
64 Nothing -> return ()
65 Just rj -> processRenderJob win conn rj
66 WS.sendPing conn ("hello" :: Text)
67 GLFW.pollEvents
68 threadDelay 100000
69 putStrLn "disconnected"
70 WS.sendClose conn ("Bye!" :: Text)
71
72doAfter = flip (>>)
73
74processRenderJob win conn renderJob@RenderJob{..} = do
75 putStrLn "got render job"
76 gpuData@GPUData{..} <- allocateGPUData renderJob
77 -- foreach pipeline
78 doAfter (disposeGPUData gpuData) $ forM_ pipelines $ \pipelineDesc -> do
79 renderer <- allocRenderer pipelineDesc
80 -- foreach scene
81 doAfter (disposeRenderer renderer) $ forM_ scenes $ \Scene{..} -> do
82 storage <- allocStorage schema
83 -- add objects
84 forM_ (Map.toList objectArrays) $ \(name,objs) -> forM_ objs $ addMeshToObjectArray storage name [] . (gpuMeshes !)
85 -- set render target size
86 GLFW.setWindowSize win renderTargetWidth renderTargetHeight
87 setScreenSize storage (fromIntegral renderTargetWidth) (fromIntegral renderTargetHeight)
88 -- connect renderer with storage
89 doAfter (disposeStorage storage) $ setStorage renderer storage >>= \case
90 Just err -> putStrLn err
91 Nothing -> do
92 -- foreach frame
93 forM_ frames $ \Frame{..} -> do
94 -- setup uniforms
95 updateUniforms storage $ do
96 forM_ (Map.toList frameTextures) $ \(name,tex) -> pack name @= return (gpuTextures ! tex)
97 forM_ (Map.toList frameUniforms) $ uncurry setUniformValue
98 -- rendering
99 renderTimes <- V.replicateM renderCount . timeDiff $ do
100 renderFrame renderer
101 GLFW.swapBuffers win
102 GLFW.pollEvents
103 -- send render job result to server
104 WS.sendTextData conn . encode . RenderJobResult $ FrameResult
105 { frRenderTimes = renderTimes
106 , frImageWidth = renderTargetWidth
107 , frImageHeight = renderTargetHeight
108 }
109 -- send the last render result using Base64 encoding
110 WS.sendBinaryData conn . B64.encode =<< getFrameBuffer renderTargetWidth renderTargetHeight
111
112-- utility code
113
114initWindow :: String -> Int -> Int -> IO Window
115initWindow title width height = do
116 GLFW.init
117 GLFW.defaultWindowHints
118 mapM_ GLFW.windowHint
119 [ WindowHint'ContextVersionMajor 3
120 , WindowHint'ContextVersionMinor 3
121 , WindowHint'OpenGLProfile OpenGLProfile'Core
122 , WindowHint'OpenGLForwardCompat True
123 ]
124 Just win <- GLFW.createWindow width height title Nothing Nothing
125 GLFW.makeContextCurrent $ Just win
126 return win
127
128getFrameBuffer w h = do
129 glFinish
130 glBindFramebuffer GL_READ_FRAMEBUFFER 0
131 glReadBuffer GL_FRONT_LEFT
132 glBlitFramebuffer 0 0 (fromIntegral w) (fromIntegral h) 0 (fromIntegral h) (fromIntegral w) 0 GL_COLOR_BUFFER_BIT GL_NEAREST
133 glReadBuffer GL_BACK_LEFT
134 withFrameBuffer 0 0 w h $ \p -> SB.packCStringLen (castPtr p,w*h*4)
135
136withFrameBuffer :: Int -> Int -> Int -> Int -> (Ptr Word8 -> IO a) -> IO a
137withFrameBuffer x y w h fn = allocaBytes (w*h*4) $ \p -> do
138 glPixelStorei GL_UNPACK_LSB_FIRST 0
139 glPixelStorei GL_UNPACK_SWAP_BYTES 0
140 glPixelStorei GL_UNPACK_ROW_LENGTH 0
141 glPixelStorei GL_UNPACK_IMAGE_HEIGHT 0
142 glPixelStorei GL_UNPACK_SKIP_ROWS 0
143 glPixelStorei GL_UNPACK_SKIP_PIXELS 0
144 glPixelStorei GL_UNPACK_SKIP_IMAGES 0
145 glPixelStorei GL_UNPACK_ALIGNMENT 1 -- normally 4!
146 glReadPixels (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) GL_RGBA GL_UNSIGNED_BYTE $ castPtr p
147 fn p
148
149data GPUData
150 = GPUData
151 { gpuTextures :: Vector TextureData
152 , gpuMeshes :: Vector GPUMesh
153 }
154
155allocateGPUData RenderJob{..} = GPUData <$> mapM uploadTex2D textures <*> mapM uploadMeshToGPU meshes
156 where uploadTex2D = uploadTexture2DToGPU . either error id . decodeImage . either error id . B64.decode . pack
157
158disposeGPUData GPUData{..} = mapM_ disposeTexture gpuTextures >> mapM_ disposeMesh gpuMeshes
159
160timeDiff m = (\s e -> realToFrac $ diffUTCTime e s) <$> getCurrentTime <* m <*> getCurrentTime
161
162setUniformValue name = \case
163 VBool v -> pack name @= return v
164 VV2B v -> pack name @= return v
165 VV3B v -> pack name @= return v
166 VV4B v -> pack name @= return v
167 VWord v -> pack name @= return v
168 VV2U v -> pack name @= return v
169 VV3U v -> pack name @= return v
170 VV4U v -> pack name @= return v
171 VInt v -> pack name @= return v
172 VV2I v -> pack name @= return v
173 VV3I v -> pack name @= return v
174 VV4I v -> pack name @= return v
175 VFloat v -> pack name @= return v
176 VV2F v -> pack name @= return v
177 VV3F v -> pack name @= return v
178 VV4F v -> pack name @= return v
179 VM22F v -> pack name @= return v
180 VM23F v -> pack name @= return v
181 VM24F v -> pack name @= return v
182 VM32F v -> pack name @= return v
183 VM33F v -> pack name @= return v
184 VM34F v -> pack name @= return v
185 VM42F v -> pack name @= return v
186 VM43F v -> pack name @= return v
187 VM44F v -> pack name @= return v