Intermediate Demo


The executables require OpenGL.


The vector scene consists of two shapes. The first shape is an S-shaped curve stroked with an elliptic nib. The second shape is from the first demo but with a transparent crystal-blue stroke.

Stroking with an elliptic nib can be achieved using only a few lines of code with Smoke. Unlike conventional vector graphics, Smoke applies transforms after stroking, allowing a wider range of effects and facilitating hardware-accelerated transformations. In this case, a skew transform is applied to the cirved contour before stroking and a transform node in the scene graph unskews the stroked contour, giving the appearance of stroking with an elliptic nib (a skewed circle).

All this functionality is achieved in only 35 lines of OCaml code:

open Graphics2D

The style and geometry definitions relating to the first object are encapsulated by nesting the definitions inside the definition of obj1:

let obj1 =

First, we define the skew matrix:

  let m = mat2 1. 0. 0.5 1. 0. 0. in

Then we define an open-ended contour and skew it (by inverse m) before stroking, to produce the skewed skeleton of the S-shape:

  let contour =
    (move_to (-2.) (-2.), [curve_to (-1.) (-3.) 1. (-3.) 2. (-2.);
                           curve_to 4. 0. (-4.) 0. (-2.) 2.;
                           curve_to (-1.) 3. 1. 3. 2. 2.]) |>
    Contour.make |>
    Contour.trans (inverse m) in
  let geo = ContourGeometry.of_contours [contour] in

We define the fill color and stroke style of the S-shape:

  let blue = Fill.color 0. 0.25 1. 1. in

  let stroke = Style.stroke ~endcaps:(`Round, `Round) 1. in

Finally, the S-shape is created as a tranformation node (with the skew matrix m) applied to a vector shape:

  transform m (Shape([Fill.flat blue, stroke], geo))

The second object is created the same way as before (in the first demo), except that the fill is a translucent color with an α-value of ½:

let obj2 =
  let geo =
    [Contour.Closed, [curve_to (-0.8) 0. (-0.8) 0. (-1.) 1.;
                      line_to 1. 1.;
                      curve_to 0.8 0. 0.8 0. 1. (-1.);
                      line_to (-1.) (-1.)]] |>
    ContourGeometry.make in

  let styles =
    let highlight =
      let r1 = vec2 0.4 0.5 and r2 = vec2 0.6 0.7 and r3 = vec2 0.1 0.8 in
      Fill.radial r1 r2 r3 Fill.white Fill.clear in

    let clear_blue = Fill.make 0. 0.5 1. 0.5 in

    let fill = Style.Interior `Odd in

    let stroke = Style.stroke ~joins:`Round 0.2 in

    [Fill.flat, fill; highlight, fill; clear_blue, stroke] in

  Shape(styles, geo)

Generation of the animated scene graph is encapsulated in a single function that uses the current time:

let scene() = Group [|obj1; transform (time() |> rot) obj2|]

The portal is initialized with a suitable viewing area:

let portal = {view=Some(vec2 (-3.5) (-3.5), vec2 3.5 3.5); scene=scene()}

Once again, the paint event is used to update the scene graph:

let () =
  let on_paint = Event.create() in
  Event.add (fun () -> portal.scene <- scene()) on_paint;
  GUI.spawn ~on_paint portal

This program is more complicated than the first demo but still does not use the feedback features of our library to put vector scenes under user control. Feedback is used in the next demo.


This example program may be compiled using our library with:

$ ocamlopt -I +camlimages -I +lablGL ci_core.cmxa ci_freetype.cmxa lablgl.cmxa lablglut.cmxa unix.cmxa
  graphics2D.cmxa -o demo2

(Note: We are not VAT registered and, therefore, cannot provide VAT receipts)

Mastercard VISA VISA Delta VISA Electron VISA Purchasing JCB Solo Switch