(************************************************************************************)
(* 
 * To prepare an Ocaml graphics window for use with OpenGL the following hack is used. 
 * The method is similar, but not identical, on both Windows and X11. 
 * After opening the window with Graphics.open_graph (), the function init_opengl ()
 * has to be called. This function gives the window a (hopefully) unique name. Then 
 * some C code is called which searches through all available windows for a window
 * with that particular name, gets pointers to its internal structure (both Win32 and
 * Xlib allow this) and sets it up for use as an OpenGL surface.
 *
 * Compiling:
 * You need the file win_stub.c and the ML code contained in this section, specifically
 * the function init_opengl () and the external functions init_gl'(), find_window() and swap_buffers ().
 * Link the resultant executable with libGL.a on X11, opengl32.lib and gdi32.lib on Windows
 *
 * Usage:
 * First set up your caml window with Graphics.open_graph ()
 * Next, call the function init_gl () defined here below.
 * After this you can (re)set the window title (if you set it previously it will be empty)
 * Feel free to call any OpenGL calls you wish. lablgl, glcaml and camlgl may all be used.
 * You may mix the Ocaml graphics functions with OpenGL.
 * Call swap_buffers () any time you need to flip the contents of your back buffer to the screen.
 *)

external find_window : string -> int = "stub_find_window""stub_find_window"
external init_gl' : string -> unit = "stub_init_gl" "stub_init_gl"
external swap_buffers : unit -> unit = "stub_swap_buffers" "stub_swap_buffers"

let init_opengl () =
        let _  = Random.self_init () in
        let title = Printf.sprintf "%d.%d" (Random.int 1000000) (Random.int 1000000) in
        Graphics.set_window_title title;
        init_gl' title;
        Graphics.set_window_title "";;
        
(************************************************************************************)



(* --------------------------------------------------------------------------------- *)
open Glcaml

(* Replacement for GluPerspective() *)
let perspective fov aspect zNear zFar =
        let pi = 4.0 *. (atan 1.0) in
        let fH = (tan (fov /. 360.0 *. pi )) *. zNear in
        let fW = fH *. aspect in 
        glFrustum (-.fW) fW (-.fH) fH zNear zFar;; 
 
(* A general OpenGL initialization function.  Sets all of the initial parameters. *)
let init_gl width height =
        glViewport 0 0 width height;
        glClearColor 0.0 0.0 0.0 0.0;
        glClearDepth 1.0;
        glDepthFunc GL_LESS;
        glEnable GL_DEPTH_TEST;
        glShadeModel GL_SMOOTH;
        glMatrixMode GL_PROJECTION;
        glLoadIdentity ();
        let aspect = (float_of_int width) /. (float_of_int height) in
        perspective 45.0 aspect 1.0 100.0;
        glMatrixMode GL_MODELVIEW
        
;;        
        
(* The main drawing function. *)
let draw_gl_scene () =
        glClear [GL_COLOR_BUFFER_BIT; GL_DEPTH_BUFFER_BIT];
        glLoadIdentity ();
        glTranslatef (-.1.5) 0.0 (-.6.0);
        (* draw a triangle *)
        glBegin GL_TRIANGLES;                                
        glColor3f 1.0 0.0 0.0;                
        glVertex3f  0.0 1.0 0.0;
        glColor3f 0.0 1.0 0.0;                
        glVertex3f 1.0 (-.1.0) 0.0;                
        glColor3f 0.0 0.0 1.0;                
        glVertex3f (-.1.0) (-.1.0) 0.0;                        
        glEnd ();                                        
        glTranslatef 3.0 0.0 0.0;                        (* Move Right 3 Units *)
        (* draw a square (quadrilateral) *)
        glColor3f 0.5 0.5 1.0;
        glBegin GL_QUADS;                                
        glVertex3f (-.1.0) 1.0 0.0;                
        glVertex3f 1.0 1.0 0.0;                
        glVertex3f 1.0 (-.1.0) 0.0;                
        glVertex3f (-.1.0)(-.1.0) 0.0;                
        glEnd ()
;;                                                
                        

(************ main ***********)

let width = 640
let height =480
let topx = 50
let topy = 50

let init_graphics () =
    let init_string = (Printf.sprintf " %dx%d" width height) in 
    Graphics.open_graph init_string;
    init_opengl ();
    init_gl width height;
    Graphics.set_window_title "Test OpenGL with native Ocaml graphics" ;;

let show_img img =
    Graphics.draw_image (Graphics.make_image img) 0 0;;

 
let _ = init_graphics ();;

let main () = 
        draw_gl_scene ();
        swap_buffers ();
        Graphics.set_color Graphics.white;
        Graphics.moveto 50 50;
        Graphics.draw_string "Hello OpenGL world, from Ocaml Graphics";  (* Mix in Ocaml Graphics primitives *)
        let _ = Graphics.read_key () in
        ();; 

main ()