diff options
author | Joe Crayne <joe@jerkface.net> | 2019-05-14 13:32:37 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-05-14 13:32:37 -0400 |
commit | 07ea0fe2a37cab1e549c084f31d231632857b99f (patch) | |
tree | 4e884c2cdf509fa10d35842d5853063b7a56d995 | |
parent | 9f99af1750924a0be6e003842830aec93380dfdc (diff) |
TextureBuffer-based ring buffer.
-rw-r--r-- | MeshSketch.hs | 182 | ||||
-rw-r--r-- | hello_obj2.lc | 32 |
2 files changed, 173 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) | |||
16 | import Data.Map.Strict (Map) | 16 | import Data.Map.Strict (Map) |
17 | import qualified Data.Map.Strict as Map | 17 | import qualified Data.Map.Strict as Map |
18 | import qualified Data.Vector as V | 18 | import qualified Data.Vector as V |
19 | import Foreign.Marshal.Array | ||
20 | import Foreign.Storable | ||
19 | import GI.Gdk | 21 | import GI.Gdk |
20 | import GI.Gdk.Objects | 22 | import GI.Gdk.Objects |
21 | import GI.GLib.Constants | 23 | import GI.GLib.Constants |
@@ -30,9 +32,12 @@ import Control.Exception | |||
30 | import LambdaCube.GL as LC | 32 | import LambdaCube.GL as LC |
31 | import LambdaCube.IR as LC | 33 | import LambdaCube.IR as LC |
32 | import LambdaCube.Gtk | 34 | import LambdaCube.Gtk |
33 | import LambdaCube.GL.Data (uploadCubeMapToGPU) | 35 | import LambdaCube.GL.Data (uploadCubeMapToGPU,uploadTextureBufferToGPU,updateTextureBuffer) |
34 | import LambdaCube.GL.Type (TextureCubeData(..)) | 36 | import LambdaCube.GL.Type (TextureCubeData(..),Object(..)) |
35 | -- import Text.Show.Pretty (ppShow) | 37 | -- import Text.Show.Pretty (ppShow) |
38 | import qualified Graphics.Rendering.OpenGL as GL | ||
39 | import Data.Char | ||
40 | import Text.Printf | ||
36 | 41 | ||
37 | import CubeMap | 42 | import CubeMap |
38 | import GLWidget (nullableContext, withCurrentGL) | 43 | import GLWidget (nullableContext, withCurrentGL) |
@@ -44,6 +49,27 @@ import InfinitePlane | |||
44 | import MtlParser (ObjMaterial(..)) | 49 | import MtlParser (ObjMaterial(..)) |
45 | import Matrix | 50 | import Matrix |
46 | 51 | ||
52 | |||
53 | prettyDebug :: GL.DebugMessage -> String | ||
54 | prettyDebug (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 | |||
63 | setupGLDebugging :: IO () | ||
64 | setupGLDebugging = 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. |
48 | data State = State | 74 | data 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 | ||
58 | data Camera = Camera | 86 | data 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 | ||
142 | data 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 | |||
151 | newRing :: GLStorage -> Int -> IO Ring | ||
152 | newRing 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 | |||
114 | uploadState :: IsWidget glarea => MeshData -> glarea -> GLStorage -> IO State | 185 | uploadState :: IsWidget glarea => MeshData -> glarea -> GLStorage -> IO State |
115 | uploadState obj glarea storage = do | 186 | uploadState 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 | ||
191 | data MeshSketch = MeshSketch | 269 | data 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 | |||
248 | onRealize :: MeshData -> Pipeline -> PipelineSchema -> MeshSketch -> IO () | 331 | onRealize :: MeshData -> Pipeline -> PipelineSchema -> MeshSketch -> IO () |
249 | onRealize mesh pipeline schema mm = do | 332 | onRealize 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. | ||
301 | computeDirection :: Camera -> Double -> Double -> Vector Float | 387 | computeDirection :: Camera -> Double -> Double -> Vector Float |
302 | computeDirection cam h k = | 388 | computeDirection 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 |
diff --git a/hello_obj2.lc b/hello_obj2.lc index 991c3c2..8e9bbe0 100644 --- a/hello_obj2.lc +++ b/hello_obj2.lc | |||
@@ -19,6 +19,8 @@ makeFrame (cubemap :: TextureCube) | |||
19 | (texture :: Texture) | 19 | (texture :: Texture) |
20 | (prims :: PrimitiveStream Triangle (Vec 4 Float, Vec 3 Float, Vec 3 Float)) | 20 | (prims :: PrimitiveStream Triangle (Vec 4 Float, Vec 3 Float, Vec 3 Float)) |
21 | (plane :: PrimitiveStream Triangle ((Vec 4 Float))) | 21 | (plane :: PrimitiveStream Triangle ((Vec 4 Float))) |
22 | (pointsMax :: Int) | ||
23 | (pointsStart :: Int) | ||
22 | 24 | ||
23 | = imageFrame (emptyDepthImage 1, emptyColorImage (V4 0 0 0.4 1)) | 25 | = imageFrame (emptyDepthImage 1, emptyColorImage (V4 0 0 0.4 1)) |
24 | `overlay` | 26 | `overlay` |
@@ -43,6 +45,34 @@ makeFrame (cubemap :: TextureCube) | |||
43 | r = V4 1 1 1 0 *! (max c%x c%y) | 45 | r = V4 1 1 1 0 *! (max c%x c%y) |
44 | in ((r + V4 0 0 0 (0.8)))) | 46 | in ((r + V4 0 0 0 (0.8)))) |
45 | & accumulateWith (DepthOp Less True, ColorOp blendplane (V4 True True True True)) | 47 | & accumulateWith (DepthOp Less True, ColorOp blendplane (V4 True True True True)) |
48 | `overlay` | ||
49 | zipCount (fetch "Points" ((Attribute "position")) :: PrimitiveStream Point ((Float))) | ||
50 | & mapPrimitives (\(n,_) -> {- let nn = 0.2 * fromInt n :: Float | ||
51 | p = V4 nn nn nn 1 | ||
52 | p' = coordmap cam p | ||
53 | in (p', V4 1 1 0 1 :: Vec 4 Float)) -} | ||
54 | let i = mod (n + pointsStart) pointsMax | ||
55 | t = TextureBufferSlot "PointBuffer" | ||
56 | p = V4 (textureBuffer t i) | ||
57 | (textureBuffer t (i+1)) | ||
58 | (textureBuffer t (i+2)) | ||
59 | 1 | ||
60 | p' = coordmap cam p | ||
61 | in (p', V4 1 1 0 1 :: Vec 4 Float)) | ||
62 | |||
63 | & renderPoints cam | ||
64 | |||
65 | |||
66 | renderPoints :: | ||
67 | Mat 4 4 Float | ||
68 | -> PrimitiveStream Point (Vec 4 Float, Vec 4 Float) | ||
69 | -> ( (FragmentOperation Depth, FragmentOperation (Color (VecScalar 4 Float))) | ||
70 | , FragmentStream 1 ((Vec 4 Float)) ) | ||
71 | renderPoints cam points = | ||
72 | points | ||
73 | & rasterizePrimitives (PointCtx (PointSize 10.0) 1.0 LowerLeft) ((Flat)) | ||
74 | & mapFragments (\((c)) -> ((c))) | ||
75 | & accumulateWith (DepthOp Always False, ColorOp NoBlending (V4 True True True True)) | ||
46 | 76 | ||
47 | textureCubeSlot s = TextureCubeSlot s | 77 | textureCubeSlot s = TextureCubeSlot s |
48 | 78 | ||
@@ -56,4 +86,6 @@ main = renderFrame $ | |||
56 | (Texture2DSlot "diffuseTexture") | 86 | (Texture2DSlot "diffuseTexture") |
57 | (fetch "objects" (Attribute "position", Attribute "normal", Attribute "uvw")) | 87 | (fetch "objects" (Attribute "position", Attribute "normal", Attribute "uvw")) |
58 | (fetch "plane" ((Attribute "position"))) | 88 | (fetch "plane" ((Attribute "position"))) |
89 | (Uniform "PointsMax") | ||
90 | (Uniform "PointsStart") | ||
59 | 91 | ||