anchor.diff:              [ 
                   "divide", toEffect Shader.gs0
                   "shrink", toEffect Shader.gs1 
  +                "extrude", toEffect Shader.extrude
  +                "invert", toEffect Shader.gs2
               ]
   
           let combinations = 
               all available
                   |> List.sortBy List.length
                   |> List.map (fun l ->
  -                    let name = l |> List.map fst |> String.concat ", " |> sprintf "{ %s }"
  +                    let name = 
  +                        match l |> List.map fst with
  +                            | [] -> "empty"
  +                            | list -> list |> String.concat ", " |> sprintf "[ %s ]"
                       let effect = l |> List.map snd |> FShade.Effect.compose
                       name, effect
                   )
  +                |> List.toArray
  +
  +        let w = ceil (sqrt (float combinations.Length)) |> int
  +        let h = ceil (float combinations.Length / float w) |> int
   
           let font = Font("Consolas")
   
           win.RenderTask <-
               Sg.ofList [
  -                let mutable index = 0
  -                for (name, effect) in combinations do
  -
  -                    let label = 
  -                        Sg.text font C4b.White (Mod.constant name)
  -                            |> Sg.transform (Trafo3d.FromBasis(V3d.IOO, V3d.OOI, V3d.OIO, V3d.Zero) * Trafo3d.Scale(0.1))
  -                            |> Sg.translate 0.0 0.0 1.5
  -
  -                    let inner = 
  -                        Sg.box' C4b.Red Box3d.Unit
  -                            |> Sg.shader {
  -                                do! DefaultSurfaces.trafo
  -                                do! effect
  -                                do! DefaultSurfaces.vertexColor
  -                                do! DefaultSurfaces.simpleLighting
  -                            }
  -
  -                    yield 
  -                        Sg.ofList [
  -                            inner
  -                                |> Sg.cullMode (Mod.constant CullMode.Clockwise)
  -
  -                            inner
  -                                |> Sg.translate 0.0 0.0 -1.5
  -                                |> Sg.fillMode (Mod.constant FillMode.Line)
  -                                |> Sg.cullMode (Mod.constant CullMode.Clockwise)
  -                            label
  -                        ]
  -                        |> Sg.translate (1.5 * float index) 0.0 0.0
  -
  -                    index <- index + 1
  +                for i in 0 .. w - 1 do
  +                    for j in 0 .. h - 1 do
  +                        let id = i * h + j
  +                        if id < combinations.Length then
  +                            let (name, effect) = combinations.[id]
  +     
  +                            let label = 
  +                                Sg.text font C4b.White (Mod.constant name)
  +                                    |> Sg.transform (Trafo3d.FromBasis(V3d.IOO, V3d.OOI, V3d.OIO, V3d.Zero) * Trafo3d.Scale(0.1))
  +                                    |> Sg.translate 0.0 0.0 1.5
  +
  +                            let inner = 
  +                                Sg.box' C4b.Red Box3d.Unit
  +                                    |> Sg.shader {
  +                                        do! DefaultSurfaces.trafo
  +                                        do! effect
  +                                        do! Shader.withLightDir
  +                                        do! DefaultSurfaces.constantColor C4f.Red
  +                                        do! DefaultSurfaces.stableHeadlight
  +                                        //do! DefaultSurfaces.simpleLighting
  +                                    }
  +
  +                            yield 
  +                                Sg.ofList [
  +                                    inner
  +                                        |> Sg.cullMode (Mod.constant CullMode.Clockwise)
  +
  +                                    label
  +                                ]
  +                                |> Sg.translate (2.0 * float i) 0.0 (-2.0 * float j)
  +
               ]
               //|> Sg.fillMode (Mod.constant FillMode.Line)
               |> Sg.viewTrafo viewTrafo
  
positive.code:                 yield { v.P1 with p = uniform.ViewProjTrafo * b; wp = b } 
                  yield { v.P2 with p = uniform.ViewProjTrafo * c; wp = c } 
  
              }
  
      let run() =
  
negative.code:     module Shader =
          open FShade
  
          type Vertex = { [<Position>] p : V4d; [<WorldPosition>] wp : V4d; [<Color>] c : V4d; [<Normal>] n : V3d; [<Semantic("LightDir")>] ldir : V3d }
  
          let gs0 (v : Triangle<Vertex>) =
              triangle {
                  
                  let cc = v.P0.c
                  let n = v.P0.n
                  let cp = (v.P0.wp + v.P1.wp + v.P2.wp) / 3.0
                  //let cc = (v.P0.c + v.P1.c + v.P2.c) / 3.0
  
  
                  // 0 1 c   c 1 2   c 2 3
                  yield { v.P0 with c = cc; n = n }
                  yield { v.P1 with c = cc; n = n }
                  yield { p = uniform.ViewProjTrafo * cp; wp = cp; c = cc; n = n; ldir = V3d.Zero}
                  yield { v.P2 with c = cc; n = n }
                  yield { v.P0 with c = cc; n = n }
  //                restartStrip()
  //                
  //                yield { p = uniform.ViewProjTrafo * cp; wp = cp; c = V4d.OIOI; n = n; ldir = V3d.Zero }
  //                yield { v.P1 with c = V4d.OIOI; n = n }
  //                yield { v.P2 with c = V4d.OIOI; n = n }
  //                restartStrip()
  //                
  //                yield { v.P2 with c = V4d.OOII; n = n }
  //                yield { v.P0 with c = V4d.OOII; n = n }
  //                yield { p = uniform.ViewProjTrafo * cp; wp = cp; c = V4d.OOII; n = n; ldir = V3d.Zero }
  
              }
  
  