(* $Id: planet.ml,v 1.17 2001-09-07 06:50:01 garrigue Exp $ *)

#load"unix.cma";;

class planet togl = object (self)
  val togl = togl
  val mutable year = 0.0
  val mutable day = 0.0
  val mutable eye = 0.0
  val mutable time = 0.0

  method tick new_time =
    if time = 0. then time <- new_time else
    let diff = new_time -. time in
    time <- new_time;
    day <- mod_float (day +. diff *. 200.) 360.0;
    year <- mod_float (year +. diff *. 20.) 360.0
  method day_add =
    day <- mod_float (day +. 10.0) 360.0
  method day_subtract =
    day <- mod_float (day -. 10.0) 360.0
  method year_add =
    year <- mod_float (year +. 5.0) 360.0
  method year_subtract =
    year <- mod_float (year -. 5.0) 360.0
  method eye x =
    eye <- x; self#display

  method display =
    GlClear.clear [`color;`depth];

    GlDraw.color (1.0, 1.0, 1.0);
    GlMat.push();
    GlMat.rotate ~angle:eye ~x:1. ();
(*	draw sun	*)
    GlLight.material ~face:`front (`specular (1.0,1.0,0.0,1.0));
    GlLight.material ~face:`front (`shininess 5.0);
    GluQuadric.sphere ~radius:1.0 ~slices:32 ~stacks:32 ();
(*	draw smaller planet	*)
    GlMat.rotate ~angle:year ~y:1.0 ();
    GlMat.translate () ~x:3.0;
    GlMat.rotate ~angle:day ~y:1.0 ();
    GlDraw.color (0.0, 1.0, 1.0);
    GlDraw.shade_model `flat;
    GlLight.material ~face:`front(`shininess 128.0);
    GluQuadric.sphere ~radius:0.2 ~slices:10 ~stacks:10 ();
    GlDraw.shade_model `smooth;
    GlMat.pop ();
    Gl.flush ();
    Togl.swap_buffers togl
end

let myinit () =
  let light_ambient = 0.5, 0.5, 0.5, 1.0
  and light_diffuse = 1.0, 0.8, 0.2, 1.0
  and light_specular = 1.0, 1.0, 1.0, 1.0
  (*  light_position is NOT default value	*)
  and light_position = 1.0, 1.0, 1.0, 0.0
  in
  List.iter (GlLight.light ~num:0)
    [ `ambient light_ambient; `diffuse light_diffuse;
      `specular light_specular; `position light_position ];
  GlFunc.depth_func `less;
  List.iter Gl.enable [`lighting; `light0; `depth_test];
  GlDraw.shade_model `smooth


let my_reshape togl =
  let w = Togl.width togl and h = Togl.height togl in
  GlDraw.viewport ~x:0 ~y:0 ~w ~h;
  GlMat.mode `projection;
  GlMat.load_identity();
  GluMat.perspective ~fovy:60.0 ~aspect:(float w /. float h) ~z:(1.0,20.0);
  GlMat.mode `modelview;
  GlMat.load_identity();
  GlMat.translate () ~z:(-5.0)

(*  Main Loop
 *  Open window with initial window size, title bar, 
 *  RGBA display mode, and handle input events.
 *)
open Tk

let main () =
  let top = openTk () in
  let togl =
    Togl.create top ~width:700 ~height:500 ~double:true ~rgba:true
      ~depth:true in
  Wm.title_set top "Planet";

  myinit ();

  let planet = new planet togl in
  let scale =
    Scale.create top ~min:(-45.) ~max:45. ~orient:`Vertical
      ~command:(planet#eye) ~showvalue:false ~highlightbackground:`Black in
  bind togl ~events:[`Enter] ~action:(fun _ -> Focus.set togl);
  bind scale ~events:[`Enter] ~action:(fun _ -> Focus.set scale);
  bind togl ~events:[`KeyPress] ~fields:[`KeySymString]
    ~action:(fun ev ->
      begin match ev.ev_KeySymString with
	"Left" ->  planet#year_subtract
      |	"Right" -> planet#year_add
      |	"Up" -> planet#day_add
      |	"Down" -> planet#day_subtract
      |	"Escape" -> destroy top; exit 0
      |	_ -> ()
      end;
      planet#display);
  Togl.timer_func ~ms:20
    ~cb:(fun () -> planet#tick (Unix.gettimeofday()); planet#display);
  Togl.display_func togl ~cb:(fun () -> planet#display);
  Togl.reshape_func togl ~cb:(fun () -> my_reshape togl);
  my_reshape togl;
  pack [togl] ~side:`Left ~expand:true ~fill:`Both;
  pack [scale] ~side:`Right ~fill:`Y;
  Focus.set togl;
  mainLoop ()

let _ = Printexc.print main ()
