diff options
author | Joe Crayne <joe@jerkface.net> | 2019-06-17 17:33:18 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-06-17 17:33:18 -0400 |
commit | 40b339a401a82610d16601e9a1ce34af9b159d56 (patch) | |
tree | 61fb201151db692e9fc50c9b369f251fd27a53d0 | |
parent | de867b10f2a3645fd7f42efc6389013fa8ad62f5 (diff) |
Maskable materials.
-rw-r--r-- | Mask.hs | 63 | ||||
-rw-r--r-- | MeshSketch.hs | 64 | ||||
-rw-r--r-- | lambda-gtk.cabal | 2 |
3 files changed, 111 insertions, 18 deletions
@@ -0,0 +1,63 @@ | |||
1 | module Mask where | ||
2 | |||
3 | import Data.Int | ||
4 | |||
5 | newtype Mask = Mask [(Int32,Int32)] | ||
6 | deriving (Eq,Ord,Show) | ||
7 | |||
8 | {- | ||
9 | merge ((x0,x):xs) ((y0,y):ys) = | ||
10 | if x0 <= y0 | ||
11 | then case compare x y0 of | ||
12 | LT -> (x0 x) (y0 y) | ||
13 | EQ -> (x0 x=y0 y) | ||
14 | GT -> if x <= y then -> (x0 y0 x y) | ||
15 | else -> (x0 y0 y x) | ||
16 | else case compare x0 y of | ||
17 | LT -> if x <= y then (y0 x0 x y) | ||
18 | else (y0 x0 y x) | ||
19 | EQ -> (y0 y=x0 x) | ||
20 | GT -> (y0 y) (x0 x) | ||
21 | -} | ||
22 | |||
23 | subtr [] ys = [] | ||
24 | subtr xs [] = xs | ||
25 | subtr ((x0,x):xs) ((y0,y):ys) = | ||
26 | if x0 <= y0 | ||
27 | then case compare x y0 of | ||
28 | LT -> subtr ((x0,x):xs) ys | ||
29 | EQ -> (x0,x) : subtr xs ((y0,y):ys) | ||
30 | GT -> if x <= y then (if x0<y0 then ((x0,y0) :) else id) $ subtr xs ((y0,y):ys) | ||
31 | else (if x0<y0 then ((x0,y0) :) else id) $ subtr ((y,x):xs) ys | ||
32 | else case compare x0 y of | ||
33 | LT -> if x <= y then subtr xs ((y0,y):ys) | ||
34 | else subtr ((y,x):xs) ys | ||
35 | EQ -> subtr ((x0,x):xs) ys | ||
36 | GT -> subtr ((x0,x):xs) ys | ||
37 | |||
38 | union [] ys = ys | ||
39 | union xs [] = xs | ||
40 | union ((x0,x):xs) ((y0,y):ys) = | ||
41 | if x0 <= y0 | ||
42 | then case compare x y0 of | ||
43 | LT -> (x0,x) : union xs ((y0,y):ys) | ||
44 | EQ -> (x0,y) : union xs ys | ||
45 | GT -> if x <= y then union xs ((x0,y):ys) | ||
46 | else union ((x0,x):xs) ys | ||
47 | else case compare x0 y of | ||
48 | LT -> if x <= y then union xs ((y0,y):ys) | ||
49 | else union ((y0,x):xs) ys | ||
50 | EQ -> (y0,x) : union xs ys | ||
51 | GT -> (y0,y) : union ((x0,x):xs) ys | ||
52 | |||
53 | endpts :: (Int32,Int32) -> (Int32,Int32) | ||
54 | endpts (x0,sz) = (x0,x0 + sz) | ||
55 | |||
56 | sized :: (Int32,Int32) -> (Int32,Int32) | ||
57 | sized (x0,x) = (x0, x - x0) | ||
58 | |||
59 | maskPlus :: Mask -> Mask -> Mask | ||
60 | maskPlus (Mask xs) (Mask ys) = Mask $ sized <$> union (endpts <$> xs) (endpts <$> ys) | ||
61 | |||
62 | maskSubtract :: Mask -> Mask -> Mask | ||
63 | maskSubtract (Mask xs) (Mask ys) = Mask $ sized <$> subtr (endpts <$> xs) (endpts <$> ys) | ||
diff --git a/MeshSketch.hs b/MeshSketch.hs index 7ab0d7a..f31c7cf 100644 --- a/MeshSketch.hs +++ b/MeshSketch.hs | |||
@@ -66,11 +66,12 @@ import Matrix | |||
66 | import qualified GPURing as GPU | 66 | import qualified GPURing as GPU |
67 | import qualified VectorRing as Vector | 67 | import qualified VectorRing as Vector |
68 | import RingBuffer | 68 | import RingBuffer |
69 | import MaskableStream (AttributeKey,(@<-)) | 69 | import MaskableStream (AttributeKey,(@<-),updateCommands) |
70 | import SmallRing | 70 | import SmallRing |
71 | import Camera | 71 | import Camera |
72 | import FitCurves | 72 | import FitCurves |
73 | import Bezier | 73 | import Bezier |
74 | import Mask | ||
74 | 75 | ||
75 | prettyDebug :: GL.DebugMessage -> String | 76 | prettyDebug :: GL.DebugMessage -> String |
76 | prettyDebug (GL.DebugMessage src typ (GL.DebugMessageID mid) severity msg) = unwords ws | 77 | prettyDebug (GL.DebugMessage src typ (GL.DebugMessageID mid) severity msg) = unwords ws |
@@ -113,6 +114,8 @@ data State = State | |||
113 | , stDragPlane :: IORef (Maybe (Vector Float,Plane)) | 114 | , stDragPlane :: IORef (Maybe (Vector Float,Plane)) |
114 | , stRecentPts :: IORef (Giver (Vector Double)) | 115 | , stRecentPts :: IORef (Giver (Vector Double)) |
115 | , stAngle :: IORef Int | 116 | , stAngle :: IORef Int |
117 | , stObjects :: IORef [MaskableObject] | ||
118 | , stMasks :: IORef [Mask] | ||
116 | } | 119 | } |
117 | 120 | ||
118 | initCamera :: Camera | 121 | initCamera :: Camera |
@@ -138,9 +141,14 @@ realToFracVector v = Math.fromList $ map realToFrac $ Math.toList v | |||
138 | 141 | ||
139 | data MaskableObject = MaskableObject | 142 | data MaskableObject = MaskableObject |
140 | { maskableObject :: LC.Object | 143 | { maskableObject :: LC.Object |
141 | , groupMasks :: Map Text [(Int32,Int32)] | 144 | , groupMasks :: Map Text Mask |
142 | } | 145 | } |
143 | 146 | ||
147 | objSpan :: LC.Object -> Mask | ||
148 | objSpan obj = case Map.elems (objAttributes obj) of | ||
149 | Stream { streamLength = x }:_ -> Mask [(0,fromIntegral x)] | ||
150 | _ -> Mask [(0,1)] | ||
151 | |||
144 | addOBJToObjectArray :: GLStorage -> String -> [(GPUMesh, Maybe Text)] -> Map Text (ObjMaterial,TextureData) | 152 | addOBJToObjectArray :: GLStorage -> String -> [(GPUMesh, Maybe Text)] -> Map Text (ObjMaterial,TextureData) |
145 | -> IO [MaskableObject] | 153 | -> IO [MaskableObject] |
146 | addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \(mesh,mat) -> do | 154 | addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \(mesh,mat) -> do |
@@ -151,10 +159,7 @@ addOBJToObjectArray storage slotName objMesh mtlLib = forM objMesh $ \(mesh,mat) | |||
151 | Just (ObjMaterial{..},t) -> LC.updateObjectUniforms obj $ do | 159 | Just (ObjMaterial{..},t) -> LC.updateObjectUniforms obj $ do |
152 | "diffuseTexture" @= return t -- set model's diffuse texture | 160 | "diffuseTexture" @= return t -- set model's diffuse texture |
153 | "diffuseColor" @= let (r,g,b) = mtl_Kd in return (V4 r g b mtl_Tr) | 161 | "diffuseColor" @= let (r,g,b) = mtl_Kd in return (V4 r g b mtl_Tr) |
154 | let len = case Map.elems (objAttributes obj) of | 162 | return $ MaskableObject obj $ maybe Map.empty (`Map.singleton` objSpan obj) mat |
155 | Stream { streamLength = x }:_ -> x | ||
156 | _ -> 1 | ||
157 | return $ MaskableObject obj $ maybe Map.empty (`Map.singleton` [(0,1)]) mat | ||
158 | 163 | ||
159 | mkFullscreenToggle :: IsWindow a => a -> IO (IO ()) | 164 | mkFullscreenToggle :: IsWindow a => a -> IO (IO ()) |
160 | mkFullscreenToggle w = do | 165 | mkFullscreenToggle w = do |
@@ -182,6 +187,8 @@ uploadState obj mm storage = do | |||
182 | let gs = Map.keys $ foldr (\a ms -> Map.union (groupMasks a) ms) Map.empty bufs | 187 | let gs = Map.keys $ foldr (\a ms -> Map.union (groupMasks a) ms) Map.empty bufs |
183 | forM_ gs $ \groupname -> do | 188 | forM_ gs $ \groupname -> do |
184 | addToGroupsPane (mmListStore mm) True groupname | 189 | addToGroupsPane (mmListStore mm) True groupname |
190 | objsRef <- newIORef bufs | ||
191 | masksRef <- newIORef $ map (objSpan . maskableObject) bufs | ||
185 | 192 | ||
186 | -- grid plane | 193 | -- grid plane |
187 | uploadMeshToGPU xzplane >>= addMeshToObjectArray storage "plane" [] | 194 | uploadMeshToGPU xzplane >>= addMeshToObjectArray storage "plane" [] |
@@ -239,6 +246,8 @@ uploadState obj mm storage = do | |||
239 | , stDragPlane = dragPlane | 246 | , stDragPlane = dragPlane |
240 | , stRecentPts = recentPts | 247 | , stRecentPts = recentPts |
241 | , stAngle = angle | 248 | , stAngle = angle |
249 | , stObjects = objsRef | ||
250 | , stMasks = masksRef | ||
242 | } | 251 | } |
243 | -- _ <- addAnimation tm (whirlingCamera st) | 252 | -- _ <- addAnimation tm (whirlingCamera st) |
244 | 253 | ||
@@ -336,17 +345,15 @@ new = do | |||
336 | either (\e _ -> hPutStrLn stderr e >> throwIO (userError e)) (&) m $ \(obj,pipeline) -> do | 345 | either (\e _ -> hPutStrLn stderr e >> throwIO (userError e)) (&) m $ \(obj,pipeline) -> do |
337 | mapM_ (putStrLn . ppShow) (targets $ dynamicPipeline pipeline) | 346 | mapM_ (putStrLn . ppShow) (targets $ dynamicPipeline pipeline) |
338 | ref <- newIORef Nothing | 347 | ref <- newIORef Nothing |
339 | (groups,liststore) <- newGroupsListWidget | 348 | g <- gLAreaNew |
349 | (groups,liststore) <- newGroupsListWidget (\store itr b -> onMaskedGroup g ref store itr b) | ||
340 | panes <- panedNew OrientationHorizontal | 350 | panes <- panedNew OrientationHorizontal |
341 | g <- do | 351 | let mm = MeshSketch g panes groups liststore ref |
342 | g <- gLAreaNew | 352 | gLAreaSetHasDepthBuffer g True |
343 | let mm = MeshSketch g panes groups liststore ref | 353 | st <- return g |
344 | gLAreaSetHasDepthBuffer g True | 354 | _ <- on g #realize $ withCurrentGL g (onRealize obj (dynamicPipeline pipeline) (dynamicSchema pipeline) mm) |
345 | st <- return g | 355 | _ <- on g #unrealize $ onUnrealize mm |
346 | _ <- on g #realize $ withCurrentGL g (onRealize obj (dynamicPipeline pipeline) (dynamicSchema pipeline) mm) | 356 | _ <- on g #createContext $ nullableContext (onCreateContext g) |
347 | _ <- on g #unrealize $ onUnrealize mm | ||
348 | _ <- on g #createContext $ nullableContext (onCreateContext g) | ||
349 | return g | ||
350 | panedPack1 panes g True True | 357 | panedPack1 panes g True True |
351 | return panes | 358 | return panes |
352 | 359 | ||
@@ -357,7 +364,7 @@ addToGroupsPane liststore isEnabled groupName = do | |||
357 | iter <- listStoreAppend liststore | 364 | iter <- listStoreAppend liststore |
358 | listStoreSet liststore iter [0,1] [gtrue,gvalue] | 365 | listStoreSet liststore iter [0,1] [gtrue,gvalue] |
359 | 366 | ||
360 | newGroupsListWidget = do | 367 | newGroupsListWidget changedListStore = do |
361 | liststore <- listStoreNew [gtypeBoolean,gtypeString] | 368 | liststore <- listStoreNew [gtypeBoolean,gtypeString] |
362 | treeView <- treeViewNewWithModel liststore | 369 | treeView <- treeViewNewWithModel liststore |
363 | treeViewSetHeadersVisible treeView False | 370 | treeViewSetHeadersVisible treeView False |
@@ -379,6 +386,7 @@ newGroupsListWidget = do | |||
379 | b <- fromGValue gval | 386 | b <- fromGValue gval |
380 | notb <- toGValue (not b) | 387 | notb <- toGValue (not b) |
381 | listStoreSetValue liststore itr 0 notb | 388 | listStoreSetValue liststore itr 0 notb |
389 | changedListStore liststore itr (not b) | ||
382 | return togc | 390 | return togc |
383 | groupc <- do | 391 | groupc <- do |
384 | groupr <- cellRendererTextNew | 392 | groupr <- cellRendererTextNew |
@@ -876,3 +884,25 @@ onCreateContext w = do | |||
876 | putStrLn "onCreateContext!" | 884 | putStrLn "onCreateContext!" |
877 | mwin <- widgetGetWindow w | 885 | mwin <- widgetGetWindow w |
878 | forM mwin $ \win -> windowCreateGlContext win | 886 | forM mwin $ \win -> windowCreateGlContext win |
887 | |||
888 | onMaskedGroup g ref store itr b = do | ||
889 | gval <- treeModelGetValue store itr 1 | ||
890 | mtxt <- fromGValue gval | ||
891 | let _ = mtxt :: Maybe Text | ||
892 | putStrLn $ "Mask changed " ++ show (mtxt,b) | ||
893 | mr <- readIORef ref | ||
894 | forM_ ((,) <$> mr <*> mtxt) $ \(r,txt) -> do | ||
895 | let st = stState r | ||
896 | os <- readIORef (stObjects st) -- stObjects :: IORef [MaskableObject] | ||
897 | ms <- readIORef (stMasks st) -- stMasks :: IORef [Mask] | ||
898 | ms' <- forM (zip os ms) $ \(o,m) -> do | ||
899 | let mmask = Map.lookup txt (groupMasks o) | ||
900 | op = maybe id (flip $ bool maskSubtract maskPlus b) mmask | ||
901 | m' = op m | ||
902 | unmask (Mask is) = is | ||
903 | updateCommands (stStorage r) (maskableObject o) (const $ unmask m') | ||
904 | return m' | ||
905 | writeIORef (stMasks st) ms' | ||
906 | mwin <- widgetGetWindow g | ||
907 | forM_ mwin $ \win -> windowInvalidateRect win Nothing False | ||
908 | return () | ||
diff --git a/lambda-gtk.cabal b/lambda-gtk.cabal index 75bcdfc..08e9ff2 100644 --- a/lambda-gtk.cabal +++ b/lambda-gtk.cabal | |||
@@ -50,7 +50,7 @@ executable meshsketch | |||
50 | other-modules: InfinitePlane LambdaCubeWidget GLWidget LambdaCube.Gtk TimeKeeper | 50 | other-modules: InfinitePlane LambdaCubeWidget GLWidget LambdaCube.Gtk TimeKeeper |
51 | LoadMesh MtlParser Matrix LambdaCube.GL.HMatrix | 51 | LoadMesh MtlParser Matrix LambdaCube.GL.HMatrix |
52 | Animator MeshSketch CubeMap AttributeData GPURing MaskableStream | 52 | Animator MeshSketch CubeMap AttributeData GPURing MaskableStream |
53 | RingBuffer SmallRing VectorRing Camera Bezier FitCurves | 53 | RingBuffer SmallRing VectorRing Camera Bezier FitCurves Mask |
54 | extensions: NondecreasingIndentation | 54 | extensions: NondecreasingIndentation |
55 | other-extensions: OverloadedLabels, OverloadedLists, OverloadedStrings | 55 | other-extensions: OverloadedLabels, OverloadedLists, OverloadedStrings |
56 | build-depends: base, containers >=0.5 && <0.6, bytestring >=0.10 && <0.11, | 56 | build-depends: base, containers >=0.5 && <0.6, bytestring >=0.10 && <0.11, |