1 // -*- C++ -*-
2 /*
3  * button.cc:
4  * Simple toggle button example.
5  *
6  * written by Naofumi Yasufuku  <naofumi@users.sourceforge.net>
7  */
8 
9 #include <iostream>
10 #include <cstdlib>
11 #include <cmath>
12 
13 #include <gtkmm.h>
14 
15 #include <gtkglmm.h>
16 
17 #ifdef G_OS_WIN32
18 #define WIN32_LEAN_AND_MEAN 1
19 #include <windows.h>
20 #endif
21 
22 #include <GL/gl.h>
23 #include <GL/glu.h>
24 
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 // OpenGL scene.
29 //
30 ///////////////////////////////////////////////////////////////////////////////
31 
32 class GLScene : public Gtk::GL::DrawingArea
33 {
34 public:
35   static const unsigned int TIMEOUT_INTERVAL;
36 
37 public:
38   GLScene(const Glib::RefPtr<const Gdk::GL::Config>& config);
39   virtual ~GLScene();
40 
41 protected:
42   virtual void on_realize();
43   virtual bool on_configure_event(GdkEventConfigure* event);
44   virtual bool on_expose_event(GdkEventExpose* event);
45   virtual bool on_map_event(GdkEventAny* event);
46   virtual bool on_unmap_event(GdkEventAny* event);
47   virtual bool on_visibility_notify_event(GdkEventVisibility* event);
48   virtual bool on_timeout();
49 
50 public:
51   // Invalidate whole window.
invalidate()52   void invalidate() {
53     get_window()->invalidate_rect(get_allocation(), false);
54   }
55 
56   // Update window synchronously (fast).
update()57   void update()
58   { get_window()->process_updates(false); }
59 
60 protected:
61   void timeout_add();
62   void timeout_remove();
63 
64 public:
65   void toggle_animation();
66 
67 protected:
68   bool m_Animate;
69   // timeout signal connection:
70   sigc::connection m_ConnectionTimeout;
71 
72 protected:
73   GLfloat m_Angle;
74   GLfloat m_PosY;
75 
76 };
77 
78 const unsigned int GLScene::TIMEOUT_INTERVAL = 10;
79 
GLScene(const Glib::RefPtr<const Gdk::GL::Config> & config)80 GLScene::GLScene(const Glib::RefPtr<const Gdk::GL::Config>& config)
81   : Gtk::GL::DrawingArea(config),
82     m_Animate(true), m_Angle(0.0), m_PosY(0.0)
83 {
84   set_size_request(200, 200);
85   add_events(Gdk::VISIBILITY_NOTIFY_MASK);
86 }
87 
~GLScene()88 GLScene::~GLScene()
89 {
90 }
91 
on_realize()92 void GLScene::on_realize()
93 {
94   // We need to call the base on_realize()
95   Gtk::GL::DrawingArea::on_realize();
96 
97   //
98   // Get GL::Window.
99   //
100 
101   Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window();
102 
103   //
104   // GL calls.
105   //
106 
107   // *** OpenGL BEGIN ***
108   if (!glwindow->gl_begin(get_gl_context()))
109     return;
110 
111   static GLfloat ambient[]  = { 0.0, 0.0, 0.0, 1.0 };
112   static GLfloat diffuse[]  = { 1.0, 1.0, 1.0, 1.0 };
113   static GLfloat position[] = { 1.0, 1.0, 1.0, 0.0 };
114   static GLfloat lmodel_ambient[] = {0.2, 0.2, 0.2, 1.0};
115   static GLfloat local_view[] = {0.0};
116 
117   glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
118   glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
119   glLightfv (GL_LIGHT0, GL_POSITION, position);
120   glLightModelfv (GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
121   glLightModelfv (GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
122   glEnable (GL_LIGHTING);
123   glEnable (GL_LIGHT0);
124   glEnable (GL_DEPTH_TEST);
125 
126   glClearColor (1.0, 1.0, 1.0, 1.0);
127   glClearDepth (1.0);
128 
129   glwindow->gl_end();
130   // *** OpenGL END ***
131 }
132 
on_configure_event(GdkEventConfigure * event)133 bool GLScene::on_configure_event(GdkEventConfigure* event)
134 {
135   //
136   // Get GL::Window.
137   //
138 
139   Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window();
140 
141   //
142   // GL calls.
143   //
144 
145   // *** OpenGL BEGIN ***
146   if (!glwindow->gl_begin(get_gl_context()))
147     return false;
148 
149   GLfloat w = get_width();
150   GLfloat h = get_height();
151   GLfloat aspect;
152 
153   glViewport(0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h));
154 
155   glMatrixMode(GL_PROJECTION);
156   glLoadIdentity();
157   if (w > h)
158     {
159       aspect = w / h;
160       glFrustum(-aspect, aspect, -1.0, 1.0, 5.0, 60.0);
161     }
162   else
163     {
164       aspect = h / w;
165       glFrustum(-1.0, 1.0, -aspect, aspect, 5.0, 60.0);
166     }
167 
168   glMatrixMode(GL_MODELVIEW);
169 
170   glwindow->gl_end();
171   // *** OpenGL END ***
172 
173   return true;
174 }
175 
on_expose_event(GdkEventExpose * event)176 bool GLScene::on_expose_event(GdkEventExpose* event)
177 {
178   //
179   // Get GL::Window.
180   //
181 
182   Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window();
183 
184   //
185   // GL calls.
186   //
187 
188   // *** OpenGL BEGIN ***
189   if (!glwindow->gl_begin(get_gl_context()))
190     return false;
191 
192   // brass
193   static GLfloat ambient[4]  = { 0.329412, 0.223529, 0.027451, 1.0 };
194   static GLfloat diffuse[4]  = { 0.780392, 0.568627, 0.113725, 1.0 };
195   static GLfloat specular[4] = { 0.992157, 0.941176, 0.807843, 1.0 };
196   static GLfloat shininess   = 0.21794872 * 128.0;
197 
198   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
199 
200   glLoadIdentity();
201   glTranslatef(0.0, 0.0, -10.0);
202 
203   glPushMatrix();
204     glTranslatef(0.0, m_PosY, 0.0);
205     glRotatef(m_Angle, 0.0, 1.0, 0.0);
206     glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
207     glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
208     glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
209     glMaterialf(GL_FRONT, GL_SHININESS, shininess);
210     glwindow->draw_torus(true, 0.3, 0.6, 30, 30);
211   glPopMatrix();
212 
213   // Swap buffers.
214   if (glwindow->is_double_buffered())
215     glwindow->swap_buffers();
216   else
217     glFlush();
218 
219   glwindow->gl_end();
220   // *** OpenGL END ***
221 
222   return true;
223 }
224 
on_timeout()225 bool GLScene::on_timeout()
226 {
227   m_Angle += 1.0;
228   if (m_Angle >= 360.0)
229     m_Angle -= 360.0;
230 
231   float t = m_Angle * G_PI / 180.0;
232   if (t > G_PI)
233     t = 2.0 * G_PI - t;
234 
235   m_PosY = 2.0 * (std::sin (t) + 0.4 * std::sin (3.0*t)) - 1.0;
236 
237   // Invalidate whole window.
238   invalidate();
239   // Update window synchronously (fast).
240   update();
241 
242   return true;
243 }
244 
timeout_add()245 void GLScene::timeout_add()
246 {
247   if (!m_ConnectionTimeout.connected())
248     m_ConnectionTimeout = Glib::signal_timeout().connect(
249       sigc::mem_fun(*this, &GLScene::on_timeout), TIMEOUT_INTERVAL);
250 }
251 
timeout_remove()252 void GLScene::timeout_remove()
253 {
254   if (m_ConnectionTimeout.connected())
255     m_ConnectionTimeout.disconnect();
256 }
257 
on_map_event(GdkEventAny * event)258 bool GLScene::on_map_event(GdkEventAny* event)
259 {
260   if (m_Animate)
261     timeout_add();
262 
263   return true;
264 }
265 
on_unmap_event(GdkEventAny * event)266 bool GLScene::on_unmap_event(GdkEventAny* event)
267 {
268   timeout_remove();
269 
270   return true;
271 }
272 
on_visibility_notify_event(GdkEventVisibility * event)273 bool GLScene::on_visibility_notify_event(GdkEventVisibility* event)
274 {
275   if (m_Animate)
276     {
277       if (event->state == GDK_VISIBILITY_FULLY_OBSCURED)
278         timeout_remove();
279       else
280         timeout_add();
281     }
282 
283   return true;
284 }
285 
toggle_animation()286 void GLScene::toggle_animation()
287 {
288   m_Animate = !m_Animate;
289 
290   if (m_Animate)
291     {
292       timeout_add();
293     }
294   else
295     {
296       timeout_remove();
297       invalidate();
298     }
299 }
300 
301 
302 ///////////////////////////////////////////////////////////////////////////////
303 //
304 // Toggle button which contains an OpenGL scene.
305 //
306 ///////////////////////////////////////////////////////////////////////////////
307 
308 class GLToggleButton : public Gtk::ToggleButton
309 {
310 public:
311   GLToggleButton(const Glib::RefPtr<const Gdk::GL::Config>& config);
312   virtual ~GLToggleButton();
313 
314 protected:
315   virtual void on_toggled();
316 
317 protected:
318   Gtk::VBox m_VBox;
319   GLScene m_GLScene;
320   Gtk::Label m_Label;
321 
322 };
323 
GLToggleButton(const Glib::RefPtr<const Gdk::GL::Config> & config)324 GLToggleButton::GLToggleButton(const Glib::RefPtr<const Gdk::GL::Config>& config)
325   : m_VBox(false, 0), m_GLScene(config), m_Label("Toggle Animation")
326 {
327   m_VBox.set_border_width(10);
328   m_VBox.pack_start(m_GLScene);
329   m_VBox.pack_start(m_Label, Gtk::PACK_SHRINK, 10);
330 
331   add(m_VBox);
332 }
333 
~GLToggleButton()334 GLToggleButton::~GLToggleButton()
335 {
336 }
337 
on_toggled()338 void GLToggleButton::on_toggled()
339 {
340   m_GLScene.toggle_animation();
341 }
342 
343 
344 ///////////////////////////////////////////////////////////////////////////////
345 //
346 // The application class.
347 //
348 ///////////////////////////////////////////////////////////////////////////////
349 
350 class Button : public Gtk::Window
351 {
352 public:
353   Button(const Glib::RefPtr<const Gdk::GL::Config>& config);
354   virtual ~Button();
355 
356 protected:
357   virtual bool on_delete_event(GdkEventAny* event);
358 
359 protected:
360   // member widgets:
361   GLToggleButton m_Button;
362 
363 };
364 
Button(const Glib::RefPtr<const Gdk::GL::Config> & config)365 Button::Button(const Glib::RefPtr<const Gdk::GL::Config>& config)
366   : m_Button(config)
367 {
368   //
369   // Top-level window.
370   //
371 
372   set_title("button");
373 
374   // Get automatically redrawn if any of their children changed allocation.
375   set_reallocate_redraws(true);
376   // Set border width.
377   set_border_width(10);
378 
379   //
380   // Add toggle button.
381   //
382 
383   add(m_Button);
384 
385   //
386   // Show window.
387   //
388 
389   show_all();
390 }
391 
~Button()392 Button::~Button()
393 {
394 }
395 
on_delete_event(GdkEventAny * event)396 bool Button::on_delete_event(GdkEventAny* event)
397 {
398   Gtk::Main::quit();
399 
400   return true;
401 }
402 
403 
404 ///////////////////////////////////////////////////////////////////////////////
405 //
406 // Main.
407 //
408 ///////////////////////////////////////////////////////////////////////////////
409 
main(int argc,char ** argv)410 int main(int argc, char** argv)
411 {
412   Gtk::Main kit(argc, argv);
413 
414   //
415   // Init gtkglextmm.
416   //
417 
418   Gtk::GL::init(argc, argv);
419 
420   //
421   // Configure OpenGL-capable visual.
422   //
423 
424   Glib::RefPtr<Gdk::GL::Config> glconfig;
425 
426   // Try double-buffered visual
427   glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB    |
428                                      Gdk::GL::MODE_DEPTH  |
429                                      Gdk::GL::MODE_DOUBLE);
430   if (!glconfig)
431     {
432       std::cerr << "*** Cannot find the double-buffered visual.\n"
433                 << "*** Trying single-buffered visual.\n";
434 
435       // Try single-buffered visual
436       glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB   |
437                                          Gdk::GL::MODE_DEPTH);
438       if (!glconfig)
439         {
440           std::cerr << "*** Cannot find any OpenGL-capable visual.\n";
441           std::exit(1);
442         }
443     }
444 
445   //
446   // Instantiate and run the application.
447   //
448 
449   Button button(glconfig);
450 
451   kit.run(button);
452 
453   return 0;
454 }
455