(* ============================================================================== *) (* === Projet ocamlpilot - CG version du 21/04/2005 === *) (* === === *) (* === Ce programme montre comment utiliser la pile de matrices du modelview === *) (* === afin de dessiner plusieurs theieres. En OpenGL les theieres sont === *) (* === definies centrees sur l'origine des axes et elles sont orientees le === *) (* === bec vers l'axe des x. === *) (* ============================================================================== *) (* ============================================================================== *) (* === initialisation d'openGL a faire pour chaque programme === *) (* ============================================================================== *) (* on recupere les arguments specifiques a OpenGL transmis sur la ligne de commande *) ignore(Glut.init Sys.argv);; (* initialisation du mode d'affichage : alpha : permet de jouer sur la luminosite des objets double_buffer : on travaille en double buffering, comme en 2D depth : on utilise le Z-buffer pour supprimer les parties cachees *) Glut.initDisplayMode ~alpha:true ~double_buffer:true ~depth:true ();; (* taille de la fenetre a l'ouverture *) Glut.initWindowSize ~w:800 ~h:600;; (* creation de la fenetre et titre de la fenetre *) ignore(Glut.createWindow "OcamlPilot");; (* gestion du clavier : ESC = sortie du programme *) let manage_keyboard () = Glut.keyboardFunc ~cb:(fun ~key ~x ~y -> if key = 27 then exit 0);; (* ============================================================================== *) (* === affichage /stacks === *) (* ============================================================================== *) let angle = ref 0.;; let dessine_theieres () = (* on efface le buffer dans lequel on dessine *) GlClear.color (0.0, 0.0, 0.0); (* <- couleur de fond = noir *) GlClear.clear [`color;`depth]; (* lumiere *) Gl.enable `lighting; GlDraw.shade_model `smooth; (* on place la camera, l'oeil se trouve sur un cercle de centre (0,0,10) et de rayon 10. On regarde toujours dans la direction du point (0,0,10) *) GlMat.mode `modelview; GlMat.load_identity(); GluMat.look_at ~eye:(10. *. cos !angle,0.,10. *. (1. +. sin !angle)) ~center:(0.,0.,10.) ~up:(0.,1.,0.); (* on sauvegarde la matrice courante dans la pile de maniere a pouvoir la reutiliser pour la deuxieme theiere. Si l'on ne faisait pas cela, on serait oblige de dupliquer le code a partir du GlMat.mode `modelview pour chaque objet a dessiner. *) GlMat.push (); (* on affiche une theiere *) GlLight.material ~face:`front (`ambient_and_diffuse (0.10,0.10,0.50,1.0)); (* bleu *) GlLight.material ~face:`front (`shininess 100.0); GlLight.material ~face:`front (`specular (1.,1.,0.,10.)); GlMat.translate ~x:1.5 ~y:0.5 ~z:10. (); GlMat.rotate ~angle:(-45.0) ~x:(1.0) (); (* theiere de taille 0.5 *) Glut.solidTeapot 0.5; (* on peut maintenant faire un pop et se retrouver avec la matrice qui indique ou se trouve la camera. Le pop permet ainsi d'eliminer les effets de la rotation et de la translation ci-dessus. *) GlMat.pop (); (* 2eme theiere : jaune *) GlLight.material ~face:`front (`ambient_and_diffuse (0.61,0.35,0.10,1.0)); GlLight.material ~face:`front (`shininess 120.0); GlLight.material ~face:`front (`specular (0.7,0.7,0.7,0.1)); GlMat.push (); GlMat.translate ~y:(-0.5) ~z:10. (); GlMat.rotate ~angle:(-45.0) ~y:(1.0) (); Glut.solidTeapot 1.; GlMat.pop (); (* 3eme theiere : rouge *) GlLight.material ~face:`front (`ambient_and_diffuse (0.49,0.,0.16,1.0)); GlLight.material ~face:`front (`shininess 120.0); GlLight.material ~face:`front (`specular (0.7,0.7,0.7,0.1)); GlMat.push (); GlMat.translate ~x:(-0.5) ~y:0.5 ~z:7. (); GlMat.rotate ~angle:(-45.0) ~z:(1.0) (); Glut.wireTeapot 1.5; GlMat.pop (); (* on effectue la synchronisation du double buffering *) Gl.flush (); Glut.swapBuffers (); (* on rajoute un delta a l'angle *) angle := !angle +. 0.05;; (* fonction qui reaffiche tout toutes les 3 secondes *) let rec affichage ~value = dessine_theieres (); Glut.timerFunc ~ms:100 ~cb:affichage ~value:0;; let manage_light () = (* caracteristiques de la lumiere numero 0 (le spot 0) *) GlLight.light ~num:0 (`ambient (1.0, 1.0, 1.0, 1.0)); GlLight.light ~num:0 (`diffuse (1.0, 1.0, 1.0, 1.0)); GlLight.light ~num:0 (`specular (1.0, 1.0, 1.0, 1.0)); GlLight.light ~num:0 (`position ((0.0), 5.0, (-10.0), 2.0)); (* on allume le spot numero 0 *) Gl.enable `light0;; (* ============================================================================== *) (* === changement de taille de la fenetre === *) (* ============================================================================== *) (* en cas de modification de la taille de la fenetre, il ne faut pas aplatir ou alonger l'image mais plutot diminuer ou augmenter le champ de vision. Ceci est calcule en utilisant une matrice de projection/perspective *) let reshape_window ~w ~h = (* w = nouvelle largeur de la fenetre h = nouvelle hauteur de la fenetre *) (* remise a jour de la matrice de projection *) GlMat.mode `projection; GlMat.load_identity(); (* changement de la matrice de perspective : fovy = l'angle de vision aspect = déformation aplatissement/alongement z = la coordonnee en Z du plan le plus proche et du plus eloigne ces parametres definissent le cone de ce qui est visible *) GluMat.perspective ~fovy:45.0 ~aspect:(float w /. float h) ~z:(7.,1500.0);; (* ============================================================================== *) (* ============================================================================== *) let main () = (* on binde le clavier *) manage_keyboard (); (* initialisation de la lumiere *) manage_light (); (* creation du timer pour effectuer les affichages regulierement *) Glut.timerFunc ~ms:100 ~cb:affichage ~value:0; (* au cas ou la taille de la fenetre aurait change *) Glut.reshapeFunc ~cb:reshape_window; (* on appelle reshape de maniere a mettre en place la matrice de perspective *) reshape_window ~w:800 ~h:600; (* lancement de la boucle principale d'openGL. Ceci doit etre effectue en dernier car mainLoop ne rendra la main qu'a la fin de l'execution du programme. *) Glut.mainLoop ();; main ();;