(* ============================================================================== *) (* === Projet ocamlpilot - CG version du 19/04/2005 === *) (* === === *) (* === Ce programme montre comment utiliser les lumieres dans openGL. === *) (* ============================================================================== *) (* ============================================================================== *) (* === 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);; (* ============================================================================== *) (* === creation de la lumiere === *) (* ============================================================================== *) 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), 1.0)); (* on allume le spot numero 0 *) Gl.enable `light0;; (* ============================================================================== *) (* === affichage === *) (* ============================================================================== *) let dessine_fenetre () = (* on efface le buffer dans lequel on dessine *) GlClear.color (0.0, 0.0, 0.0); (* <- couleur de fond = noir *) GlClear.clear [`color;`depth]; (* on place la camera, l'oeil au centre des axes, on regarde selon l'axe des z, vers les z croissants, et le haut de notre tete est vers le haut. *) GlMat.mode `modelview; GlMat.load_identity(); GluMat.look_at ~eye:(0.,0.,0.) ~center:(0.,0.,1.) ~up:(0.,1.,0.); (* on supprime la lumiere => les objets sont dessines avec la couleur specifiee par un GlDraw.color. Ici on affiche un triangle plein rouge *) Gl.disable `lighting; GlDraw.color (1.0, 0.0, 0.0); (* <- rouge *) GlDraw.polygon_mode `front `fill; GlDraw.begins `triangles; GlDraw.vertex ~x:(-3.) ~y:0. ~z:10. (); GlDraw.vertex ~x:(-1.) ~y:0. ~z:10. (); GlDraw.vertex ~x:(-2.) ~y:1. ~z:10. (); GlDraw.ends (); (* on affiche deux rectangles remplis bleus un peu brillants : on autorise les calculs de lumiere pour le rendu des objets *) Gl.enable `lighting; (* on definit la couleur des objets ainsi que la maniere dont ils refletent la lumiere *) GlLight.material ~face:`front (`ambient (0.10,0.10,0.50,1.0)); (* bleu *) GlLight.material ~face:`front (`diffuse (1.0,1.0,0.50,10.0)); (* bleu *) GlLight.material ~face:`front (`shininess 20.0); GlLight.material ~face:`front (`specular (1.,0.,0.,10.)); GlDraw.polygon_mode `front `fill; GlDraw.begins `quads; (* on affiche le 1er rectangle *) GlDraw.vertex ~x:1. ~y:0. ~z:7. (); GlDraw.vertex ~x:3. ~y:0. ~z:7. (); GlDraw.vertex ~x:3. ~y:1. ~z:10. (); GlDraw.vertex ~x:1. ~y:1. ~z:10. (); (* on affiche le 2eme rectangle *) GlDraw.vertex ~x:0.5 ~y:1. ~z:10. (); GlDraw.vertex ~x:3. ~y:1. ~z:10. (); GlDraw.vertex ~x:3. ~y:2. ~z:10. (); GlDraw.vertex ~x:0.5 ~y:2. ~z:10. (); GlDraw.ends (); (* on effectue la synchronisation du double buffering *) Gl.flush (); Glut.swapBuffers ();; (* fonction qui reaffiche tout toutes les 3 secondes *) let rec affichage ~value = dessine_fenetre (); Glut.timerFunc ~ms:100 ~cb:affichage ~value:0;; (* ============================================================================== *) (* === 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 ();;