Page
Library
Module
Module type
Parameter
Class
Class type
Source
Graphv is a real time 2D rendering library for OCaml, supporting both native and web targets. It is based on the NanoVG C library. A live demo can be viewed here. If the fonts don't load, try refreshing the page.
Graphv is a performant pure OCaml 2D vector graphics renderer.
Provides:
conf-gles2
and the web on js_of_ocaml
.Ready to use modules:
Modules for creating a new backend:
Pick a platform implementation:
opam install graphv_gles2_native
for a native GLES2 implementation.opam install graphv_webgl
for a WebGL implementation, for use with Js_of_ocaml.This library does not provide context creation or GUI library support. That will be application depedent. For native contexts glfw
is recommended and can be installed with: opam install glfw-ocaml
For the web Js_of_ocaml should be installed with: opam install js_of_ocaml
Graphv requires a stencil buffer for the OpenGL (and WebGL) backends. Make sure a stencil buffer is present when creating the OpenGL context.
The boilerplate needed depends on the platform you are developing for. In the source code repository there are two examples, one for native and one for web that show sample implementations. These can be found here.
A minimal native application can be made using two extra libraries, tgles2
and glfw-ocaml
. Install these through opam.
(executable
(name main)
(libraries
graphv_gles2_native
glfw-ocaml
tgls.tgles2
)
)
open Tgles2
module NVG = Graphv_gles2_native
let _ =
GLFW.init();
at_exit GLFW.terminate;
GLFW.windowHint ~hint:GLFW.ClientApi ~value:GLFW.OpenGLESApi;
GLFW.windowHint ~hint:GLFW.ContextVersionMajor ~value:2;
GLFW.windowHint ~hint:GLFW.ContextVersionMinor ~value:0;
let window =
GLFW.createWindow ~width:400 ~height:400 ~title:"window" ()
in
GLFW.makeContextCurrent ~window:(Some window);
GLFW.swapInterval ~interval:1;
Gl.clear_color 0.3 0.3 0.32 1.;
let vg = NVG.create
~flags:NVG.CreateFlags.(antialias lor stencil_strokes)
()
in
while not GLFW.(windowShouldClose ~window) do
let win_w, win_h = GLFW.getWindowSize ~window in
Gl.viewport 0 0 win_w win_h;
Gl.clear (
Gl.color_buffer_bit
lor Gl.depth_buffer_bit
lor Gl.stencil_buffer_bit
);
NVG.begin_frame vg
~width:(float win_w)
~height:(float win_h)
~device_ratio:1.
;
NVG.Path.begin_ vg;
NVG.Path.rect vg ~x:40. ~y:40. ~w:320. ~h:320.;
NVG.set_fill_color vg
~color:NVG.Color.(rgba ~r:154 ~g:203 ~b:255 ~a:200);
NVG.fill vg;
NVG.end_frame vg;
GLFW.swapBuffers ~window;
GLFW.pollEvents();
done;
;;
Once compiled the web demo should look like this.
(executable
(name main)
(modes byte js)
(preprocess (pps js_of_ocaml-ppx))
(libraries
graphv_webgl
js_of_ocaml
)
)
open Js_of_ocaml
module NVG = Graphv_webgl
(* This scales the canvas to match the DPI of the window,
it prevents blurriness when rendering to the canvas *)
let scale_canvas (canvas : Dom_html.canvasElement Js.t) =
let dpr = Dom_html.window##.devicePixelRatio in
let rect = canvas##getBoundingClientRect in
let width = rect##.right -. rect##.left in
let height = rect##.bottom -. rect##.top in
canvas##.width := width *. dpr |> int_of_float;
canvas##.height := height *. dpr |> int_of_float;
let width = Printf.sprintf "%dpx" (int_of_float width) |> Js.string in
let height = Printf.sprintf "%dpx" (int_of_float height) |> Js.string in
canvas##.style##.width := width;
canvas##.style##.height := height;
;;
let _ =
let canvas = Js.Unsafe.coerce (Dom_html.getElementById_exn "canvas") in
scale_canvas canvas;
let webgl_ctx =
(* Graphv requires a stencil buffer to work properly *)
let attrs = WebGL.defaultContextAttributes in
attrs##.stencil := Js._true;
match WebGL.getContextWithAttributes canvas attrs
|> Js.Opt.to_option
with
| None ->
print_endline "Sorry your browser does not support WebGL";
raise Exit
| Some ctx -> ctx
in
let open NVG in
let vg = create
~flags:CreateFlags.(antialias lor stencil_strokes)
webgl_ctx
in
(* File in this case is actually the CSS font name *)
Text.create vg ~name:"sans" ~file:"sans" |> ignore;
webgl_ctx##clearColor 0.3 0.3 0.32 1.;
let rec render (time : float) =
webgl_ctx##clear (
webgl_ctx##._COLOR_BUFFER_BIT_
lor webgl_ctx##._DEPTH_BUFFER_BIT_
lor webgl_ctx##._STENCIL_BUFFER_BIT_
);
let device_ratio = Dom_html.window##.devicePixelRatio in
begin_frame vg
~width:(canvas##.width)
~height:(canvas##.height)
~device_ratio
;
Transform.scale vg ~x:device_ratio ~y:device_ratio;
Path.begin_ vg;
Path.rect vg ~x:40. ~y:40. ~w:320. ~h:320.;
set_fill_color vg ~color:Color.(rgba ~r:154 ~g:203 ~b:255 ~a:200);
fill vg;
Transform.translate vg ~x:200. ~y:200.;
Transform.rotate vg ~angle:(time *. 0.0005);
Text.set_font_face vg ~name:"sans";
Text.set_size vg ~size:48.;
Text.set_align vg ~align:Align.(center lor middle);
set_fill_color vg ~color:Color.white;
Text.text vg ~x:0. ~y:0. "Hello World!";
NVG.end_frame vg;
Dom_html.window##requestAnimationFrame (Js.wrap_callback render)
|> ignore;
in
Dom_html.window##requestAnimationFrame (Js.wrap_callback render)
|> ignore;
;;
Don't forget to change the script path to match wherever you are building this project from.
<!DOCTYPE> <html> <head> <style> html, body { width: 100%; height: 100%; overflow: hidden; margin: 0; padding: 0; } div { display: flex; align-items: center; justify-content: center; } canvas { width: 400px; height: 400px; } </style> </head> <body> <div> <canvas id='canvas'></canvas> </div> </body> <script type='text/javascript' defer src='../../_build/default/examples/web_doc/main.bc.js'> </script> </html>