Source

clutter-ocaml / examples / flowers.ml

Full commit
open Clutter

let petal_min = 20.
let petal_var = 40.
let n_flowers = 40

type flower = {
  ctex : ClutterCairo.cairo;
  mutable x : float;
  mutable y : float;
  mutable rot : float;
  v : float;
  rv : float;
}

let colors = [|
  (0.71, 0.81, 0.83); 
  (1.0,  0.78, 0.57);
  (0.64, 0.30, 0.35);
  (0.73, 0.40, 0.39); 
  (0.91, 0.56, 0.64); 
  (0.70, 0.47, 0.45);  
  (0.92, 0.75, 0.60);  
  (0.82, 0.86, 0.85);  
  (0.51, 0.56, 0.67); 
  (1.0, 0.79, 0.58);
|]

let pi = 3.14156
  
let make_flower_actor () =
  let _petal_size = ref (petal_min +. (Random.float petal_var)) in
  let size = int_of_float (!_petal_size *. 8.) in
  let n_groups = 1 + (Random.int 3) in
  let ctex = ClutterCairo.create ~surface_width:size ~surface_height:size () in
  let cr = ctex#new_context in
  Cairo.set_tolerance cr 0.1;
  Cairo.set_operator cr Cairo.OPERATOR_CLEAR;
  Cairo.paint cr;
  Cairo.set_operator cr Cairo.OPERATOR_OVER;
  Cairo.translate cr ((float size) /. 2.) ((float size) /. 2.);

  for i=0 to pred n_groups do
    let petal_size = !_petal_size in
    let n_petals = 4 + (Random.int 5) in
    Cairo.save cr;
    Cairo.rotate cr (Random.float 6.);
    let idx = Random.int (Array.length colors) in
    let red,green,blue = colors.(idx) in
    Cairo.set_source_rgba cr ~red ~green ~blue ~alpha:0.5;
    let pm1 = Random.float 20. and pm2 = Random.float 4. in
    for j=0 to pred n_petals do
      Cairo.save cr;
      Cairo.rotate cr ~angle:(((2. *. pi) /. (float n_petals)) *. (float j));
      Cairo.new_path cr;
      Cairo.move_to cr ~x:0. ~y:0.;
      (*Cairo.move_to cr ~x:petal_size petal_size ~y:((pm2+2)*petal_size)
	(petal_size) ((2*petal_size) + pm1) 0;*)
      Cairo.rel_curve_to cr ~dx1:(pm2*.petal_size) ~dy1:(-.petal_size)
	~dx2:(-.petal_size)
	~dy2:(-.petal_size) ~dx3:((-.2. *. petal_size) +. pm1) ~dy3:0.;
      Cairo.close_path cr;
      Cairo.fill cr;
      Cairo.restore cr;
    done;
    _petal_size := !_petal_size -. (Random.float ((float size)/.8.));
    Cairo.restore cr;
  done;

  let idx = Random.int (Array.length colors) in
  let petal_size = !_petal_size in
  let petal_size = if petal_size < 0. then Random.float 10. else petal_size in
  let red,green,blue = colors.(idx) in
  Cairo.set_source_rgba cr ~red ~green ~blue ~alpha:0.5;
  Cairo.arc cr 0. 0. petal_size 0. (pi *. 2.);
  Cairo.fill cr;
  ctex

let tick flowers =
  let stage = ClutterStage.get_default () in
  for i=0 to pred n_flowers do
    let f = flowers.(i) in
    let fa = f.ctex in
    f.y <- f.y +. f.v;
    f.rot <- f.rot +. f.rv;
    if (f.y > (float stage#height)) then
      f.y <- -.(float stage#height);
    f.ctex#set_position (int_of_float f.x) (int_of_float f.y);
    f.ctex#set_rotation `Z_AXIS f.rot
      (fa#width / 2) (fa#height / 2) 0;
  done;
  true

let _ =
  let stage_color = Color.rgb (0,0,0) in
  let stage = ClutterStage.get_default () in
  stage#set_color stage_color;
  stage#set_fullscreen true;
  let flowers = Array.init n_flowers
    (fun i ->
       let f =
	 { ctex = make_flower_actor ();
	   x = (Random.float (float stage#width)) -. ((petal_min +. petal_var) /. 2.);
	   y = (Random.float (float stage#height));
	   rv = (Random.float 5.) +. 1.;
	   v = (Random.float 10.) +. 2.;
	   rot = 0.;
	 }
       in
       stage#add f.ctex;
       f.ctex#set_position (int_of_float f.x) (int_of_float f.y);
       f
    ) in
  let _ = GMain.Timeout.add 50 (fun _ -> tick flowers) in
  stage#show_all;
  let _ = stage#connect#key_press_event (fun _ -> clutter_quit (); true) in
  clutter_main ()