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