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 testGL.ShapesGL;
28 
29 private import gtk.VBox;
30 private import gtkglc.gl;
31 private import gl.TrackBall;
32 
33 private import gtkc.glibtypes;
34 
35 version (Tango)
36 {
37     private import tango.io.Stdout;
38     private import tango.math.Math;
39     //private import tango.stdc.math;//std.math;
40     //private import tango.stdc.stdio;//std.stdio;
41 }
42 else
43 {
44     private import std.c.stdio;
45     private import std.math;
46 }
47 
48 const float DIG_2_RAD = (PI / 180.0);
49 const float RAD_2_DIG = (180.0 / PI);
50 
51 const int ANIMATE_THRESHOLD = cast(int)25.0;
52 
53 const float VIEW_SCALE_MAX = 2.0;
54 const float VIEW_SCALE_MIN = 0.5;
55 
56 const int NUM_SHAPES = 9;
57 
58 enum Shapes
59 {
60 	cube         = 0,
61 	sphere       = 1,
62 	cone         = 2,
63 	torus        = 3,
64 	tetrahedron  = 4,
65 	octahedron   = 5,
66 	dodecahedron = 6,
67 	icosahedron  = 7,
68 	teapot       = 8
69 }
70 
71 static GLuint shape_list_base = 0;
72 static GLuint shape_current = 8;
73 
74 struct MaterialProp
75 {
76   GLfloat ambient[4];
77   GLfloat diffuse[4];
78   GLfloat specular[4];
79   GLfloat shininess;
80 };
81 
82 static MaterialProp mat_emerald = {
83   [0.0215, 0.1745, 0.0215, 1.0],
84   [0.07568, 0.61424, 0.07568, 1.0],
85   [0.633, 0.727811, 0.633, 1.0],
86   0.6
87 };
88 
89 static MaterialProp mat_jade = {
90   [0.135, 0.2225, 0.1575, 1.0],
91   [0.54, 0.89, 0.63, 1.0],
92   [0.316228, 0.316228, 0.316228, 1.0],
93   0.1
94 };
95 
96 static MaterialProp mat_obsidian = {
97   [0.05375, 0.05, 0.06625, 1.0],
98   [0.18275, 0.17, 0.22525, 1.0],
99   [0.332741, 0.328634, 0.346435, 1.0],
100   0.3
101 };
102 
103 static MaterialProp mat_pearl = {
104   [0.25, 0.20725, 0.20725, 1.0],
105   [1.0, 0.829, 0.829, 1.0],
106   [0.296648, 0.296648, 0.296648, 1.0],
107   0.088
108 };
109 
110 static MaterialProp mat_ruby = {
111   [0.1745, 0.01175, 0.01175, 1.0],
112   [0.61424, 0.04136, 0.04136, 1.0],
113   [0.727811, 0.626959, 0.626959, 1.0],
114   0.6
115 };
116 
117 static MaterialProp mat_turquoise = {
118   [0.1, 0.18725, 0.1745, 1.0],
119   [0.396, 0.74151, 0.69102, 1.0],
120   [0.297254, 0.30829, 0.306678, 1.0],
121   0.1
122 };
123 
124 static MaterialProp mat_brass = {
125   [0.329412, 0.223529, 0.027451, 1.0],
126   [0.780392, 0.568627, 0.113725, 1.0],
127   [0.992157, 0.941176, 0.807843, 1.0],
128   0.21794872
129 };
130 
131 static MaterialProp mat_bronze = {
132   [0.2125, 0.1275, 0.054, 1.0],
133   [0.714, 0.4284, 0.18144, 1.0],
134   [0.393548, 0.271906, 0.166721, 1.0],
135   0.2
136 };
137 
138 static MaterialProp mat_chrome = {
139   [0.25, 0.25, 0.25, 1.0],
140   [0.4, 0.4, 0.4, 1.0],
141   [0.774597, 0.774597, 0.774597, 1.0],
142   0.6
143 };
144 
145 static MaterialProp mat_copper = {
146   [0.19125, 0.0735, 0.0225, 1.0],
147   [0.7038, 0.27048, 0.0828, 1.0],
148   [0.256777, 0.137622, 0.086014, 1.0],
149   0.1
150 };
151 
152 static MaterialProp mat_gold = {
153   [0.24725, 0.1995, 0.0745, 1.0],
154   [0.75164, 0.60648, 0.22648, 1.0],
155   [0.628281, 0.555802, 0.366065, 1.0],
156   0.4
157 };
158 
159 static MaterialProp mat_silver = {
160   [0.19225, 0.19225, 0.19225, 1.0],
161   [0.50754, 0.50754, 0.50754, 1.0],
162   [0.508273, 0.508273, 0.508273, 1.0],
163   0.4
164 };
165 
166 static MaterialProp* mat_current;
167 
168 static float view_quat_diff[4] = [ 0.0, 0.0, 0.0, 1.0 ];
169 static float view_quat[4] = [ 0.0, 0.0, 0.0, 1.0 ];
170 static float view_scale = 1.0;
171 
172 static gboolean animate = false;
173 
174 static void
175 init_view ()
176 {
177   view_quat[0] = view_quat_diff[0] = 0.0;
178   view_quat[1] = view_quat_diff[1] = 0.0;
179   view_quat[2] = view_quat_diff[2] = 0.0;
180   view_quat[3] = view_quat_diff[3] = 1.0;
181   view_scale = 1.0;
182 }
183 
184 private import glgdk.GLConfig;
185 private import glgdk.GLContext;
186 private import glgdk.GLDraw;
187 private import glgdk.GLDrawable;
188 private import gtkglc.glgdktypes;
189 private import gtkglc.glgtktypes;
190 
191 private import glgtk.GLCapability;
192 private import glgtk.GLWidget;
193 
194 private import gtk.Main;
195 
196 private import gtk.DrawingArea;
197 private import gtk.Layout;
198 private import gtk.Menu;
199 private import gtk.MenuItem;
200 private import gtk.Widget;
201 private import gtk.Button;
202 private import gtk.MainWindow;
203 private import gdk.Event;
204 private import gdk.EventStruct;
205 
206 private import gtk.Idle;
207 private import gtk.Timeout;
208 
209 /**
210  * A GL toggle button
211  */
212 class ShapesGL : DrawingArea
213 {
214 
215 	TestGL testGL;
216 	
217 	bool animate = false;
218 
219 	//GLfloat angle = 0.0;
220 	//GLfloat pos_y = 0.0;
221 
222 	//int idleID;
223 	
224 	Idle mainIdle;
225 	
226 	//DrawingArea da;
227 	
228 	Menu menu;
229 	
230 	/** need to include the mixin to add GL capabilities to this widget */
231 	mixin GLCapability;
232 
233 	GLfloat width;
234 	GLfloat height;
235 	
236 	this(TestGL testGL)
237 	{
238 		mat_current = &mat_silver;
239 
240 		this.testGL = testGL;
241 		//super(false,0);
242 		//super(null, null);
243 		setGLCapability();	// set the GL capabilities for this widget
244 	
245 		setSizeRequest(400,400);		
246 		addOnRealize(&realizeCallback);						// dispatcher.addRealizeListener(this,da);
247 		addOnMap(&mapCallback);								// dispatcher.addMapListener(this,da);
248 		addOnExpose(&exposeCallback);						// dispatcher.addExposeListener(this,da);
249 		//addOnConfigure(&configureCallback);					// dispatcher.addConfigureListener(this,da);
250 		addOnVisibilityNotify(&visibilityCallback);			// dispatcher.addVisibilityListener(this,da);
251 		//dispatcher.addButtonClickedListener(this,da);
252 		addOnButtonPress(&mouseButtonPressCallback);		// dispatcher.addMouseButtonListener(this,da);
253 		addOnButtonRelease(&mouseButtonReleaseCallback);	// dispatcher.addMouseMotionListener(this,da);
254 			
255 		//da.addOnVisibilityNotify(&visibilityCallback);
256 			
257 		addOnMotionNotify(&motionNotifyCallback);
258 			
259 		menu = createPopupMenu();
260 	}		
261 
262 
263 	bool visibilityCallback(GdkEventVisibility* e, Widget widget)
264 	{
265 		if (animate)
266 		{
267 			if (e.state == VisibilityState.FULLY_OBSCURED)
268 			{
269 				removeIdle();
270 			}
271 			else
272 			{
273 				addIdle();
274 			}
275 		}
276 		
277 		return true;
278 	}
279 
280 	
281 	bool idleCallback()
282 	{
283 		glDrawFrame(this);
284 		return true;
285 	}
286 	
287 	bool exposeCallback(GdkEventExpose* e, Widget widget)
288 	{
289 		glDrawFrame(widget);
290 		return true;
291 	}
292 	
293 	/**
294 	 * put any gl initializations here
295 	 * returns true to consume the event
296 	 */
297 	bool initGL()
298 	{
299 		resizeGL(null);
300 		return true;
301 	}
302 	
303 
304 private import gdk.Font;
305 private import gdk.Drawable;
306 private import gdk.GC;
307 	
308 	bool drawGL(GdkEventExpose* event = null)
309 	{
310 		float m[4][4];
311 
312 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
313 
314 		glLoadIdentity();
315 		
316 		/* View transformation. */
317 		glTranslatef(0.0, 0.0, -10.0);
318 		glScalef(view_scale, view_scale, view_scale);
319 		add_quats(view_quat_diff, view_quat, view_quat);
320 		build_rotmatrix(m, view_quat);
321 		glMultMatrixf(&m[0][0]);
322 		
323 		/* Render shape */
324 		glMaterialfv(GL_FRONT, GL_AMBIENT, mat_current.ambient.ptr);
325 		glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_current.diffuse.ptr);
326 		glMaterialfv(GL_FRONT, GL_SPECULAR, mat_current.specular.ptr);
327 		glMaterialf(GL_FRONT, GL_SHININESS, mat_current.shininess * 128.0);
328 		glCallList(shape_list_base + shape_current);
329 
330 		
331 		return true;
332 
333 	}
334 
335 	bool noExposeCallback(Widget widget){return false;}
336 
337 	bool resizeGL(GdkEventConfigure* e)
338 	{
339 		GLfloat w;
340 		GLfloat h;
341 		
342 		if ( e == null )
343 		{
344 			w = getWidth();
345 			h = getHeight();
346 		}
347 		else
348 		{
349 			w = e.width;
350 			h = e.height;
351 		}
352 		
353 		width = w;
354 		height = h;
355 		
356 		GLfloat aspect;
357 
358 		glViewport(0, 0, cast(int)w, cast(int)h);
359 		
360 		glMatrixMode(GL_PROJECTION);
361 		glLoadIdentity();
362 
363 		double x = w/h;
364 		double y = 1.0;
365 		if ( x > 1.0 )
366 		{
367 			y = h/w;
368 			x = 1.0;
369 		}
370 		glFrustum (-x, x, -y, y, 5.0, 60.0);
371 
372 		//if (w > h)
373 		//{
374 		//	aspect = w / h;
375 		//	glFrustum(-aspect, aspect, -1.0, 1.0, 5.0, 60.0);
376 		//}
377 		//else
378 		//{
379 		//	aspect = h / w;
380 		//	glFrustum(-1.0, 1.0, -aspect, aspect, 5.0, 60.0);
381 		//}
382 		
383 		glMatrixMode(GL_MODELVIEW);
384 		
385 		return true;
386 	}
387 
388 	void addIdle()
389 	{
390 		if ( mainIdle is null )
391 		{
392 			mainIdle = new Idle(&idleCallback);
393 		}
394 	}
395 	
396 	void removeIdle()
397 	{
398 		if ( mainIdle !is null )
399 		{
400 			mainIdle.stop();
401 			mainIdle = null;
402 		}
403 	}
404 
405 	void mapCallback(Widget drawable)
406 	{
407 		if (animate)
408 		{
409 			addIdle();
410 		}
411 	}
412 
413 	void unmapCallback(Widget drawable)
414 	{
415 		removeIdle();
416 	}
417 
418 //	void buttonClickedCallback(Button button, String action)
419 //	{
420 //	}
421 
422 	void realizeCallback(Widget widget)
423 	{
424 		GLContext context = GLWidget.getGLContext(widget);
425 		GLDrawable drawable = GLWidget.getGLDrawable(widget);
426 		
427 		static GLfloat ambient[] = [0.0, 0.0, 0.0, 1.0];
428 		static GLfloat diffuse[] = [1.0, 1.0, 1.0, 1.0];
429 		static GLfloat position[] = [0.0, 3.0, 3.0, 0.0];
430 		
431 		static GLfloat lmodel_ambient[] = [0.2, 0.2, 0.2, 1.0];
432 		static GLfloat local_view[] = [0.0];
433 		
434 		/*** OpenGL BEGIN ***/
435 		if (!drawable.glBegin(context) )
436 		{
437 			return ;
438 		}
439 		
440 		glClearColor(0.5, 0.5, 0.8, 1.0);
441 		glClearDepth(1.0);
442 		
443 		glLightfv(GL_LIGHT0, GL_AMBIENT, ambient.ptr);
444 		glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse.ptr);
445 		glLightfv(GL_LIGHT0, GL_POSITION, position.ptr);
446 		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient.ptr);
447 		glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view.ptr);
448 		
449 		glFrontFace(GL_CW);
450 		glEnable(GL_LIGHTING);
451 		glEnable(GL_LIGHT0);
452 		glEnable(GL_AUTO_NORMAL);
453 		glEnable(GL_NORMALIZE);
454 		glEnable(GL_DEPTH_TEST);
455 		glDepthFunc(GL_LESS);
456 		
457 		/* Shape display lists */
458 		shape_list_base = glGenLists(Shapes.max);
459 
460 		
461 		int depth = 1;
462 		GLfloat none = 0.0;
463 		GLfloat step = 1.8 / depth;
464 		GLfloat size = step / 1.8;
465 		GLfloat back = -(depth-1)*step;
466 		GLfloat start;
467 		if ( depth % 2 == 1 )
468 		{
469 			start = -(depth-1)/2*step;
470 		}
471 		else
472 		{
473 			start = -depth/2*step+step/2;
474 		}
475 
476 		void addCube(GLfloat tx, GLfloat ty, GLfloat tz)
477 		{
478 			if ( tx!=none || ty!=none || tz!=none )
479 			{
480 				glTranslatef(tx, ty, tz);
481 			}
482 			GLDraw.cube(true, size);
483 		}
484 		
485 		/* Cube */
486 		glNewList(shape_list_base + Shapes.cube, GL_COMPILE);
487 		glPushMatrix();
488 		
489 		for ( int z=0 ; z<depth ; z++ )
490 		{
491 			for ( int y=0 ; y<depth ; y++ )
492 			{
493 				if ( y==0 )
494 				{
495 					if ( z == 0 )
496 					{
497 						addCube(start,start,start);
498 					}
499 					else
500 					{
501 						addCube(back, back, step);
502 					}
503 				}
504 				else
505 				{
506 					addCube(back, step, none);
507 				}
508 				for ( int x=1 ; x<depth ; x++ )
509 				{
510 					addCube(step, none, none);
511 				}
512 			}
513 		}
514 
515 		glPopMatrix();
516 		glEndList();
517 		
518 		/* Sphere */
519 		glNewList(shape_list_base + Shapes.sphere, GL_COMPILE);
520 		GLDraw.sphere(true, 1.0, 30, 30);
521 		glEndList();
522 		
523 		/* Cone */
524 		glNewList(shape_list_base + Shapes.cone, GL_COMPILE);
525 		glPushMatrix();
526 		  glTranslatef(0.0, 0.0, -1.0);
527 		  GLDraw.cone(true, 1.0, 2.0, 30, 30);
528 		glPopMatrix();
529 		glEndList();
530 		
531 		/* Torus */
532 		glNewList(shape_list_base + Shapes.torus, GL_COMPILE);
533 		GLDraw.torus(true, 0.4, 0.8, 30, 30);
534 		glEndList();
535 		
536 		/* Tetrahedron */
537 		glNewList(shape_list_base + Shapes.tetrahedron, GL_COMPILE);
538 		glPushMatrix();
539 		  glScalef(1.2, 1.2, 1.2);
540 		  GLDraw.tetrahedron(true);
541 		glPopMatrix();
542 		glEndList();
543 		
544 		/* Octahedron */
545 		glNewList(shape_list_base + Shapes.octahedron, GL_COMPILE);
546 		glPushMatrix();
547 		  glScalef(1.2, 1.2, 1.2);
548 		  GLDraw.octahedron(true);
549 		glPopMatrix();
550 		glEndList();
551 		
552 		/* Dodecahedron */
553 		glNewList(shape_list_base + Shapes.dodecahedron, GL_COMPILE);
554 		glPushMatrix();
555 		  glScalef(0.7, 0.7, 0.7);
556 		  GLDraw.dodecahedron(true);
557 		glPopMatrix();
558 		glEndList();
559 		
560 		/* Icosahedron */
561 		glNewList(shape_list_base + Shapes.icosahedron, GL_COMPILE);
562 		glPushMatrix();
563 		  glScalef(1.2, 1.2, 1.2);
564 		  GLDraw.icosahedron(true);
565 		glPopMatrix();
566 		glEndList();
567 		
568 		/* Teapot */
569 		glNewList(shape_list_base + Shapes.teapot, GL_COMPILE);
570 		GLDraw.teapot(true, 1.0);
571 		glEndList();
572 		
573 		drawable.glEnd();
574 		/*** OpenGL END ***/
575 		
576 		return;
577 	}
578 
579 	bool unrealizeCallback(Widget widget){return false;}
580 
581 static float begin_x = 0.0;
582 static float begin_y = 0.0;
583 
584 static float dx = 0.0;
585 static float dy = 0.0;
586 
587 
588 	bool mouseButtonPressCallback(GdkEventButton*event, Widget widget)
589 	{
590 		if (event.button == 1)
591 		{
592 			if (animate)
593 			{
594 				toggleAnimation();
595 			}
596 		}
597 		
598 		begin_x = event.x;
599 		begin_y = event.y;
600 		
601 		return false;
602 	}
603 	
604 	bool mouseButtonReleaseCallback(GdkEventButton*event, Widget widget)
605 	{
606 		if (event.button == 1)
607 		{
608 			if (!animate && ((dx*dx + dy*dy) > ANIMATE_THRESHOLD))
609 			{
610 				toggleAnimation();
611 			}
612 		}
613 		else if (event.button == 3)
614 		{
615 			/* Popup menu. */
616 			menu.popup(null,null,null,null,event.button, event.time);
617 			return true;
618 		}
619 		
620 		dx = 0.0;
621 		dy = 0.0;
622 		
623 		return false;
624 	}
625 
626 	bool motionNotifyCallback(GdkEventMotion* event, Widget widget)
627 	{
628 		float w = width;
629 		float h = height;
630 		float x = event.x;
631 		float y = event.y;
632 		gboolean redraw = false;
633 		
634 		/* Rotation. */
635 		if (event.state == ModifierType.BUTTON1_MASK )
636 		{
637 			trackball(view_quat_diff,
638 				(2.0 * begin_x - w) / w,
639 				(h - 2.0 * begin_y) / h,
640 				(2.0 * x - w) / w,
641 				(h - 2.0 * y) / h);
642 			
643 				dx = x - begin_x;
644 				dy = y - begin_y;
645 			
646 			redraw = true;
647 		}
648 		
649 		/* Scaling. */
650 		if (event.state == ModifierType.BUTTON2_MASK )
651 		{
652 			view_scale = view_scale * (1.0 + (y - begin_y) / h);
653 			if (view_scale > VIEW_SCALE_MAX)
654 			{
655 				view_scale = VIEW_SCALE_MAX;
656 			}
657 			else if (view_scale < VIEW_SCALE_MIN)
658 			{
659 				view_scale = VIEW_SCALE_MIN;
660 			}
661 			
662 			redraw = true;
663 		}
664 		
665 		begin_x = x;
666 		begin_y = y;
667 		
668 		if (redraw && !animate)
669 		{
670 			queueDraw();
671 		}
672 		
673 		return true;
674 	}
675 
676 //static gboolean
677 //key_press_event (GtkWidget   *widget,
678 //		 GdkEventKey *event,
679 //		 gpointer     data)
680 //{
681 //  switch (event->keyval)
682 //    {
683 //    case GDK_Escape:
684 //      gtk_main_quit ();
685 //      break;
686 //
687 //    default:
688 //      return false;
689 //    }
690 //
691 //  return true;
692 //}
693 
694 	/* Toggle animation.*/
695 	void toggleAnimation()
696 	{
697 		animate = !animate;
698 
699 		if (animate)
700 		{
701 			addIdle();
702 		}
703 		else
704 		{
705 			removeIdle();
706 			view_quat_diff[0] = 0.0;
707 			view_quat_diff[1] = 0.0;
708 			view_quat_diff[2] = 0.0;
709 			view_quat_diff[3] = 1.0;
710 			queueDraw();
711 		}
712 
713 	}
714 
715 //	static void
716 //	change_shape (GtkMenuItem  *menuitem, GLuint *shape)
717 //	{
718 //	  shape_current = *shape;
719 //	  init_view();
720 //	}
721 //
722 //	static void
723 //	change_material (GtkMenuItem  *menuitem,
724 //					 MaterialProp *mat)
725 //	{
726 //	  mat_current = mat;
727 //	}
728 
729 //	/* For popup menu. */
730 //	static gboolean
731 //	button_press_event_popup_menu (GtkWidget      *widget,
732 //					   GdkEventButton *event,
733 //					   gpointer        data)
734 //	{
735 //	  if (event->button == 3)
736 //		{
737 //		  /* Popup menu. */
738 //		  gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
739 //				  event->button, event->time);
740 //		  return true;
741 //		}
742 //	
743 //	  return false;
744 //	}
745 //
746 
747 //	void activateCallback(MenuItem menuItem, string action)
748 //	{
749 //	}
750 	void activateItemCallback(MenuItem menuItem)
751 	{
752 		string action = menuItem.getActionName();
753 		version(Tango)
754 		{
755 			Stdout("activateItemCallback action = %s ")( action).newline;
756 		}
757 		else //version(Phobos)
758 		{
759 			printf("activateItemCallback action = %.*s \n", action);
760 		}
761 		
762 		switch(action)
763 		{
764 			case "shapes.Cube":shape_current = Shapes.cube; break;
765 			case "shapes.Sphere":shape_current = Shapes.sphere; break;
766 			case "shapes.Cone":shape_current = Shapes.cone; break;
767 			case "shapes.Torus":shape_current = Shapes.torus; break;
768 			case "shapes.Tetrahedron":shape_current = Shapes.tetrahedron; break;
769 			case "shapes.Octahedron":shape_current = Shapes.octahedron; break;
770 			case "shapes.Dodecahedron":shape_current = Shapes.dodecahedron; break;
771 			case "shapes.Icosahedron":shape_current = Shapes.icosahedron; break;
772 			case "shapes.Teapot":shape_current = Shapes.teapot; break;
773 
774 			case "materials.Emerald":mat_current = &mat_emerald;break;
775 			case "materials.Jade":mat_current = &mat_jade;break;
776 			case "materials.Obsidian":mat_current = &mat_obsidian;break;
777 			case "materials.Pearl":mat_current = &mat_pearl;break;
778 			case "materials.Ruby":mat_current = &mat_ruby;break;
779 			case "materials.Turquoise":mat_current = &mat_turquoise;break;
780 			case "materials.Brass":mat_current = &mat_brass;break;
781 			case "materials.Bronze":mat_current = &mat_bronze;break;
782 			case "materials.Chrome":mat_current = &mat_chrome;break;
783 			case "materials.Copper":mat_current = &mat_copper;break;
784 			case "materials.Gold":mat_current = &mat_gold;break;
785 			case "materials.Silver":mat_current = &mat_silver;break;
786 			case "reset":init_view();break;
787 			case "fullScreen":testGL.fullscreen();break;
788 			case "unFullScreen":testGL.unfullscreen();break;
789 			default: break;
790 		}
791     	//init_view();
792 	}
793 
794 	/* Creates the popup menu.*/
795 	Menu createPopupMenu()
796 	{
797 		Menu shapes = new Menu();
798 		Menu materials = new Menu();
799 		Menu menu = new Menu();
800 		MenuItem item;
801 
802 		/*
803 		 * Shapes submenu.
804 		 */
805 		
806 		menu.append(new MenuItem(&activateItemCallback, "Cube", "shapes.Cube"));
807 		menu.append(new MenuItem("Sphere", &activateItemCallback, "shapes.Sphere"));
808 		menu.append(new MenuItem("Cone", &activateItemCallback, "shapes.Cone"));
809 		menu.append(new MenuItem("Torus", &activateItemCallback, "shapes.Torus"));
810 		menu.append(new MenuItem("Tetrahedron", &activateItemCallback, "shapes.Tetrahedron"));
811 		menu.append(new MenuItem("Octahedron", &activateItemCallback, "shapes.Octahedron"));
812 		menu.append(new MenuItem("Dodecahedron", &activateItemCallback, "shapes.Dodecahedron"));
813 		menu.append(new MenuItem("Icosahedron", &activateItemCallback, "shapes.Icosahedron"));
814 		menu.append(new MenuItem("Teapot", &activateItemCallback, "shapes.Teapot"));
815 		
816 		/*
817 		 * Materials submenu.
818 		 */
819 		menu.append(new SeparatorMenuItem());
820 		
821 		menu.append(new MenuItem("Emerald", &activateItemCallback, "materials.Emerald"));
822 		menu.append(new MenuItem("Jade", &activateItemCallback, "materials.Jade"));
823 		menu.append(new MenuItem("Obsidian", &activateItemCallback, "materials.Obsidian"));
824 		menu.append(new MenuItem("Pearl", &activateItemCallback, "materials.Pearl"));
825 		menu.append(new MenuItem("Ruby", &activateItemCallback, "materials.Ruby"));
826 		menu.append(new MenuItem("Turquoise", &activateItemCallback, "materials.Turquoise"));
827 		menu.append(new MenuItem("Brass", &activateItemCallback, "materials.Brass"));
828 		menu.append(new MenuItem("Bronze", &activateItemCallback, "materials.Bronze"));
829 		menu.append(new MenuItem("Chrome", &activateItemCallback, "materials.Chrome"));
830 		menu.append(new MenuItem("Copper", &activateItemCallback, "materials.Copper"));
831 		menu.append(new MenuItem("Gold", &activateItemCallback, "materials.Gold"));
832 		menu.append(new MenuItem("Silver", &activateItemCallback, "materials.Silver"));
833 
834 		/* 
835 		 * Root popup menu.
836 	     */
837 	
838 //		item = new MenuItem("Shapes");
839 //		menu.append(item);
840 //		item.setSubmenu(shapes);
841 //		
842 //		item = new MenuItem("Materials");
843 //		menu.append(item);
844 //		item.setSubmenu(materials);
845 
846 		/* reset */
847 		menu.append(new SeparatorMenuItem());
848 		menu.append(new MenuItem("Reset", &activateItemCallback, "reset"));	
849 		menu.append(new MenuItem("Fullscreen", &activateItemCallback, "fullScreen"));	
850 		menu.append(new MenuItem("un-Fullscreen", &activateItemCallback, "unFullScreen"));	
851 
852 		/* Quit */
853 		menu.append(new SeparatorMenuItem());
854 		menu.append(new MenuItem("Cancel", &activateItemCallback, "quit"));	
855 		
856 		menu.showAll();
857 		
858 		return menu;
859 	}
860 private import gtk.SeparatorMenuItem;
861 //static void
862 //print_gl_config_attrib (GdkGLConfig *glconfig,
863 //                        const gchar *attrib_str,
864 //                        int          attrib,
865 //                        gboolean     is_boolean)
866 //{
867 //  int value;
868 //
869 //  g_print ("%s = ", attrib_str);
870 //  if (gdk_gl_config_get_attrib (glconfig, attrib, &value))
871 //    {
872 //      if (is_boolean)
873 //        g_print ("%s\n", value == true ? "true" : "false");
874 //      else
875 //        g_print ("%d\n", value);
876 //    }
877 //  else
878 //    g_print ("*** Cannot get %s attribute value\n", attrib_str);
879 //}
880 //
881 //static void
882 //examine_gl_config_attrib (GdkGLConfig *glconfig)
883 //{
884 //  g_print ("\nOpenGL visual configurations :\n\n");
885 //
886 //  g_print ("gdk_gl_config_is_rgba (glconfig) = %s\n",
887 //           gdk_gl_config_is_rgba (glconfig) ? "true" : "false");
888 //  g_print ("gdk_gl_config_is_double_buffered (glconfig) = %s\n",
889 //           gdk_gl_config_is_double_buffered (glconfig) ? "true" : "false");
890 //  g_print ("gdk_gl_config_is_stereo (glconfig) = %s\n",
891 //           gdk_gl_config_is_stereo (glconfig) ? "true" : "false");
892 //  g_print ("gdk_gl_config_has_alpha (glconfig) = %s\n",
893 //           gdk_gl_config_has_alpha (glconfig) ? "true" : "false");
894 //  g_print ("gdk_gl_config_has_depth_buffer (glconfig) = %s\n",
895 //           gdk_gl_config_has_depth_buffer (glconfig) ? "true" : "false");
896 //  g_print ("gdk_gl_config_has_stencil_buffer (glconfig) = %s\n",
897 //           gdk_gl_config_has_stencil_buffer (glconfig) ? "true" : "false");
898 //  g_print ("gdk_gl_config_has_accum_buffer (glconfig) = %s\n",
899 //           gdk_gl_config_has_accum_buffer (glconfig) ? "true" : "false");
900 //
901 //  g_print ("\n");
902 //
903 //  print_gl_config_attrib (glconfig, "GDK_GL_USE_GL",           GDK_GL_USE_GL,           true);
904 //  print_gl_config_attrib (glconfig, "GDK_GL_BUFFER_SIZE",      GDK_GL_BUFFER_SIZE,      false);
905 //  print_gl_config_attrib (glconfig, "GDK_GL_LEVEL",            GDK_GL_LEVEL,            false);
906 //  print_gl_config_attrib (glconfig, "GDK_GL_RGBA",             GDK_GL_RGBA,             true);
907 //  print_gl_config_attrib (glconfig, "GDK_GL_DOUBLEBUFFER",     GDK_GL_DOUBLEBUFFER,     true);
908 //  print_gl_config_attrib (glconfig, "GDK_GL_STEREO",           GDK_GL_STEREO,           true);
909 //  print_gl_config_attrib (glconfig, "GDK_GL_AUX_BUFFERS",      GDK_GL_AUX_BUFFERS,      false);
910 //  print_gl_config_attrib (glconfig, "GDK_GL_RED_SIZE",         GDK_GL_RED_SIZE,         false);
911 //  print_gl_config_attrib (glconfig, "GDK_GL_GREEN_SIZE",       GDK_GL_GREEN_SIZE,       false);
912 //  print_gl_config_attrib (glconfig, "GDK_GL_BLUE_SIZE",        GDK_GL_BLUE_SIZE,        false);
913 //  print_gl_config_attrib (glconfig, "GDK_GL_ALPHA_SIZE",       GDK_GL_ALPHA_SIZE,       false);
914 //  print_gl_config_attrib (glconfig, "GDK_GL_DEPTH_SIZE",       GDK_GL_DEPTH_SIZE,       false);
915 //  print_gl_config_attrib (glconfig, "GDK_GL_STENCIL_SIZE",     GDK_GL_STENCIL_SIZE,     false);
916 //  print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_RED_SIZE",   GDK_GL_ACCUM_RED_SIZE,   false);
917 //  print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_GREEN_SIZE", GDK_GL_ACCUM_GREEN_SIZE, false);
918 //  print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_BLUE_SIZE",  GDK_GL_ACCUM_BLUE_SIZE,  false);
919 //  print_gl_config_attrib (glconfig, "GDK_GL_ACCUM_ALPHA_SIZE", GDK_GL_ACCUM_ALPHA_SIZE, false);
920 //
921 //  g_print ("\n");
922 //}
923 
924 
925   
926 }
927 
928 
929 
930 public:
931 class TestGL : MainWindow
932 {
933 	this()
934 	{
935 		super("GtkD ShapesGL (right-click for menu)");
936 		setReallocateRedraws(true);
937 		//setBorderWidth(10);
938 		show();
939 	}
940 }
941  
942  
943 private import glgdk.GLdInit;
944 
945 void main(string[] args)
946 {
947 	
948 	
949 	Main.init(args);
950 
951 	GLdInit.init(args);
952 		
953 	TestGL testGL = new TestGL();
954 	
955 	
956 	testGL.add(new ShapesGL(testGL));
957 	testGL.showAll();
958 	
959 	Main.run();
960 
961 	
962 }