open Bigarray

type location_t = {mutable x: float; mutable y: float; 
                   mutable dx: float; mutable dy: float;
                   width: int; height: int; offset: float};;

let bobR = 20;;
let bobR2 = bobR * bobR;;
let locations = [{x = float(bobR); y = float(bobR + 5);
                dx = 3.; dy = 1.5; 
                width = 256; height = 227; offset = 0.};
                {x = float(255 - bobR); y = float(227 - (bobR + 5));
                dx = 3.; dy = 1.5; 
                width = 256; height = 227; offset = 0.25};
                {x = float(bobR); y = float(bobR + 174);
                dx = 1.1; dy = 3.; 
                width = 256; height = 227; offset = 0.5};
                {x = float(255 - bobR); y = float(128 - (bobR + 5));
                dx = 1.8; dy = 3.; 
                width = 256; height = 227; offset = 0.75}];;

let updateLocation loc =
  loc.x <- loc.x +. loc.dx;
  loc.y <- loc.y +. loc.dy;
  let fw = float(loc.width - bobR) in
  let fh = float(loc.height - bobR) in
  let fr = float(bobR) in
    if loc.x >= fw then (
      loc.dx <- -.loc.dx;
      loc.x <- 2. *. fw -. loc.x -. 1.;
    );
    if loc.y >= fh then (
      loc.dy <- -.loc.dy;
      loc.y <- 2. *. fh -. loc.y -. 1.;
    );
    if loc.x < fr then (
      loc.dx <- -.loc.dx;
      loc.x <- 2. *. fr -.loc.x;
    );
    if loc.y < fr then (
      loc.dy <- -.loc.dy;
      loc.y <- 2. *. fr -.loc.y;
    );;

let drawBob (array, loc, (r, g, b)) =
  let x0 = truncate loc.x in
  let y0 = truncate loc.y in 
    for dx = -bobR to bobR do
      for dy = -bobR to bobR do
        if (dx * dx + dy * dy <= bobR2) then 
          let x = x0 + dx in
          let y = y0 + dy in
          let origR = array.{y, x, 0} in
            array.{y, x, 0} <- min 255 (origR + r);
          let origG = array.{y, x, 1} in
            array.{y, x, 1} <- min 255 (origG + g);
          let origB = array.{y, x, 2} in
            array.{y, x, 2} <- min 255 (origB + b);
      done
    done;;

(* HSV to RGB with S=1 *)
let makeColor (hue, value) =
  let hue6 = hue *. 6. in
  let h = hue6 -. (float ((truncate hue) * 6)) in
  let i = truncate h in
  let f = h -. float i in
  let bb = value *. (1. -. f) in
  let cc = value *. f in
    match i with 
        0 -> (value, cc, 0.) 
      | 1 -> (bb, value, 0.) 
      | 2 -> (0., value, cc)
      | 3 -> (0., bb, value) 
      | 4 -> (cc, 0., value)
      | 5 -> (value, 0., bb);;

let makeIntColor(r, g, b) =
  (truncate (r *. 256.), truncate (g *. 256.), truncate (b *. 256.));;

let renderBob array loc time_ms = 
    updateLocation loc;
    let phase = float(time_ms) /. 3000. in
      drawBob (array, loc, makeIntColor (makeColor (phase +. loc.offset, 0.06)));;

let render array time_ms = 
  List.iter (fun loc -> renderBob array loc time_ms) locations;;

let init width height = 
  0;;

(* C export *)
let _ = Callback.register "render" render;;
let _ = Callback.register "init" init;;
