2 * 3-D gear wheels. This program is in the public domain.
7 /* Conversion to GLUT by Mark J. Kilgard */
9 /* Conversion to GtkGLExt by Naofumi Yasufuku */
16 #include <gdk/gdkkeysyms.h>
18 #include <gtk/gtkgl.h>
21 #define WIN32_LEAN_AND_MEAN 1
29 * Draw a gear wheel. You'll probably want to call this function when
30 * building a display list since we do a lot of trig here.
32 * Input: inner_radius - radius of hole at center
33 * outer_radius - radius at center of teeth
34 * width - width of gear
35 * teeth - number of teeth
36 * tooth_depth - depth of tooth
40 gear(GLfloat inner_radius,
52 r1 = outer_radius - tooth_depth / 2.0;
53 r2 = outer_radius + tooth_depth / 2.0;
55 da = 2.0 * G_PI / teeth / 4.0;
57 glShadeModel(GL_FLAT);
59 glNormal3f(0.0, 0.0, 1.0);
62 glBegin(GL_QUAD_STRIP);
63 for (i = 0; i <= teeth; i++) {
64 angle = i * 2.0 * G_PI / teeth;
65 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
66 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
68 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
69 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
74 /* draw front sides of teeth */
76 da = 2.0 * G_PI / teeth / 4.0;
77 for (i = 0; i < teeth; i++) {
78 angle = i * 2.0 * G_PI / teeth;
80 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
81 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
82 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
83 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
87 glNormal3f(0.0, 0.0, -1.0);
90 glBegin(GL_QUAD_STRIP);
91 for (i = 0; i <= teeth; i++) {
92 angle = i * 2.0 * G_PI / teeth;
93 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
94 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
96 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
97 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
102 /* draw back sides of teeth */
104 da = 2.0 * G_PI / teeth / 4.0;
105 for (i = 0; i < teeth; i++) {
106 angle = i * 2.0 * G_PI / teeth;
108 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
109 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
110 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
111 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
115 /* draw outward faces of teeth */
116 glBegin(GL_QUAD_STRIP);
117 for (i = 0; i < teeth; i++) {
118 angle = i * 2.0 * G_PI / teeth;
120 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
121 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
122 u = r2 * cos(angle + da) - r1 * cos(angle);
123 v = r2 * sin(angle + da) - r1 * sin(angle);
124 len = sqrt(u * u + v * v);
127 glNormal3f(v, -u, 0.0);
128 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
129 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
130 glNormal3f(cos(angle), sin(angle), 0.0);
131 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
132 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
133 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
134 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
135 glNormal3f(v, -u, 0.0);
136 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
137 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
138 glNormal3f(cos(angle), sin(angle), 0.0);
141 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
142 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
146 glShadeModel(GL_SMOOTH);
148 /* draw inside radius cylinder */
149 glBegin(GL_QUAD_STRIP);
150 for (i = 0; i <= teeth; i++) {
151 angle = i * 2.0 * G_PI / teeth;
152 glNormal3f(-cos(angle), -sin(angle), 0.0);
153 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
154 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
160 static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
161 static GLint gear1, gear2, gear3;
162 static GLfloat angle = 0.0;
164 static GTimer *timer = NULL;
165 static gint frames = 0;
167 static gboolean is_sync = TRUE;
170 draw (GtkWidget *widget,
171 GdkEventExpose *event,
174 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
175 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
177 /*** OpenGL BEGIN ***/
178 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
181 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
184 glRotatef (view_rotx, 1.0, 0.0, 0.0);
185 glRotatef (view_roty, 0.0, 1.0, 0.0);
186 glRotatef (view_rotz, 0.0, 0.0, 1.0);
189 glTranslatef (-3.0, -2.0, 0.0);
190 glRotatef (angle, 0.0, 0.0, 1.0);
195 glTranslatef (3.1, -2.0, 0.0);
196 glRotatef (-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
201 glTranslatef (-3.1, 4.2, 0.0);
202 glRotatef (-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
208 if (gdk_gl_drawable_is_double_buffered (gldrawable))
209 gdk_gl_drawable_swap_buffers (gldrawable);
213 gdk_gl_drawable_gl_end (gldrawable);
219 gdouble seconds = g_timer_elapsed (timer, NULL);
220 if (seconds >= 5.0) {
221 gdouble fps = frames / seconds;
222 g_print ("%d frames in %6.3f seconds = %6.3f FPS\n", frames, seconds, fps);
223 g_timer_reset (timer);
231 /* new window size or exposure */
233 reshape (GtkWidget *widget,
234 GdkEventConfigure *event,
237 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
238 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
240 GLfloat h = (GLfloat) (widget->allocation.height) / (GLfloat) (widget->allocation.width);
242 /*** OpenGL BEGIN ***/
243 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
246 glViewport (0, 0, widget->allocation.width, widget->allocation.height);
247 glMatrixMode (GL_PROJECTION);
249 glFrustum (-1.0, 1.0, -h, h, 5.0, 60.0);
250 glMatrixMode (GL_MODELVIEW);
252 glTranslatef (0.0, 0.0, -40.0);
254 gdk_gl_drawable_gl_end (gldrawable);
261 init(GtkWidget *widget,
264 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
265 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
267 static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0};
268 static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0};
269 static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0};
270 static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0};
272 /*** OpenGL BEGIN ***/
273 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
276 glLightfv (GL_LIGHT0, GL_POSITION, pos);
277 glEnable (GL_CULL_FACE);
278 glEnable (GL_LIGHTING);
279 glEnable (GL_LIGHT0);
280 glEnable (GL_DEPTH_TEST);
283 gear1 = glGenLists (1);
284 glNewList (gear1, GL_COMPILE);
285 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
286 gear (1.0, 4.0, 1.0, 20, 0.7);
289 gear2 = glGenLists (1);
290 glNewList (gear2, GL_COMPILE);
291 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
292 gear (0.5, 2.0, 2.0, 10, 0.7);
295 gear3 = glGenLists (1);
296 glNewList (gear3, GL_COMPILE);
297 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
298 gear (1.3, 2.0, 0.5, 10, 0.7);
301 glEnable (GL_NORMALIZE);
304 g_print ("GL_RENDERER = %s\n", (char *) glGetString (GL_RENDERER));
305 g_print ("GL_VERSION = %s\n", (char *) glGetString (GL_VERSION));
306 g_print ("GL_VENDOR = %s\n", (char *) glGetString (GL_VENDOR));
307 g_print ("GL_EXTENSIONS = %s\n", (char *) glGetString (GL_EXTENSIONS));
310 gdk_gl_drawable_gl_end (gldrawable);
315 timer = g_timer_new ();
317 g_timer_start (timer);
321 idle (GtkWidget *widget)
325 /* Invalidate the whole window. */
326 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
328 /* Update synchronously (fast). */
330 gdk_window_process_updates (widget->window, FALSE);
335 static guint idle_id = 0;
338 idle_add (GtkWidget *widget)
342 idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW,
350 idle_remove (GtkWidget *widget)
354 g_source_remove (idle_id);
360 map (GtkWidget *widget,
370 unmap (GtkWidget *widget,
374 idle_remove (widget);
380 visible (GtkWidget *widget,
381 GdkEventVisibility *event,
384 if (event->state == GDK_VISIBILITY_FULLY_OBSCURED)
385 idle_remove (widget);
392 /* change view angle, exit upon ESC */
394 key (GtkWidget *widget,
398 switch (event->keyval)
425 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
434 GdkGLConfig *glconfig;
437 GtkWidget *drawing_area;
445 gtk_init (&argc, &argv);
451 gtk_gl_init (&argc, &argv);
454 * Command line options.
457 for (i = 0; i < argc; i++)
459 if (strcmp (argv[i], "--async") == 0)
464 * Configure OpenGL-capable visual.
467 /* Try double-buffered visual */
468 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
471 if (glconfig == NULL)
473 g_print ("*** Cannot find the double-buffered visual.\n");
474 g_print ("*** Trying single-buffered visual.\n");
476 /* Try single-buffered visual */
477 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
479 if (glconfig == NULL)
481 g_print ("*** No appropriate OpenGL-capable visual found.\n");
490 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
491 gtk_window_set_title (GTK_WINDOW (window), "gears");
493 /* Get automatically redrawn if any of their children changed allocation. */
494 gtk_container_set_reallocate_redraws (GTK_CONTAINER (window), TRUE);
496 g_signal_connect (G_OBJECT (window), "delete_event",
497 G_CALLBACK (gtk_main_quit), NULL);
503 vbox = gtk_vbox_new (FALSE, 0);
504 gtk_container_add (GTK_CONTAINER (window), vbox);
505 gtk_widget_show (vbox);
508 * Drawing area for drawing OpenGL scene.
511 drawing_area = gtk_drawing_area_new ();
512 gtk_widget_set_size_request (drawing_area, 300, 300);
514 /* Set OpenGL-capability to the widget. */
515 gtk_widget_set_gl_capability (drawing_area,
521 gtk_widget_add_events (drawing_area,
522 GDK_VISIBILITY_NOTIFY_MASK);
524 g_signal_connect_after (G_OBJECT (drawing_area), "realize",
525 G_CALLBACK (init), NULL);
526 g_signal_connect (G_OBJECT (drawing_area), "configure_event",
527 G_CALLBACK (reshape), NULL);
528 g_signal_connect (G_OBJECT (drawing_area), "expose_event",
529 G_CALLBACK (draw), NULL);
530 g_signal_connect (G_OBJECT (drawing_area), "map_event",
531 G_CALLBACK (map), NULL);
532 g_signal_connect (G_OBJECT (drawing_area), "unmap_event",
533 G_CALLBACK (unmap), NULL);
534 g_signal_connect (G_OBJECT (drawing_area), "visibility_notify_event",
535 G_CALLBACK (visible), NULL);
537 g_signal_connect_swapped (G_OBJECT (window), "key_press_event",
538 G_CALLBACK (key), drawing_area);
540 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
542 gtk_widget_show (drawing_area);
545 * Simple quit button.
548 button = gtk_button_new_with_label ("Quit");
550 g_signal_connect (G_OBJECT (button), "clicked",
551 G_CALLBACK (gtk_main_quit), NULL);
553 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
555 gtk_widget_show (button);
561 gtk_widget_show (window);