1 /*
2  * button.c:
3  * Simple toggle button example.
4  *
5  * written by Naofumi Yasufuku  <naofumi@users.sourceforge.net>
6  * adapted by Antonio Monteiro to the gtkD toolkit <gtkDoolkit@yahoo.ca>
7  * this example is released under GPL license
8  */
9 /*
10  * This file is part of gtkD.
11  * 
12  * gtkD is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  * 
17  * gtkD is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Lesser General Public License for more details.
21  * 
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with gtkD; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
25  */
26 
27 module ShapesGL;
28 
29 import TrackBall;
30 import DrawGL;
31 
32 import cairo.Context;
33 import glib.Idle;
34 import glib.Timeout;
35 import gdk.Event;
36 import gtk.Button;
37 import gtk.DrawingArea;
38 import gtk.Layout;
39 import gtk.Main;
40 import gtk.MainWindow;
41 import gtk.Menu;
42 import gtk.MenuItem;
43 import gtk.SeparatorMenuItem;
44 import gtk.VBox;
45 import gtk.Widget;
46 import glgdk.GLConfig;
47 import glgdk.GLContext;
48 import glgdk.GLdInit;
49 import glgdk.GLWindow;
50 import glgtk.GLCapability;
51 import glgtk.GLWidget;
52 
53 import gtkc.glibtypes;
54 import gtkglc.gl;
55 import gtkglc.glu;
56 import gtkglc.glgdktypes;
57 import gtkglc.glgtktypes;
58 
59 version (Tango)
60 {
61     import tango.io.Stdout;
62     import tango.math.Math;
63 }
64 else
65 {
66     import std.math;
67 	import std.stdio;
68 }
69 
70 const float DIG_2_RAD = (PI / 180.0);
71 const float RAD_2_DIG = (180.0 / PI);
72 
73 const int ANIMATE_THRESHOLD = cast(int)25.0;
74 
75 const float VIEW_SCALE_MAX = 2.0;
76 const float VIEW_SCALE_MIN = 0.5;
77 
78 const int NUM_SHAPES = 9;
79 
80 enum Shapes
81 {
82 	cube         = 0,
83 	sphere       = 1,
84 	cone         = 2,
85 	torus        = 3,
86 	tetrahedron  = 4,
87 	octahedron   = 5,
88 	dodecahedron = 6,
89 	icosahedron  = 7,
90 	teapot       = 8
91 }
92 
93 static GLuint shape_list_base = 0;
94 static GLuint shape_current = 0;
95 
96 struct MaterialProp
97 {
98 	GLfloat ambient[4];
99 	GLfloat diffuse[4];
100 	GLfloat specular[4];
101 	GLfloat shininess;
102 }
103 
104 static MaterialProp mat_emerald = {
105   [0.0215, 0.1745, 0.0215, 1.0],
106   [0.07568, 0.61424, 0.07568, 1.0],
107   [0.633, 0.727811, 0.633, 1.0],
108   0.6
109 };
110 
111 static MaterialProp mat_jade = {
112   [0.135, 0.2225, 0.1575, 1.0],
113   [0.54, 0.89, 0.63, 1.0],
114   [0.316228, 0.316228, 0.316228, 1.0],
115   0.1
116 };
117 
118 static MaterialProp mat_obsidian = {
119   [0.05375, 0.05, 0.06625, 1.0],
120   [0.18275, 0.17, 0.22525, 1.0],
121   [0.332741, 0.328634, 0.346435, 1.0],
122   0.3
123 };
124 
125 static MaterialProp mat_pearl = {
126   [0.25, 0.20725, 0.20725, 1.0],
127   [1.0, 0.829, 0.829, 1.0],
128   [0.296648, 0.296648, 0.296648, 1.0],
129   0.088
130 };
131 
132 static MaterialProp mat_ruby = {
133   [0.1745, 0.01175, 0.01175, 1.0],
134   [0.61424, 0.04136, 0.04136, 1.0],
135   [0.727811, 0.626959, 0.626959, 1.0],
136   0.6
137 };
138 
139 static MaterialProp mat_turquoise = {
140   [0.1, 0.18725, 0.1745, 1.0],
141   [0.396, 0.74151, 0.69102, 1.0],
142   [0.297254, 0.30829, 0.306678, 1.0],
143   0.1
144 };
145 
146 static MaterialProp mat_brass = {
147   [0.329412, 0.223529, 0.027451, 1.0],
148   [0.780392, 0.568627, 0.113725, 1.0],
149   [0.992157, 0.941176, 0.807843, 1.0],
150   0.21794872
151 };
152 
153 static MaterialProp mat_bronze = {
154   [0.2125, 0.1275, 0.054, 1.0],
155   [0.714, 0.4284, 0.18144, 1.0],
156   [0.393548, 0.271906, 0.166721, 1.0],
157   0.2
158 };
159 
160 static MaterialProp mat_chrome = {
161   [0.25, 0.25, 0.25, 1.0],
162   [0.4, 0.4, 0.4, 1.0],
163   [0.774597, 0.774597, 0.774597, 1.0],
164   0.6
165 };
166 
167 static MaterialProp mat_copper = {
168   [0.19125, 0.0735, 0.0225, 1.0],
169   [0.7038, 0.27048, 0.0828, 1.0],
170   [0.256777, 0.137622, 0.086014, 1.0],
171   0.1
172 };
173 
174 static MaterialProp mat_gold = {
175   [0.24725, 0.1995, 0.0745, 1.0],
176   [0.75164, 0.60648, 0.22648, 1.0],
177   [0.628281, 0.555802, 0.366065, 1.0],
178   0.4
179 };
180 
181 static MaterialProp mat_silver = {
182   [0.19225, 0.19225, 0.19225, 1.0],
183   [0.50754, 0.50754, 0.50754, 1.0],
184   [0.508273, 0.508273, 0.508273, 1.0],
185   0.4
186 };
187 
188 static MaterialProp* mat_current;
189 
190 static float view_quat_diff[4] = [ 0.0, 0.0, 0.0, 1.0 ];
191 static float view_quat[4] = [ 0.0, 0.0, 0.0, 1.0 ];
192 static float view_scale = 1.0;
193 
194 static gboolean animate = false;
195 
196 static void init_view()
197 {
198   view_quat[0] = view_quat_diff[0] = 0.0;
199   view_quat[1] = view_quat_diff[1] = 0.0;
200   view_quat[2] = view_quat_diff[2] = 0.0;
201   view_quat[3] = view_quat_diff[3] = 1.0;
202   view_scale = 1.0;
203 }
204 
205 /**
206  * A GL toggle button
207  */
208 class ShapesGL : DrawingArea
209 {
210 	TestGL testGL;
211 	bool animate = false;
212 	Idle mainIdle;
213 	Menu menu;
214 	
215 	/** need to include the mixin to add GL capabilities to this widget */
216 	mixin GLCapability;
217 
218 	GLfloat width;
219 	GLfloat height;
220 	
221 	this(TestGL testGL)
222 	{
223 		mat_current = &mat_silver;
224 
225 		this.testGL = testGL;
226 		setGLCapability();	// set the GL capabilities for this widget
227 	
228 		setSizeRequest(400,400);		
229 		addOnMap(&mapCallback);	                         // dispatcher.addMapListener(this,da);
230 		addOnVisibilityNotify(&visibilityCallback);      // dispatcher.addVisibilityListener(this,da);
231 		addOnButtonPress(&mouseButtonPressCallback);     // dispatcher.addMouseButtonListener(this,da);
232 		addOnButtonRelease(&mouseButtonReleaseCallback); // dispatcher.addMouseMotionListener(this,da);
233 		addOnMotionNotify(&motionNotifyCallback);
234 			
235 		menu = createPopupMenu();
236 	}		
237 
238 	bool visibilityCallback(Event e, Widget widget)
239 	{
240 		if (animate)
241 		{
242 			if (e.visibility.state == VisibilityState.FULLY_OBSCURED)
243 			{
244 				removeIdle();
245 			}
246 			else
247 			{
248 				addIdle();
249 			}
250 		}
251 		
252 		return true;
253 	}
254 	
255 	bool idleCallback()
256 	{
257 		return drawFrame();
258 	}
259 	
260 	bool drawGL()
261 	{
262 		float m[4][4];
263 
264 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
265 
266 		glLoadIdentity();
267 		
268 		/* View transformation. */
269 		glTranslatef(0.0, 0.0, -10.0);
270 		glScalef(view_scale, view_scale, view_scale);
271 		add_quats(view_quat_diff, view_quat, view_quat);
272 		build_rotmatrix(m, view_quat);
273 		glMultMatrixf(&m[0][0]);
274 		
275 		/* Render shape */
276 		glMaterialfv(GL_FRONT, GL_AMBIENT, mat_current.ambient.ptr);
277 		glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_current.diffuse.ptr);
278 		glMaterialfv(GL_FRONT, GL_SPECULAR, mat_current.specular.ptr);
279 		glMaterialf(GL_FRONT, GL_SHININESS, mat_current.shininess * 128.0);
280 		glCallList(shape_list_base + shape_current);
281 
282 		return true;
283 	}
284 
285 	bool resizeGL(Event e)
286 	{
287 		GLfloat w;
288 		GLfloat h;
289 		
290 		if ( e is null || e.type != GdkEventType.CONFIGURE )
291 		{
292 			w = getWidth();
293 			h = getHeight();
294 		}
295 		else
296 		{
297 			w = e.configure.width;
298 			h = e.configure.height;
299 		}
300 		
301 		width = w;
302 		height = h;
303 
304 		GLfloat aspect;
305 
306 		glViewport(0, 0, cast(int)w, cast(int)h);
307 		
308 		glMatrixMode(GL_PROJECTION);
309 		glLoadIdentity();
310 
311 		double x = w/h;
312 		double y = 1.0;
313 		if ( x > 1.0 )
314 		{
315 			y = h/w;
316 			x = 1.0;
317 		}
318 
319 		glFrustum (-x, x, -y, y, 5.0, 60.0);
320 		glMatrixMode(GL_MODELVIEW);
321 		
322 		return true;
323 	}
324 	
325 	void initGL()
326 	{
327 		static GLfloat ambient[] = [0.0, 0.0, 0.0, 1.0];
328 		static GLfloat diffuse[] = [1.0, 1.0, 1.0, 1.0];
329 		static GLfloat position[] = [0.0, 3.0, 3.0, 0.0];
330 		
331 		static GLfloat lmodel_ambient[] = [0.2, 0.2, 0.2, 1.0];
332 		static GLfloat local_view[] = [0.0];
333 
334 		resizeGL(null);
335 
336 		glClearColor(0.5, 0.5, 0.8, 1.0);
337 		glClearDepth(1.0);
338 		
339 		glLightfv(GL_LIGHT0, GL_AMBIENT, ambient.ptr);
340 		glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse.ptr);
341 		glLightfv(GL_LIGHT0, GL_POSITION, position.ptr);
342 		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient.ptr);
343 		glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view.ptr);
344 		
345 		glFrontFace(GL_CW);
346 		glEnable(GL_LIGHTING);
347 		glEnable(GL_LIGHT0);
348 		glEnable(GL_AUTO_NORMAL);
349 		glEnable(GL_NORMALIZE);
350 		glEnable(GL_DEPTH_TEST);
351 		glDepthFunc(GL_LESS);
352 		
353 		/* Shape display lists */
354 		shape_list_base = glGenLists(2); //Shapes.max);
355 		
356 		int depth = 1;
357 		GLfloat none = 0.0;
358 		GLfloat step = 1.8 / depth;
359 		GLfloat size = step / 1.8;
360 		GLfloat back = -(depth-1)*step;
361 		GLfloat start;
362 
363 		if ( depth % 2 == 1 )
364 		{
365 			start = -(depth-1)/2*step;
366 		}
367 		else
368 		{
369 			start = -depth/2*step+step/2;
370 		}
371 
372 		void addCube(GLfloat tx, GLfloat ty, GLfloat tz)
373 		{
374 			if ( tx!=none || ty!=none || tz!=none )
375 			{
376 				glTranslatef(tx, ty, tz);
377 			}
378 			drawCube(true, size);
379 		}
380 		
381 		/* Cube */
382 		glNewList(shape_list_base + Shapes.cube, GL_COMPILE);
383 		glPushMatrix();
384 
385 		for ( int z=0 ; z<depth ; z++ )
386 		{
387 			for ( int y=0 ; y<depth ; y++ )
388 			{
389 				if ( y==0 )
390 				{
391 					if ( z == 0 )
392 					{
393 						addCube(start,start,start);
394 					}
395 					else
396 					{
397 						addCube(back, back, step);
398 					}
399 				}
400 				else
401 				{
402 					addCube(back, step, none);
403 				}
404 				for ( int x=1 ; x<depth ; x++ )
405 				{
406 					addCube(step, none, none);
407 				}
408 			}
409 		}
410 
411 		glPopMatrix();
412 		glEndList();
413 		
414 		/* Sphere */
415 		glNewList(shape_list_base + Shapes.sphere, GL_COMPILE);
416 			drawSphere(true, 1.0, 30, 30);
417 		glEndList();
418 
419 		/* Cone */
420 		glNewList(shape_list_base + Shapes.cone, GL_COMPILE);
421 		glPushMatrix();
422 			glTranslatef(0.0, 0.0, -1.0);
423 			drawCone(true, 1.0, 2.0, 30, 30);
424 		glPopMatrix();
425 		glEndList();
426 		
427 		/* Torus */
428 		glNewList(shape_list_base + Shapes.torus, GL_COMPILE);
429 			drawTorus(true, 0.4, 0.8, 30, 30);
430 		glEndList();
431 		
432 		/* Tetrahedron */
433 		glNewList(shape_list_base + Shapes.tetrahedron, GL_COMPILE);
434 		glPushMatrix();
435 			glScalef(1.2, 1.2, 1.2);
436 			drawTetrahedron(true);
437 		glPopMatrix();
438 		glEndList();
439 		
440 		/* Octahedron */
441 		glNewList(shape_list_base + Shapes.octahedron, GL_COMPILE);
442 		glPushMatrix();
443 			glScalef(1.2, 1.2, 1.2);
444 			drawOctahedron(true);
445 		glPopMatrix();
446 		glEndList();
447 		
448 		/* Dodecahedron */
449 		glNewList(shape_list_base + Shapes.dodecahedron, GL_COMPILE);
450 		glPushMatrix();
451 			glScalef(0.7, 0.7, 0.7);
452 			drawDodecahedron(true);
453 		glPopMatrix();
454 		glEndList();
455 		
456 		/* Icosahedron */
457 		glNewList(shape_list_base + Shapes.icosahedron, GL_COMPILE);
458 		glPushMatrix();
459 			glScalef(1.2, 1.2, 1.2);
460 			drawIcosahedron(true);
461 		glPopMatrix();
462 		glEndList();
463 		
464 		/* Teapot */
465 		glNewList(shape_list_base + Shapes.teapot, GL_COMPILE);
466 			drawTeapot(true, 1.0);
467 		glEndList();
468 	}
469 
470 	void mapCallback(Widget drawable)
471 	{
472 		if (animate)
473 		{
474 			addIdle();
475 		}
476 	}
477 
478 	void unmapCallback(Widget drawable)
479 	{
480 		removeIdle();
481 	}
482 	
483 	void addIdle()
484 	{
485 		if ( mainIdle is null )
486 		{
487 			mainIdle = new Idle(&idleCallback);
488 		}
489 	}
490 	
491 	void removeIdle()
492 	{
493 		if ( mainIdle !is null )
494 		{
495 			mainIdle.stop();
496 			mainIdle = null;
497 		}
498 	}
499 
500 	float begin_x = 0.0;
501 	float begin_y = 0.0;
502 
503 	float dx = 0.0;
504 	float dy = 0.0;
505 
506 	bool mouseButtonPressCallback(Event event, Widget widget)
507 	{
508 		if (event.button.button == 1)
509 		{
510 			if (animate)
511 			{
512 				toggleAnimation();
513 			}
514 		}
515 		
516 		begin_x = event.button.x;
517 		begin_y = event.button.y;
518 		
519 		return false;
520 	}
521 	
522 	bool mouseButtonReleaseCallback(Event event, Widget widget)
523 	{
524 		if (event.button.button == 1)
525 		{
526 			if (!animate && ((dx*dx + dy*dy) > ANIMATE_THRESHOLD))
527 			{
528 				toggleAnimation();
529 			}
530 		}
531 		else if (event.button.button == 3)
532 		{
533 			/* Popup menu. */
534 			menu.popup(null,null,null,null,event.button.button, event.button.time);
535 			return true;
536 		}
537 		
538 		dx = 0.0;
539 		dy = 0.0;
540 		
541 		return false;
542 	}
543 
544 	bool motionNotifyCallback(Event event, Widget widget)
545 	{
546 		float w = width;
547 		float h = height;
548 		float x = event.motion.x;
549 		float y = event.motion.y;
550 		gboolean redraw = false;
551 		
552 		/* Rotation. */
553 		if (event.motion.state == ModifierType.BUTTON1_MASK )
554 		{
555 			trackball(view_quat_diff,
556 				(2.0 * begin_x - w) / w,
557 				(h - 2.0 * begin_y) / h,
558 				(2.0 * x - w) / w,
559 				(h - 2.0 * y) / h);
560 			
561 				dx = x - begin_x;
562 				dy = y - begin_y;
563 			
564 			redraw = true;
565 		}
566 		
567 		/* Scaling. */
568 		if (event.motion.state == ModifierType.BUTTON2_MASK )
569 		{
570 			view_scale = view_scale * (1.0 + (y - begin_y) / h);
571 			if (view_scale > VIEW_SCALE_MAX)
572 			{
573 				view_scale = VIEW_SCALE_MAX;
574 			}
575 			else if (view_scale < VIEW_SCALE_MIN)
576 			{
577 				view_scale = VIEW_SCALE_MIN;
578 			}
579 			
580 			redraw = true;
581 		}
582 		
583 		begin_x = x;
584 		begin_y = y;
585 		
586 		if (redraw && !animate)
587 		{
588 			queueDraw();
589 		}
590 		
591 		return true;
592 	}
593 
594 	/* Toggle animation.*/
595 	void toggleAnimation()
596 	{
597 		animate = !animate;
598 
599 		if (animate)
600 		{
601 			addIdle();
602 		}
603 		else
604 		{
605 			removeIdle();
606 			view_quat_diff[0] = 0.0;
607 			view_quat_diff[1] = 0.0;
608 			view_quat_diff[2] = 0.0;
609 			view_quat_diff[3] = 1.0;
610 			queueDraw();
611 		}
612 
613 	}
614 
615 	void activateItemCallback(MenuItem menuItem)
616 	{
617 		string action = menuItem.getActionName();
618 		version(Tango)
619 		{
620 			Stdout("activateItemCallback action = %s ")( action).newline;
621 		}
622 		else //version(Phobos)
623 		{
624 			writefln("activateItemCallback action = %s ", action);
625 		}
626 		
627 		switch(action)
628 		{
629 			case "shapes.Cube":shape_current = Shapes.cube; break;
630 			case "shapes.Sphere":shape_current = Shapes.sphere; break;
631 			case "shapes.Cone":shape_current = Shapes.cone; break;
632 			case "shapes.Torus":shape_current = Shapes.torus; break;
633 			case "shapes.Tetrahedron":shape_current = Shapes.tetrahedron; break;
634 			case "shapes.Octahedron":shape_current = Shapes.octahedron; break;
635 			case "shapes.Dodecahedron":shape_current = Shapes.dodecahedron; break;
636 			case "shapes.Icosahedron":shape_current = Shapes.icosahedron; break;
637 			case "shapes.Teapot":shape_current = Shapes.teapot; break;
638 
639 			case "materials.Emerald":mat_current = &mat_emerald;break;
640 			case "materials.Jade":mat_current = &mat_jade;break;
641 			case "materials.Obsidian":mat_current = &mat_obsidian;break;
642 			case "materials.Pearl":mat_current = &mat_pearl;break;
643 			case "materials.Ruby":mat_current = &mat_ruby;break;
644 			case "materials.Turquoise":mat_current = &mat_turquoise;break;
645 			case "materials.Brass":mat_current = &mat_brass;break;
646 			case "materials.Bronze":mat_current = &mat_bronze;break;
647 			case "materials.Chrome":mat_current = &mat_chrome;break;
648 			case "materials.Copper":mat_current = &mat_copper;break;
649 			case "materials.Gold":mat_current = &mat_gold;break;
650 			case "materials.Silver":mat_current = &mat_silver;break;
651 
652 			case "reset":init_view();break;
653 			case "fullScreen":testGL.fullscreen();break;
654 			case "unFullScreen":testGL.unfullscreen();break;
655 			default: break;
656 		}
657 
658 		queueDraw();
659 	}
660 
661 	/* Creates the popup menu.*/
662 	Menu createPopupMenu()
663 	{
664 		Menu shapes = new Menu();
665 		Menu materials = new Menu();
666 		Menu menu = new Menu();
667 		MenuItem item;
668 
669 		/*
670 		 * Shapes submenu.
671 		 */
672 		
673 		menu.append(new MenuItem(&activateItemCallback, "Cube", "shapes.Cube"));
674 		menu.append(new MenuItem("Sphere", &activateItemCallback, "shapes.Sphere"));
675 		menu.append(new MenuItem("Cone", &activateItemCallback, "shapes.Cone"));
676 		menu.append(new MenuItem("Torus", &activateItemCallback, "shapes.Torus"));
677 		menu.append(new MenuItem("Tetrahedron", &activateItemCallback, "shapes.Tetrahedron"));
678 		menu.append(new MenuItem("Octahedron", &activateItemCallback, "shapes.Octahedron"));
679 		menu.append(new MenuItem("Dodecahedron", &activateItemCallback, "shapes.Dodecahedron"));
680 		menu.append(new MenuItem("Icosahedron", &activateItemCallback, "shapes.Icosahedron"));
681 		menu.append(new MenuItem("Teapot", &activateItemCallback, "shapes.Teapot"));
682 		
683 		/*
684 		 * Materials submenu.
685 		 */
686 		menu.append(new SeparatorMenuItem());
687 		
688 		menu.append(new MenuItem("Emerald", &activateItemCallback, "materials.Emerald"));
689 		menu.append(new MenuItem("Jade", &activateItemCallback, "materials.Jade"));
690 		menu.append(new MenuItem("Obsidian", &activateItemCallback, "materials.Obsidian"));
691 		menu.append(new MenuItem("Pearl", &activateItemCallback, "materials.Pearl"));
692 		menu.append(new MenuItem("Ruby", &activateItemCallback, "materials.Ruby"));
693 		menu.append(new MenuItem("Turquoise", &activateItemCallback, "materials.Turquoise"));
694 		menu.append(new MenuItem("Brass", &activateItemCallback, "materials.Brass"));
695 		menu.append(new MenuItem("Bronze", &activateItemCallback, "materials.Bronze"));
696 		menu.append(new MenuItem("Chrome", &activateItemCallback, "materials.Chrome"));
697 		menu.append(new MenuItem("Copper", &activateItemCallback, "materials.Copper"));
698 		menu.append(new MenuItem("Gold", &activateItemCallback, "materials.Gold"));
699 		menu.append(new MenuItem("Silver", &activateItemCallback, "materials.Silver"));
700 
701 		/* reset */
702 		menu.append(new SeparatorMenuItem());
703 		menu.append(new MenuItem("Reset", &activateItemCallback, "reset"));	
704 		menu.append(new MenuItem("Fullscreen", &activateItemCallback, "fullScreen"));	
705 		menu.append(new MenuItem("un-Fullscreen", &activateItemCallback, "unFullScreen"));	
706 
707 		/* Quit */
708 		menu.append(new SeparatorMenuItem());
709 		menu.append(new MenuItem("Cancel", &activateItemCallback, "quit"));	
710 		
711 		menu.showAll();
712 		
713 		return menu;
714 	}
715 }
716 
717 class TestGL : MainWindow
718 {
719 	this()
720 	{
721 		super("GtkD ShapesGL (right-click for menu)");
722 		setReallocateRedraws(true);
723 		show();
724 	}
725 }
726  
727 void main(string[] args)
728 {
729 	Main.init(args);
730 
731 	GLdInit.init(args);
732 		
733 	TestGL testGL = new TestGL();
734 	
735 	testGL.add(new ShapesGL(testGL));
736 	testGL.showAll();
737 	
738 	Main.run();
739 }