--- /dev/null
+(* $Id$ *)
+
+(*-
+ * morph3d.c - Shows 3D morphing objects (TK Version)
+ *
+ * This program was inspired on a WindowsNT(R)'s screen saver. It was written
+ * from scratch and it was not based on any other source code.
+ *
+ * Porting it to xlock (the final objective of this code since the moment I
+ * decided to create it) was possible by comparing the original Mesa's gear
+ * demo with it's ported version, so thanks for Danny Sung for his indirect
+ * help (look at gear.c in xlock source tree). NOTE: At the moment this code
+ * was sent to Brian Paul for package inclusion, the XLock Version was not
+ * available. In fact, I'll wait it to appear on the next Mesa release (If you
+ * are reading this, it means THIS release) to send it for xlock package
+ * inclusion). It will probably there be a GLUT version too.
+ *
+ * Thanks goes also to Brian Paul for making it possible and inexpensive
+ * to use OpenGL at home.
+ *
+ * Since I'm not a native english speaker, my apologies for any gramatical
+ * mistake.
+ *
+ * My e-mail addresses are
+ *
+ * vianna@cat.cbpf.br
+ * and
+ * marcelo@venus.rdc.puc-rio.br
+ *
+ * Marcelo F. Vianna (Feb-13-1997)
+ *)
+
+(*
+This document is VERY incomplete, but tries to describe the mathematics used
+in the program. At this moment it just describes how the polyhedra are
+generated. On futhurer versions, this document will be probabbly improved.
+
+Since I'm not a native english speaker, my apologies for any gramatical
+mistake.
+
+Marcelo Fernandes Vianna
+- Undergraduate in Computer Engeneering at Catholic Pontifical University
+- of Rio de Janeiro (PUC-Rio) Brasil.
+- e-mail: vianna@cat.cbpf.br or marcelo@venus.rdc.puc-rio.br
+- Feb-13-1997
+
+POLYHEDRA GENERATION
+
+For the purpose of this program it's not sufficient to know the polyhedra
+vertexes coordinates. Since the morphing algorithm applies a nonlinear
+transformation over the surfaces (faces) of the polyhedron, each face has
+to be divided into smaller ones. The morphing algorithm needs to transform
+each vertex of these smaller faces individually. It's a very time consoming
+task.
+
+In order to reduce calculation overload, and since all the macro faces of
+the polyhedron are transformed by the same way, the generation is made by
+creating only one face of the polyhedron, morphing it and then rotating it
+around the polyhedron center.
+
+What we need to know is the face radius of the polyhedron (the radius of
+the inscribed sphere) and the angle between the center of two adjacent
+faces using the center of the sphere as the angle's vertex.
+
+The face radius of the regular polyhedra are known values which I decided
+to not waste my time calculating. Following is a table of face radius for
+the regular polyhedra with edge length = 1:
+
+ TETRAHEDRON : 1/(2*sqrt(2))/sqrt(3)
+ CUBE : 1/2
+ OCTAHEDRON : 1/sqrt(6)
+ DODECAHEDRON : T^2 * sqrt((T+2)/5) / 2 -> where T=(sqrt(5)+1)/2
+ ICOSAHEDRON : (3*sqrt(3)+sqrt(15))/12
+
+I've not found any reference about the mentioned angles, so I needed to
+calculate them, not a trivial task until I figured out how :)
+Curiously these angles are the same for the tetrahedron and octahedron.
+A way to obtain this value is inscribing the tetrahedron inside the cube
+by matching their vertexes. So you'll notice that the remaining unmatched
+vertexes are in the same straight line starting in the cube/tetrahedron
+center and crossing the center of each tetrahedron's face. At this point
+it's easy to obtain the bigger angle of the isosceles triangle formed by
+the center of the cube and two opposite vertexes on the same cube face.
+The edges of this triangle have the following lenghts: sqrt(2) for the base
+and sqrt(3)/2 for the other two other edges. So the angle we want is:
+ +-----------------------------------------------------------+
+ | 2*ARCSIN(sqrt(2)/sqrt(3)) = 109.47122063449069174 degrees |
+ +-----------------------------------------------------------+
+For the cube this angle is obvious, but just for formality it can be
+easily obtained because we also know it's isosceles edge lenghts:
+sqrt(2)/2 for the base and 1/2 for the other two edges. So the angle we
+want is:
+ +-----------------------------------------------------------+
+ | 2*ARCSIN((sqrt(2)/2)/1) = 90.000000000000000000 degrees |
+ +-----------------------------------------------------------+
+For the octahedron we use the same idea used for the tetrahedron, but now
+we inscribe the cube inside the octahedron so that all cubes's vertexes
+matches excatly the center of each octahedron's face. It's now clear that
+this angle is the same of the thetrahedron one:
+ +-----------------------------------------------------------+
+ | 2*ARCSIN(sqrt(2)/sqrt(3)) = 109.47122063449069174 degrees |
+ +-----------------------------------------------------------+
+For the dodecahedron it's a little bit harder because it's only relationship
+with the cube is useless to us. So we need to solve the problem by another
+way. The concept of Face radius also exists on 2D polygons with the name
+Edge radius:
+ Edge Radius For Pentagon (ERp)
+ ERp = (1/2)/TAN(36 degrees) * VRp = 0.6881909602355867905
+ (VRp is the pentagon's vertex radio).
+ Face Radius For Dodecahedron
+ FRd = T^2 * sqrt((T+2)/5) / 2 = 1.1135163644116068404
+Why we need ERp? Well, ERp and FRd segments forms a 90 degrees angle,
+completing this triangle, the lesser angle is a half of the angle we are
+looking for, so this angle is:
+ +-----------------------------------------------------------+
+ | 2*ARCTAN(ERp/FRd) = 63.434948822922009981 degrees |
+ +-----------------------------------------------------------+
+For the icosahedron we can use the same method used for dodecahedron (well
+the method used for dodecahedron may be used for all regular polyhedra)
+ Edge Radius For Triangle (this one is well known: 1/3 of the triangle height)
+ ERt = sin(60)/3 = sqrt(3)/6 = 0.2886751345948128655
+ Face Radius For Icosahedron
+ FRi= (3*sqrt(3)+sqrt(15))/12 = 0.7557613140761707538
+So the angle is:
+ +-----------------------------------------------------------+
+ | 2*ARCTAN(ERt/FRi) = 41.810314895778596167 degrees |
+ +-----------------------------------------------------------+
+
+*)
+
+
+let scale = 0.3
+
+let vect_mul (x1,y1,z1) (x2,y2,z2) =
+ (y1 *. z2 -. z1 *. y2, z1 *. x2 -. x1 *. z2, x1 *. y2 -. y1 *. x2)
+
+let sqr a = a *. a
+
+(* Increasing this values produces better image quality, the price is speed. *)
+(* Very low values produces erroneous/incorrect plotting *)
+let tetradivisions = 23
+let cubedivisions = 20
+let octadivisions = 21
+let dodecadivisions = 10
+let icodivisions = 15
+
+let tetraangle = 109.47122063449069174
+let cubeangle = 90.000000000000000000
+let octaangle = 109.47122063449069174
+let dodecaangle = 63.434948822922009981
+let icoangle = 41.810314895778596167
+
+let pi = acos (-1.)
+let sqrt2 = sqrt 2.
+let sqrt3 = sqrt 3.
+let sqrt5 = sqrt 5.
+let sqrt6 = sqrt 6.
+let sqrt15 = sqrt 15.
+let cossec36_2 = 0.8506508083520399322
+let cosd x = cos (float x /. 180. *. pi)
+let sind x = sin (float x /. 180. *. pi)
+let cos72 = cosd 72
+let sin72 = sind 72
+let cos36 = cosd 36
+let sin36 = sind 36
+
+(*************************************************************************)
+
+let front_shininess = 60.0
+let front_specular = 0.7, 0.7, 0.7, 1.0
+let ambient = 0.0, 0.0, 0.0, 1.0
+let diffuse = 1.0, 1.0, 1.0, 1.0
+let position0 = 1.0, 1.0, 1.0, 0.0
+let position1 = -1.0,-1.0, 1.0, 0.0
+let lmodel_ambient = 0.5, 0.5, 0.5, 1.0
+let lmodel_twoside = true
+
+let materialRed = 0.7, 0.0, 0.0, 1.0
+let materialGreen = 0.1, 0.5, 0.2, 1.0
+let materialBlue = 0.0, 0.0, 0.7, 1.0
+let materialCyan = 0.2, 0.5, 0.7, 1.0
+let materialYellow = 0.7, 0.7, 0.0, 1.0
+let materialMagenta = 0.6, 0.2, 0.5, 1.0
+let materialWhite = 0.7, 0.7, 0.7, 1.0
+let materialGray = 0.2, 0.2, 0.2, 1.0
+let all_gray = Array.create 20 materialGray
+
+let vertex ~xf ~yf ~zf ~ampvr2 =
+ let xa = xf +. 0.01 and yb = yf +. 0.01 in
+ let xf2 = sqr xf and yf2 = sqr yf in
+ let factor = 1. -. (xf2 +. yf2) *. ampvr2
+ and factor1 = 1. -. (sqr xa +. yf2) *. ampvr2
+ and factor2 = 1. -. (xf2 +. sqr yb) *. ampvr2 in
+ let vertx = factor *. xf and verty = factor *. yf
+ and vertz = factor *. zf in
+ let neiax = factor1 *. xa -. vertx and neiay = factor1 *. yf -. verty
+ and neiaz = factor1 *. zf -. vertz and neibx = factor2 *. xf -. vertx
+ and neiby = factor2 *. yb -. verty and neibz = factor2 *. zf -. vertz in
+ GlDraw.normal3 (vect_mul (neiax, neiay, neiaz) (neibx, neiby, neibz));
+ GlDraw.vertex3 (vertx, verty, vertz)
+
+let triangle ~edge ~amp ~divisions ~z =
+ let divi = float divisions in
+ let vr = edge *. sqrt3 /. 3. in
+ let ampvr2 = amp /. sqr vr
+ and zf = edge *. z in
+ let ax = edge *. (0.5 /. divi)
+ and ay = edge *. (-0.5 *. sqrt3 /. divi)
+ and bx = edge *. (-0.5 /. divi) in
+ for ri = 1 to divisions do
+ GlDraw.begins `triangle_strip;
+ for ti = 0 to ri - 1 do
+ vertex ~zf ~ampvr2
+ ~xf:(float (ri-ti) *. ax +. float ti *. bx)
+ ~yf:(vr +. float (ri-ti) *. ay +. float ti *. ay);
+ vertex ~zf ~ampvr2
+ ~xf:(float (ri-ti-1) *. ax +. float ti *. bx)
+ ~yf:(vr +. float (ri-ti-1) *. ay +. float ti *. ay)
+ done;
+ vertex ~xf:(float ri *. bx) ~yf:(vr +. float ri *. ay) ~zf ~ampvr2;
+ GlDraw.ends ()
+ done
+
+let square ~edge ~amp ~divisions ~z =
+ let divi = float divisions in
+ let zf = edge *. z
+ and ampvr2 = amp /. sqr (edge *. sqrt2 /. 2.) in
+ for yi = 0 to divisions - 1 do
+ let yf = edge *. (-0.5 +. float yi /. divi) in
+ let yf2 = sqr yf in
+ let y = yf +. 1.0 /. divi *. edge in
+ let y2 = sqr y in
+ GlDraw.begins `quad_strip;
+ for xi = 0 to divisions do
+ let xf = edge *. (-0.5 +. float xi /. divi) in
+ vertex ~xf ~yf:y ~zf ~ampvr2;
+ vertex ~xf ~yf ~zf ~ampvr2
+ done;
+ GlDraw.ends ()
+ done
+
+let pentagon ~edge ~amp ~divisions ~z =
+ let divi = float divisions in
+ let zf = edge *. z
+ and ampvr2 = amp /. sqr(edge *. cossec36_2) in
+ let x =
+ Array.init 6
+ ~f:(fun fi -> -. cos (float fi *. 2. *. pi /. 5. +. pi /. 10.)
+ /. divi *. cossec36_2 *. edge)
+ and y =
+ Array.init 6
+ ~f:(fun fi -> sin (float fi *. 2. *. pi /. 5. +. pi /. 10.)
+ /. divi *. cossec36_2 *. edge)
+ in
+ for ri = 1 to divisions do
+ for fi = 0 to 4 do
+ GlDraw.begins `triangle_strip;
+ for ti = 0 to ri-1 do
+ vertex ~zf ~ampvr2
+ ~xf:(float(ri-ti) *. x.(fi) +. float ti *. x.(fi+1))
+ ~yf:(float(ri-ti) *. y.(fi) +. float ti *. y.(fi+1));
+ vertex ~zf ~ampvr2
+ ~xf:(float(ri-ti-1) *. x.(fi) +. float ti *. x.(fi+1))
+ ~yf:(float(ri-ti-1) *. y.(fi) +. float ti *. y.(fi+1))
+ done;
+ vertex ~xf:(float ri *. x.(fi+1)) ~yf:(float ri *. y.(fi+1)) ~zf ~ampvr2;
+ GlDraw.ends ()
+ done
+ done
+
+let call_list list color =
+ GlLight.material ~face:`both (`diffuse color);
+ GlList.call list
+
+let draw_tetra ~amp ~divisions ~color =
+ let list = GlList.create `compile in
+ triangle ~edge:2.0 ~amp ~divisions ~z:(0.5 /. sqrt6);
+ GlList.ends();
+
+ call_list list color.(0);
+ GlMat.push();
+ GlMat.rotate ~angle:180.0 ~z:1.0 ();
+ GlMat.rotate ~angle:(-.tetraangle) ~x:1.0 ();
+ call_list list color.(1);
+ GlMat.pop();
+ GlMat.push();
+ GlMat.rotate ~angle:180.0 ~y:1.0 ();
+ GlMat.rotate ~angle:(-180.0 +. tetraangle) ~x:0.5 ~y:(sqrt3 /. 2.) ();
+ call_list list color.(2);
+ GlMat.pop();
+ GlMat.rotate ~angle:180.0 ~y:1.0 ();
+ GlMat.rotate ~angle:(-180.0 +. tetraangle) ~x:0.5 ~y:(-.sqrt3 /. 2.) ();
+ call_list list color.(3);
+
+ GlList.delete list
+
+let draw_cube ~amp ~divisions ~color =
+ let list = GlList.create `compile in
+ square ~edge:2.0 ~amp ~divisions ~z:0.5;
+ GlList.ends ();
+
+ call_list list color.(0);
+ for i = 1 to 3 do
+ GlMat.rotate ~angle:cubeangle ~x:1.0 ();
+ call_list list color.(i)
+ done;
+ GlMat.rotate ~angle:cubeangle ~y:1.0 ();
+ call_list list color.(4);
+ GlMat.rotate ~angle:(2.0 *. cubeangle) ~y:1.0 ();
+ call_list list color.(5);
+
+ GlList.delete list
+
+let draw_octa ~amp ~divisions ~color =
+ let list = GlList.create `compile in
+ triangle ~edge:2.0 ~amp ~divisions ~z:(1.0 /. sqrt6);
+ GlList.ends ();
+
+ let do_list (i,y) =
+ GlMat.push();
+ GlMat.rotate ~angle:180.0 ~y:1.0 ();
+ GlMat.rotate ~angle:(-.octaangle) ~x:0.5 ~y ();
+ call_list list color.(i);
+ GlMat.pop()
+ in
+ call_list list color.(0);
+ GlMat.push();
+ GlMat.rotate ~angle:180.0 ~z:1.0 ();
+ GlMat.rotate ~angle:(-180.0 +. octaangle) ~x:1.0 ();
+ call_list list color.(1);
+ GlMat.pop();
+ List.iter [2, sqrt3 /. 2.0; 3, -.sqrt3 /. 2.0] ~f:do_list;
+ GlMat.rotate ~angle:180.0 ~x:1.0 ();
+ GlLight.material ~face:`both (`diffuse color.(4));
+ GlList.call list;
+ GlMat.push();
+ GlMat.rotate ~angle:180.0 ~z:1.0 ();
+ GlMat.rotate ~angle:(-180.0 +. octaangle) ~x:1.0 ();
+ GlLight.material ~face:`both (`diffuse color.(5));
+ GlList.call list;
+ GlMat.pop();
+ List.iter [6, sqrt3 /. 2.0; 7, -.sqrt3 /. 2.0] ~f:do_list;
+
+ GlList.delete list
+
+let draw_dodeca ~amp ~divisions ~color =
+ let tau = (sqrt5 +. 1.0) /. 2.0 in
+ let list = GlList.create `compile in
+ pentagon ~edge:2.0 ~amp ~divisions
+ ~z:(sqr(tau) *. sqrt ((tau+.2.0)/.5.0) /. 2.0);
+ GlList.ends ();
+
+ let do_list (i,angle,x,y) =
+ GlMat.push();
+ GlMat.rotate ~angle:angle ~x ~y ();
+ call_list list color.(i);
+ GlMat.pop();
+ in
+ GlMat.push ();
+ call_list list color.(0);
+ GlMat.rotate ~angle:180.0 ~z:1.0 ();
+ List.iter ~f:do_list
+ [ 1, -.dodecaangle, 1.0, 0.0;
+ 2, -.dodecaangle, cos72, sin72;
+ 3, -.dodecaangle, cos72, -.sin72;
+ 4, dodecaangle, cos36, -.sin36;
+ 5, dodecaangle, cos36, sin36 ];
+ GlMat.pop ();
+ GlMat.rotate ~angle:180.0 ~x:1.0 ();
+ call_list list color.(6);
+ GlMat.rotate ~angle:180.0 ~z:1.0 ();
+ List.iter ~f:do_list
+ [ 7, -.dodecaangle, 1.0, 0.0;
+ 8, -.dodecaangle, cos72, sin72;
+ 9, -.dodecaangle, cos72, -.sin72;
+ 10, dodecaangle, cos36, -.sin36 ];
+ GlMat.rotate ~angle:dodecaangle ~x:cos36 ~y:sin36 ();
+ call_list list color.(11);
+
+ GlList.delete list
+
+let draw_ico ~amp ~divisions ~color =
+ let list = GlList.create `compile in
+ triangle ~edge:1.5 ~amp ~divisions
+ ~z:((3.0 *. sqrt3 +. sqrt15) /. 12.0);
+ GlList.ends ();
+
+ let do_list1 i =
+ GlMat.rotate ~angle:180.0 ~y:1.0 ();
+ GlMat.rotate ~angle:(-180.0 +. icoangle) ~x:0.5 ~y:(sqrt3/.2.0) ();
+ call_list list color.(i)
+ and do_list2 i =
+ GlMat.rotate ~angle:180.0 ~y:1.0 ();
+ GlMat.rotate ~angle:(-180.0 +. icoangle) ~x:0.5 ~y:(-.sqrt3/.2.0) ();
+ call_list list color.(i)
+ and do_list3 i =
+ GlMat.rotate ~angle:180.0 ~z:1.0 ();
+ GlMat.rotate ~angle:(-.icoangle) ~x:1.0 ();
+ call_list list color.(i)
+ in
+ GlMat.push ();
+ call_list list color.(0);
+ GlMat.push ();
+ do_list3 1;
+ GlMat.push ();
+ do_list1 2;
+ GlMat.pop ();
+ do_list2 3;
+ GlMat.pop ();
+ GlMat.push ();
+ do_list1 4;
+ GlMat.push ();
+ do_list1 5;
+ GlMat.pop();
+ do_list3 6;
+ GlMat.pop ();
+ do_list2 7;
+ GlMat.push ();
+ do_list2 8;
+ GlMat.pop ();
+ do_list3 9;
+ GlMat.pop ();
+ GlMat.rotate ~angle:180.0 ~x:1.0 ();
+ call_list list color.(10);
+ GlMat.push ();
+ do_list3 11;
+ GlMat.push ();
+ do_list1 12;
+ GlMat.pop ();
+ do_list2 13;
+ GlMat.pop ();
+ GlMat.push ();
+ do_list1 14;
+ GlMat.push ();
+ do_list1 15;
+ GlMat.pop ();
+ do_list3 16;
+ GlMat.pop ();
+ do_list2 17;
+ GlMat.push ();
+ do_list2 18;
+ GlMat.pop ();
+ do_list3 19;
+
+ GlList.delete list
+
+class view area = object (self)
+ val area : GlGtk.area = area
+ val mutable smooth = true
+ val mutable step = 0.
+ val mutable obj = 1
+ val mutable draw_object = fun ~amp -> ()
+ val mutable magnitude = 0.
+
+ method width = area#misc#allocation.Gtk.width
+ method height = area#misc#allocation.Gtk.height
+
+ method draw () =
+ let ratio = float self#height /. float self#width in
+ GlClear.clear [`color;`depth];
+ GlMat.push();
+ GlMat.translate ~z:(-10.0) ();
+ GlMat.scale ~x:(scale *. ratio) ~y:scale ~z:scale ();
+ GlMat.translate ()
+ ~x:(2.5 *. ratio *. sin (step *. 1.11))
+ ~y:(2.5 *. cos (step *. 1.25 *. 1.11));
+ GlMat.rotate ~angle:(step *. 100.) ~x:1.0 ();
+ GlMat.rotate ~angle:(step *. 95.) ~y:1.0 ();
+ GlMat.rotate ~angle:(step *. 90.) ~z:1.0 ();
+ draw_object ~amp:((sin step +. 1.0/.3.0) *. (4.0/.5.0) *. magnitude);
+ GlMat.pop();
+ Gl.flush();
+ area#swap_buffers ();
+ step <- step +. 0.05
+
+ method reshape ~width ~height =
+ GlDraw.viewport ~x:0 ~y:0 ~w:width ~h:height;
+ GlMat.mode `projection;
+ GlMat.load_identity();
+ GlMat.frustum ~x:(-1.0, 1.0) ~y:(-1.0, 1.0) ~z:(5.0, 15.0);
+ GlMat.mode `modelview
+
+ method key sym =
+ begin match sym with
+ "1" -> obj <- 1
+ | "2" -> obj <- 2
+ | "3" -> obj <- 3
+ | "4" -> obj <- 4
+ | "5" -> obj <- 5
+ | "\r" -> smooth <- not smooth
+ | "\027" -> area#misc#toplevel#destroy (); exit 0
+ | _ -> ()
+ end;
+ self#pinit
+
+ method pinit =
+ begin match obj with
+ 1 ->
+ draw_object <- draw_tetra
+ ~divisions:tetradivisions
+ ~color:[|materialRed; materialGreen;
+ materialBlue; materialWhite|];
+ magnitude <- 2.5
+ | 2 ->
+ draw_object <- draw_cube
+ ~divisions:cubedivisions
+ ~color:[|materialRed; materialGreen; materialCyan;
+ materialMagenta; materialYellow; materialBlue|];
+ magnitude <- 2.0
+ | 3 ->
+ draw_object <- draw_octa
+ ~divisions:octadivisions
+ ~color:[|materialRed; materialGreen; materialBlue;
+ materialWhite; materialCyan; materialMagenta;
+ materialGray; materialYellow|];
+ magnitude <- 2.5
+ | 4 ->
+ draw_object <- draw_dodeca
+ ~divisions:dodecadivisions
+ ~color:[|materialRed; materialGreen; materialCyan;
+ materialBlue; materialMagenta; materialYellow;
+ materialGreen; materialCyan; materialRed;
+ materialMagenta; materialBlue; materialYellow|];
+ magnitude <- 2.0
+ | 5 ->
+ draw_object <- draw_ico
+ ~divisions:icodivisions
+ ~color:[|materialRed; materialGreen; materialBlue;
+ materialCyan; materialYellow; materialMagenta;
+ materialRed; materialGreen; materialBlue;
+ materialWhite; materialCyan; materialYellow;
+ materialMagenta; materialRed; materialGreen;
+ materialBlue; materialCyan; materialYellow;
+ materialMagenta; materialGray|];
+ magnitude <- 3.5
+ | _ -> ()
+ end;
+ GlDraw.shade_model (if smooth then `smooth else `flat)
+ initializer
+ area#connect#display ~callback:self#draw;
+ area#connect#reshape ~callback:self#reshape;
+ ()
+end
+
+open GMain
+
+let main () =
+ List.iter ~f:print_string
+ [ "Morph 3D - Shows morphing platonic polyhedra\n";
+ "Author: Marcelo Fernandes Vianna (vianna@cat.cbpf.br)\n";
+ "Ported to LablGL by Jacques Garrigue\n\n";
+ " [1] - Tetrahedron\n";
+ " [2] - Hexahedron (Cube)\n";
+ " [3] - Octahedron\n";
+ " [4] - Dodecahedron\n";
+ " [5] - Icosahedron\n";
+ "[RETURN] - Toggle smooth/flat shading\n";
+ " [ESC] - Quit\n" ];
+ flush stdout;
+
+ let window =
+ GWindow.window ~title:"Morph 3D - Shows morphing platonic polyhedra" ()
+ in
+ window#connect#destroy ~callback:Main.quit;
+ window#set_resize_mode `IMMEDIATE;
+
+ let area = GlGtk.area [`DEPTH_SIZE 1;`RGBA;`DOUBLEBUFFER]
+ ~width:640 ~height:480 ~packing:window#add () in
+
+ let view = new view area in
+
+ area#connect#realize ~callback:
+ begin fun () ->
+ view#pinit;
+ GlClear.depth 1.0;
+ GlClear.color (0.0, 0.0, 0.0);
+ GlDraw.color (1.0, 1.0, 1.0);
+
+ GlClear.clear [`color;`depth];
+ Gl.flush();
+
+ List.iter ~f:(GlLight.light ~num:0)
+ [`ambient ambient; `diffuse diffuse; `position position0];
+ List.iter ~f:(GlLight.light ~num:1)
+ [`ambient ambient; `diffuse diffuse; `position position1];
+ GlLight.light_model (`ambient lmodel_ambient);
+ GlLight.light_model (`two_side lmodel_twoside);
+ List.iter ~f:Gl.enable
+ [`lighting;`light0;`light1;`depth_test;`normalize];
+
+ GlLight.material ~face:`both (`shininess front_shininess);
+ GlLight.material ~face:`both (`specular front_specular);
+
+ GlMisc.hint `fog `fastest;
+ GlMisc.hint `perspective_correction `fastest;
+ GlMisc.hint `polygon_smooth `fastest
+ end;
+
+ window#event#connect#key_press
+ ~callback:(fun ev -> view#key (GdkEvent.Key.string ev); true);
+
+ Timeout.add ~ms:20
+ ~callback:(fun _ -> if area#misc#visible then view#draw (); true);
+ window#show ();
+ Main.main ()
+
+let _ = main ()