-- Here we specify the OpenGL code to draw the nodes, and where the ports of the nodes are positioned, which is needed for the layouting. module GL () where import Graph import GraphRewriting.Layout.PortSpec import qualified Graphics.UI.GLUT as GL import GraphRewriting.GL.Render -- Here we specify for each node type the position of its ports and the direction an edge attached to the port is to be oriented. Here we only use the 'sameDir' function that orients the edge in the same direction as the port, i.e. if the (only) port of the root node type (R) is south, also the edge attached to the port is to point south. instance PortSpec SKI where portSpec node = let sd = sameDir in case node of R {} → [sd s] A {} → [sd n, sd (sw*0.7), sd (se*0.7)] I {} → [sd n] E {} → [sd s] D {} → [sd nw, sd ne, sd s] V {} → [sd n] K0 {} → [sd n] K1 {} → [sd n, sd s] S0 {} → [sd n] S1 {} → [sd n, sd s] S2 {} → [sd n, sd (sw*0.7), sd (se*0.7)] where -- points of compass n = Vector2 0 1 w = Vector2 (-1) 0 e = Vector2 1 0 s = Vector2 0 (-1) sw = Vector2 (-1) (-1) se = Vector2 1 (-1) nw = Vector2 (-1) 1 ne = Vector2 1 1 -- Here we specify the OpenGL code that draws a node. Refer to the documentation of the OpenGL and GLUT packages on how to do this. instance Render SKI where render = renderNode renderNode R {} = return () renderNode node = drawPorts node >> case node of A {} → drawNode "A" I {} → drawNode "I" E {} → drawNode "E" D {} → GL.preservingMatrix $ GL.renderPrimitive GL.LineLoop $ do vertex2 (0,-1) vertex2 (-1,1) vertex2 (1,1) V {name = n} → drawNode n K0 {} → drawNode "K" K1 {} → drawNode "K" S0 {} → drawNode "S" S1 {} → drawNode "S" S2 {} → drawNode "S" drawPorts ∷ SKI -> IO () drawPorts = mapM_ drawPort . relPortPos circle r1 r2 step = mapM_ vertex2 vs where is = take (truncate step + 1) [0, i' .. ] i' = 2 * pi / step vs = [ (r1 * cos i, r2 * sin i) | i <- is ] drawPort pos = GL.preservingMatrix $ do GL.translate $ vector pos GL.renderPrimitive GL.Polygon (circle 0.15 0.15 10) drawNode label = do GL.renderPrimitive GL.LineLoop (circle 1 1 20) drawString label drawString label = GL.preservingMatrix $ do GL.translate $ vector2 (-0.3,-0.3) GL.scale 0.0065 0.0065 (0 ∷ GL.GLdouble) GL.renderString GL.MonoRoman label -- Now you can see in Main.hs how it all is tied together to make an actual graphical application out of this.