open Graphics

let max_iter = 60 (* nombre maximum d'itérations *)
let f_max_iter = float max_iter (* optim *)

let dedans = black

(* couleur = interpolation linéaire entre le rouge (loin) et le vert (près) *)
let interpolation n =
  let f = float n /. f_max_iter in
  rgb (truncate ((1. -. f) *. 255.)) (truncate (f *. 255.)) 0

let couleur xc yc =
  let rec iter i x y =
    if i = max_iter then
      dedans
    else 
      let x2 = x *. x in
      let y2 = y *. y in
      if x2 +. y2 > 4. then
	interpolation i
      else
	iter (succ i) (x2 -. y2 +. xc) (2. *. x *. y +. yc)
  in
  iter 0 xc yc

let dessine xmin xmax ymin ymax gx gy w h pas =
  let dx = float pas *. (xmax -. xmin) /. float w in
  let dy = float pas *. (ymax -. ymin) /. float h in
  for i = 0 to w/pas - 1 do
    for j = 0 to h/pas - 1 do
      let x = xmin +. float i *. dx in
      let y = ymin +. float j *. dy in
      set_color (couleur x y);
      if pas = 1 then
	plot (gx + i) (gy + j)
      else
	fill_rect (gx + i * pas) (gy + j * pas) pas pas
    done
  done

let larg = 900
let haut = 600
let () = open_graph (Printf.sprintf " %dx%d" larg haut)

let w_xmin = ref 0.0
let w_xmax = ref 0.0
let w_ymin = ref 0.0
let w_ymax = ref 0.0

let taches = Queue.create ()

let reset xmin xmax ymin ymax = 
  clear_graph ();
  Queue.clear taches;
  Queue.add (xmin, xmax, ymin, ymax, 0, 0, larg, haut, 16) taches;
  w_xmin := xmin;
  w_xmax := xmax;
  w_ymin := ymin;
  w_ymax := ymax

let rec scheduler () =
  if not (Queue.is_empty taches) then begin
    let (xmin,xmax,ymin,ymax,gx,gy,w,h,pas) = Queue.pop taches in
    dessine xmin xmax ymin ymax gx gy w h pas;
    if pas > 1 then begin
      let pas' = max 1 (pas / 2) in
      let dx = (xmax -. xmin) /. 2. in
      let dy = (ymax -. ymin) /. 2. in
      Queue.add 
	(xmin, xmin +. dx, ymin, ymin +. dy, gx, gy, w/2, h/2, pas') taches;
      Queue.add 
	(xmin +. dx, xmax, ymin, ymin +. dy, gx + w/2, gy, w/2, h/2, pas') 
	taches;
      Queue.add 
	(xmin, xmin +.dx, ymin +. dy, ymax, gx, gy + h/2, w/2, h/2, pas') 
	taches;
      Queue.add 
	(xmin +. dx, xmax, ymin +. dy, ymax, 
	 gx + w/2, gy + h/2, w/2, h/2, pas') 
	taches;
    end
  end;
  let st = wait_next_event [Poll; Key_pressed; Button_down] in
  if st.keypressed then exit 0;
  if st.button then begin
    let st = wait_next_event [Button_up] in
    let dx = !w_xmax -. !w_xmin in
    let xc = !w_xmin +. (float st.mouse_x /. float larg) *. dx in
    let dy = !w_ymax -. !w_ymin in
    let yc = !w_ymin +. (float st.mouse_y /. float haut) *. dy in
    reset (xc -. dx /. 4.) (xc +. dx /. 4.) (yc -. dy /. 4.) (yc +. dy /. 4.)
  end;
  scheduler ()

let () = 
  reset (-2.0) 1.0 (-1.0) 1.0;
  scheduler ();
  ignore (read_key ())