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