summaryrefslogtreecommitdiff
path: root/MeshSketch.hs
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-05-14 13:32:37 -0400
committerJoe Crayne <joe@jerkface.net>2019-05-14 13:32:37 -0400
commit07ea0fe2a37cab1e549c084f31d231632857b99f (patch)
tree4e884c2cdf509fa10d35842d5853063b7a56d995 /MeshSketch.hs
parent9f99af1750924a0be6e003842830aec93380dfdc (diff)
TextureBuffer-based ring buffer.
Diffstat (limited to 'MeshSketch.hs')
-rw-r--r--MeshSketch.hs182
1 files changed, 141 insertions, 41 deletions
diff --git a/MeshSketch.hs b/MeshSketch.hs
index b84cd7e..9425890 100644
--- a/MeshSketch.hs
+++ b/MeshSketch.hs
@@ -16,6 +16,8 @@ import Data.Text (Text)
16import Data.Map.Strict (Map) 16import Data.Map.Strict (Map)
17import qualified Data.Map.Strict as Map 17import qualified Data.Map.Strict as Map
18import qualified Data.Vector as V 18import qualified Data.Vector as V
19import Foreign.Marshal.Array
20import Foreign.Storable
19import GI.Gdk 21import GI.Gdk
20import GI.Gdk.Objects 22import GI.Gdk.Objects
21import GI.GLib.Constants 23import GI.GLib.Constants
@@ -30,9 +32,12 @@ import Control.Exception
30import LambdaCube.GL as LC 32import LambdaCube.GL as LC
31import LambdaCube.IR as LC 33import LambdaCube.IR as LC
32import LambdaCube.Gtk 34import LambdaCube.Gtk
33import LambdaCube.GL.Data (uploadCubeMapToGPU) 35import LambdaCube.GL.Data (uploadCubeMapToGPU,uploadTextureBufferToGPU,updateTextureBuffer)
34import LambdaCube.GL.Type (TextureCubeData(..)) 36import LambdaCube.GL.Type (TextureCubeData(..),Object(..))
35-- import Text.Show.Pretty (ppShow) 37-- import Text.Show.Pretty (ppShow)
38import qualified Graphics.Rendering.OpenGL as GL
39import Data.Char
40import Text.Printf
36 41
37import CubeMap 42import CubeMap
38import GLWidget (nullableContext, withCurrentGL) 43import GLWidget (nullableContext, withCurrentGL)
@@ -44,6 +49,27 @@ import InfinitePlane
44import MtlParser (ObjMaterial(..)) 49import MtlParser (ObjMaterial(..))
45import Matrix 50import Matrix
46 51
52
53prettyDebug :: GL.DebugMessage -> String
54prettyDebug (GL.DebugMessage src typ (GL.DebugMessageID mid) severity msg) = unwords ws
55 where
56 ws = [wsrc,wtyp,wmid,wseverity,msg]
57 -- DebugSourceShaderCompiler DebugTypeOther 1 DebugSeverityNotification
58 wsrc = filter isUpper $ drop 11 $ show src
59 wtyp = take 2 $ drop 9 $ show typ
60 wmid = printf "%03i" mid
61 wseverity = drop 13 $ show severity
62
63setupGLDebugging :: IO ()
64setupGLDebugging = do
65 let pdebug m@(GL.DebugMessage src typ mid severity msg) = do
66 putStrLn (">> " ++ prettyDebug m)
67 GL.debugOutput GL.$= GL.Enabled
68 GL.debugOutputSynchronous GL.$= GL.Enabled
69 GL.debugMessageControl (GL.MessageGroup Nothing Nothing Nothing) GL.$= GL.Enabled
70 GL.debugMessageCallback GL.$= Just pdebug
71
72
47-- State created by uploadState. 73-- State created by uploadState.
48data State = State 74data State = State
49 { stAnimator :: Animator 75 { stAnimator :: Animator
@@ -53,6 +79,8 @@ data State = State
53 , stSkybox :: IORef Int 79 , stSkybox :: IORef Int
54 , stSkyTexture :: IORef TextureCubeData 80 , stSkyTexture :: IORef TextureCubeData
55 , stDragFrom :: IORef (Maybe (Vector Float,Camera)) 81 , stDragFrom :: IORef (Maybe (Vector Float,Camera))
82 , stRingBuffer :: Ring
83 , stPenDown :: IORef Bool
56 } 84 }
57 85
58data Camera = Camera 86data Camera = Camera
@@ -111,6 +139,49 @@ mkFullscreenToggle w = do
111 if b then windowFullscreen w 139 if b then windowFullscreen w
112 else windowUnfullscreen w 140 else windowUnfullscreen w
113 141
142data Ring = Ring
143 { ringMax :: Int
144 , ringTexture :: TextureBufferData
145 , ringStart :: IO Int
146 , ringSize :: IO Int
147 , pushBack :: Float -> Float -> Float -> IO ()
148 , popFront :: IO ()
149 }
150
151newRing :: GLStorage -> Int -> IO Ring
152newRing storage cnt = do
153 let ringCapacity = cnt * 3
154 tbo <- uploadTextureBufferToGPU ringCapacity
155 p <- uploadMeshToGPU Mesh
156 { mAttributes = Map.singleton "position" $ A_Float $ V.fromList
157 $ replicate ringCapacity 0.0
158 , mPrimitive = P_Points
159 }
160 obj <- addMeshToObjectArray storage "Points" [] p
161 LC.updateUniforms storage $ do
162 "PointBuffer" @= return tbo
163 rstart <- newIORef 0
164 rsize <- newIORef 0
165 return Ring
166 { ringMax = cnt * 3
167 , ringTexture = tbo
168 , ringStart = readIORef rstart
169 , ringSize = readIORef rsize
170 , pushBack = \x y z -> do
171 start <- readIORef rstart
172 allocaArray 3 $ \ptr -> do
173 pokeElemOff ptr 0 x
174 pokeElemOff ptr 1 y
175 pokeElemOff ptr 2 z
176 updateTextureBuffer tbo start 3 ptr
177 writeIORef rstart (mod (start + 3) ringCapacity)
178 sz <- readIORef rsize
179 putStrLn $ "pushBack "++show (sz,start,(x,y,z))
180 when (sz < ringCapacity) $ do
181 writeIORef rsize (sz + 3)
182 , popFront = modifyIORef' rsize $ \s -> if s > 3 then s - 3 else 0
183 }
184
114uploadState :: IsWidget glarea => MeshData -> glarea -> GLStorage -> IO State 185uploadState :: IsWidget glarea => MeshData -> glarea -> GLStorage -> IO State
115uploadState obj glarea storage = do 186uploadState obj glarea storage = do
116 -- load OBJ geometry and material descriptions 187 -- load OBJ geometry and material descriptions
@@ -122,6 +193,8 @@ uploadState obj glarea storage = do
122 -- grid plane 193 -- grid plane
123 uploadMeshToGPU xzplane >>= addMeshToObjectArray storage "plane" [] 194 uploadMeshToGPU xzplane >>= addMeshToObjectArray storage "plane" []
124 195
196 ring <- newRing storage 100
197
125 -- setup FrameClock 198 -- setup FrameClock
126 w <- toWidget glarea 199 w <- toWidget glarea
127 tm <- newAnimator w 200 tm <- newAnimator w
@@ -146,6 +219,7 @@ uploadState obj glarea storage = do
146 LC.addMeshToObjectArray storage "SkyCube" [] mi 219 LC.addMeshToObjectArray storage "SkyCube" [] mi
147 220
148 drag <- newIORef Nothing 221 drag <- newIORef Nothing
222 pendown <- newIORef False
149 223
150 let st = State 224 let st = State
151 { stAnimator = tm 225 { stAnimator = tm
@@ -155,6 +229,8 @@ uploadState obj glarea storage = do
155 , stSkybox = skybox 229 , stSkybox = skybox
156 , stSkyTexture = skytex 230 , stSkyTexture = skytex
157 , stDragFrom = drag 231 , stDragFrom = drag
232 , stRingBuffer = ring
233 , stPenDown = pendown
158 } 234 }
159 -- _ <- addAnimation tm (whirlingCamera st) 235 -- _ <- addAnimation tm (whirlingCamera st)
160 236
@@ -187,6 +263,8 @@ setUniforms gl storage st = do
187 LC.updateUniforms storage $ do 263 LC.updateUniforms storage $ do
188 "CameraPosition" @= return (pos :: Vector Float) 264 "CameraPosition" @= return (pos :: Vector Float)
189 "ViewProjection" @= return (mvp :: Matrix Float) 265 "ViewProjection" @= return (mvp :: Matrix Float)
266 "PointsStart" @= fmap (fromIntegral :: Int -> Int32) (ringStart $ stRingBuffer st)
267 "PointsMax" @= return (fromIntegral (ringMax $ stRingBuffer st) :: Int32)
190 268
191data MeshSketch = MeshSketch 269data MeshSketch = MeshSketch
192 { mmWidget :: GLArea 270 { mmWidget :: GLArea
@@ -214,10 +292,15 @@ new = do
214 "uvw" @: Attribute_V3F 292 "uvw" @: Attribute_V3F
215 defObjectArray "plane" Triangles $ do 293 defObjectArray "plane" Triangles $ do
216 "position" @: Attribute_V4F 294 "position" @: Attribute_V4F
295 defObjectArray "Points" Points $ do
296 "position" @: Attribute_Float
217 defUniforms $ do 297 defUniforms $ do
298 "PointBuffer" @: FTextureBuffer
218 "CubeMap" @: FTextureCube 299 "CubeMap" @: FTextureCube
219 "CameraPosition" @: V3F 300 "CameraPosition" @: V3F
220 "ViewProjection" @: M44F 301 "ViewProjection" @: M44F
302 "PointsMax" @: Int
303 "PointsStart" @: Int
221 "diffuseTexture" @: FTexture2D 304 "diffuseTexture" @: FTexture2D
222 "diffuseColor" @: V4F 305 "diffuseColor" @: V4F
223 return $ (,) <$> mobj <*> mpipeline 306 return $ (,) <$> mobj <*> mpipeline
@@ -248,6 +331,7 @@ onUnrealize mm = do
248onRealize :: MeshData -> Pipeline -> PipelineSchema -> MeshSketch -> IO () 331onRealize :: MeshData -> Pipeline -> PipelineSchema -> MeshSketch -> IO ()
249onRealize mesh pipeline schema mm = do 332onRealize mesh pipeline schema mm = do
250 onUnrealize mm 333 onUnrealize mm
334 setupGLDebugging
251 storage <- LC.allocStorage schema 335 storage <- LC.allocStorage schema
252 renderer <- LC.allocRenderer pipeline 336 renderer <- LC.allocRenderer pipeline
253 compat <- LC.setStorage renderer storage -- check schema compatibility 337 compat <- LC.setStorage renderer storage -- check schema compatibility
@@ -298,6 +382,8 @@ onResize glarea realized w h = do
298 } 382 }
299 LC.setScreenSize (stStorage realized) wd ht) 383 LC.setScreenSize (stStorage realized) wd ht)
300 384
385-- This computes a point in world coordinates on the view screen if
386-- we assume the camera is located at the origin.
301computeDirection :: Camera -> Double -> Double -> Vector Float 387computeDirection :: Camera -> Double -> Double -> Vector Float
302computeDirection cam h k = 388computeDirection cam h k =
303 let d̂ = camDirection cam -- forward 389 let d̂ = camDirection cam -- forward
@@ -392,49 +478,63 @@ onEvent w realized ev = do
392 case etype of 478 case etype of
393 479
394 EventTypeMotionNotify -> do 480 EventTypeMotionNotify -> do
395 mev <- get ev #motion 481 case inputSource of
396 h <- get mev #x 482 Just InputSourcePen -> do
397 k <- get mev #y 483 isDown <- readIORef (stPenDown st)
398 {- 484 when isDown $ do
399 cam <- readIORef (stCamera st) 485 mev <- get ev #motion
400 {- 486 h <- get mev #x
401 let o = fromList [ camWidth cam / 2, camHeight cam / 2 ] 487 k <- get mev #y
402 r = camHeight cam / (2 * sin (camHeight cam / 2)) 488 cam <- readIORef (stCamera st)
403 489 let d = computeDirection cam h k
404 c = fromList [realToFrac h, realToFrac k] - o :: Vector Float 490 pushBack (stRingBuffer st) (d!0) (d!1) (d!2)
405 d = realToFrac $ norm_2 c 491 put (etype,(h,k),d)
406 τ = asin (d / r) -- angle from center 492 _ -> do
407 axis = fromList [c!1, - (c!0)] :: Vector Float 493 mev <- get ev #motion
408 -} 494 h <- get mev #x
409 let d̂ = camDirection cam -- forward 495 k <- get mev #y
410 û = camUp cam -- upward 496 put (h,k)
411 r̂ = d̂ `cross` û -- rightward 497 updateCameraRotation w st h k
412 x_r = realToFrac h - (camWidth cam / 2) 498 return ()
413 x_u = (camHeight cam / 2) - realToFrac k
414 x_d = (camHeight cam / 2) / tan (camHeightAngle cam / 2)
415 x = fromList [x_r,x_u,x_d]
416 -}
417
418 updateCameraRotation w st h k
419 return ()
420 499
421 EventTypeButtonPress -> do 500 EventTypeButtonPress -> do
422 bev <- get ev #button 501 case inputSource of
423 h <- get bev #x 502 Just InputSourcePen -> do
424 k <- get bev #y 503 writeIORef (stPenDown st) True
425 cam <- readIORef (stCamera st) 504 bev <- get ev #button
426 let d = computeDirection cam h k 505 h <- get bev #x
427 writeIORef (stDragFrom st) $ Just (d,cam) 506 k <- get bev #y
428 put (etype,(h,k),d) 507 cam <- readIORef (stCamera st)
429 return () 508 let d = computeDirection cam h k
509 pushBack (stRingBuffer st) (d!0) (d!1) (d!2)
510 put (etype,(h,k),d)
511 _ -> do
512 bev <- get ev #button
513 h <- get bev #x
514 k <- get bev #y
515 cam <- readIORef (stCamera st)
516 let d = computeDirection cam h k
517 writeIORef (stDragFrom st) $ Just (d,cam)
518 put (etype,(h,k),d)
519 return ()
430 520
431 EventTypeButtonRelease -> do 521 EventTypeButtonRelease -> do
432 bev <- get ev #button 522 case inputSource of
433 h <- get bev #x 523 Just InputSourcePen -> do
434 k <- get bev #y 524 writeIORef (stPenDown st) False
435 updateCameraRotation w st h k 525 bev <- get ev #button
436 sanitizeCamera st 526 h <- get bev #x
437 writeIORef (stDragFrom st) Nothing 527 k <- get bev #y
528 cam <- readIORef (stCamera st)
529 let d = computeDirection cam h k
530 pushBack (stRingBuffer st) (d!0) (d!1) (d!2)
531 _ -> do
532 bev <- get ev #button
533 h <- get bev #x
534 k <- get bev #y
535 updateCameraRotation w st h k
536 sanitizeCamera st
537 writeIORef (stDragFrom st) Nothing
438 538
439 EventTypeScroll -> do 539 EventTypeScroll -> do
440 sev <- get ev #scroll 540 sev <- get ev #scroll