1 /* flyingtoasters, Copyright (c) 2003, 2004 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Draws 3D flying toasters, and toast. Inspired by the ancient
12 * Berkeley Systems / After Dark hack, but now updated to the wide
13 * wonderful workd of OpenGL and 3D!
15 * Code by jwz; object models by Baconmonkey.
17 * The original After Dark flying toasters, with the fluffy white wings,
18 * were a trademark of Berkeley Systems. Berkeley Systems ceased to exist
19 * some time in 1998, having been gobbled up by Sierra Online, who were
20 * subsequently gobbled up by Flipside and/or Vivendi (it's hard to tell
21 * exactly what happened when.)
23 * I doubt anyone even cares any more, but if they do, hopefully this homage,
24 * with the space-age 3D jet-plane toasters, will be considered different
25 * enough that whoever still owns the trademark to the fluffy-winged 2D
26 * bitmapped toasters won't get all huffy at us.
29 #include <X11/Intrinsic.h>
31 extern XtAppContext app;
33 #define PROGCLASS "FlyingToasters"
34 #define HACK_INIT init_toasters
35 #define HACK_DRAW draw_toasters
36 #define HACK_RESHAPE reshape_toasters
37 #define HACK_HANDLE_EVENT toaster_handle_event
38 #define EVENT_MASK PointerMotionMask
39 #define sws_opts xlockmore_opts
41 #define DEF_SPEED "1.0"
42 #define DEF_NTOASTERS "20"
43 #define DEF_NSLICES "25"
44 #define DEF_TEXTURE "True"
46 #define DEFAULTS "*delay: 30000 \n" \
47 "*showFPS: False \n" \
48 "*wireframe: False \n" \
53 #define countof(x) (sizeof((x))/sizeof((*x)))
56 #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
58 #include "xlockmore.h"
59 #include "gltrackball.h"
60 #include "xpm-ximage.h"
63 #include "../images/chromesphere.xpm"
64 #include "../images/toast.xpm"
66 #ifdef USE_GL /* whole file */
74 *toaster, *toaster_base, *toaster_handle, *toaster_handle2, *toaster_jet,
75 *toaster_knob, *toaster_slots, *toaster_wing, *toast, *toast2;
77 struct gllist **all_objs[] = {
78 &toaster, &toaster_base, &toaster_handle, &toaster_handle2, &toaster_jet,
79 &toaster_knob, &toaster_slots, &toaster_wing, &toast, &toast2
82 #define BASE_TOASTER 0
91 #define TOAST_BITTEN 9
94 #define GRID_DEPTH 500
97 static struct { GLfloat x, y; } nice_views[] = {
100 { 12, 28 }, /* this is a list of viewer rotations that look nice. */
101 { 12, -28 }, /* every now and then we switch to a new one. */
102 {-10, -28 }, /* (but we only use the first two at start-up.) */
116 int toast_type; /* 0, 1 */
117 GLfloat handle_pos; /* 0.0 - 1.0 */
118 GLfloat knob_pos; /* degrees */
119 int loaded; /* 2 bits */
123 GLXContext *glx_context;
124 trackball_state *user_trackball;
127 int last_view, target_view;
128 GLfloat view_x, view_y;
129 int view_steps, view_tick;
130 Bool auto_tracking_p;
133 GLuint chrome_texture;
134 GLuint toast_texture;
139 } toaster_configuration;
141 static toaster_configuration *bps = NULL;
143 static GLfloat speed;
144 static int ntoasters;
146 static int do_texture;
148 static XrmOptionDescRec opts[] = {
149 { "-speed", ".speed", XrmoptionSepArg, 0 },
150 { "-ntoasters", ".ntoasters", XrmoptionSepArg, 0 },
151 { "-nslices", ".nslices", XrmoptionSepArg, 0 },
152 {"-texture", ".texture", XrmoptionNoArg, "True" },
153 {"+texture", ".texture", XrmoptionNoArg, "False" },
156 static argtype vars[] = {
157 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
158 {&ntoasters, "ntoasters", "Count", DEF_NTOASTERS, t_Int},
159 {&nslices, "nslices", "Count", DEF_NSLICES, t_Int},
160 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
163 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
167 reset_floater (ModeInfo *mi, floater *f)
169 /* toaster_configuration *bp = &bps[MI_SCREEN(mi)]; */
171 GLfloat n = GRID_SIZE/2.0;
172 GLfloat n2 = GRID_DEPTH/2.0;
173 GLfloat delta = GRID_SIZE * speed / 200.0;
179 f->dz += BELLRAND(delta) - delta/3;
181 if (! (random() % 5)) {
182 f->dx += (BELLRAND(delta*2) - delta);
183 f->dy += (BELLRAND(delta*2) - delta);
186 if (! (random() % 40)) f->dz *= 10; /* occasional speedy one */
188 f->x = frand(n) - n/2;
189 f->y = frand(n) - n/2;
190 f->z = -n2 - frand(delta * 4);
195 f->knob_pos = frand(180) - 90;
196 f->handle_pos = ((random() & 1) ? 0.0 : 1.0);
198 if (f->handle_pos > 0.8 && (! (random() % 5)))
199 f->loaded = (random() & 3); /* let's toast! */
203 if (! (random() % 10))
204 f->toast_type = 1; /* toast_bitten */
210 tick_floater (ModeInfo *mi, floater *f)
212 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
214 GLfloat n1 = GRID_DEPTH/2.0;
215 GLfloat n2 = GRID_SIZE*4;
217 if (bp->button_down_p) return;
223 if (! (random() % 50000)) /* sudden gust of gravity */
226 if (f->x < -n2 || f->x > n2 ||
227 f->y < -n2 || f->y > n2 ||
229 reset_floater (mi, f);
234 auto_track_init (ModeInfo *mi)
236 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
237 bp->last_view = (random() % 2);
238 bp->target_view = bp->last_view + 2;
239 bp->view_x = nice_views[bp->last_view].x;
240 bp->view_y = nice_views[bp->last_view].y;
241 bp->view_steps = 100;
243 bp->auto_tracking_p = True;
248 auto_track (ModeInfo *mi)
250 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
252 if (bp->button_down_p)
255 /* if we're not moving, maybe start moving. Otherwise, do nothing. */
256 if (! bp->auto_tracking_p)
259 if (++tick < 200/speed) return;
261 if (! (random() % 5))
262 bp->auto_tracking_p = True;
269 GLfloat ox = nice_views[bp->last_view].x;
270 GLfloat oy = nice_views[bp->last_view].y;
271 GLfloat tx = nice_views[bp->target_view].x;
272 GLfloat ty = nice_views[bp->target_view].y;
274 /* move from A to B with sinusoidal deltas, so that it doesn't jerk
276 GLfloat th = sin ((M_PI / 2) * (double) bp->view_tick / bp->view_steps);
278 bp->view_x = (ox + ((tx - ox) * th));
279 bp->view_y = (oy + ((ty - oy) * th));
282 if (bp->view_tick >= bp->view_steps)
285 bp->view_steps = (350.0 / speed);
286 bp->last_view = bp->target_view;
287 bp->target_view = (random() % (countof(nice_views) - 2)) + 2;
288 bp->auto_tracking_p = False;
294 /* Window management, etc
297 reshape_toasters (ModeInfo *mi, int width, int height)
299 GLfloat h = (GLfloat) height / (GLfloat) width;
301 glViewport (0, 0, (GLint) width, (GLint) height);
303 glMatrixMode(GL_PROJECTION);
305 gluPerspective (40.0, 1/h, 1.0, 250);
307 glMatrixMode(GL_MODELVIEW);
309 gluLookAt( 0.0, 2.0, 30.0,
313 glClear(GL_COLOR_BUFFER_BIT);
318 toaster_handle_event (ModeInfo *mi, XEvent *event)
320 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
322 if (event->xany.type == ButtonPress &&
323 event->xbutton.button == Button1)
325 bp->button_down_p = True;
326 gltrackball_start (bp->user_trackball,
327 event->xbutton.x, event->xbutton.y,
328 MI_WIDTH (mi), MI_HEIGHT (mi));
331 else if (event->xany.type == ButtonRelease &&
332 event->xbutton.button == Button1)
334 bp->button_down_p = False;
337 else if (event->xany.type == ButtonPress &&
338 (event->xbutton.button == Button4 ||
339 event->xbutton.button == Button5))
341 gltrackball_mousewheel (bp->user_trackball, event->xbutton.button, 5,
342 !event->xbutton.state);
345 else if (event->xany.type == MotionNotify &&
348 gltrackball_track (bp->user_trackball,
349 event->xmotion.x, event->xmotion.y,
350 MI_WIDTH (mi), MI_HEIGHT (mi));
359 load_textures (ModeInfo *mi)
361 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
364 xi = xpm_to_ximage (mi->dpy, mi->xgwa.visual, mi->xgwa.colormap,
368 glGenTextures (1, &bp->chrome_texture);
369 glBindTexture (GL_TEXTURE_2D, bp->chrome_texture);
370 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
371 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
372 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
373 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
374 xi->width, xi->height, 0,
376 /* GL_UNSIGNED_BYTE, */
377 GL_UNSIGNED_INT_8_8_8_8_REV,
379 check_gl_error("texture");
381 xi = xpm_to_ximage (mi->dpy, mi->xgwa.visual, mi->xgwa.colormap,
384 glGenTextures (1, &bp->toast_texture);
385 glBindTexture (GL_TEXTURE_2D, bp->toast_texture);
386 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
387 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
388 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
389 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
390 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
391 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
392 xi->width, xi->height, 0,
394 /* GL_UNSIGNED_BYTE, */
395 GL_UNSIGNED_INT_8_8_8_8_REV,
397 check_gl_error("texture");
399 glEnable(GL_TEXTURE_GEN_S);
400 glEnable(GL_TEXTURE_GEN_T);
401 glEnable(GL_TEXTURE_2D);
406 init_toasters (ModeInfo *mi)
408 toaster_configuration *bp;
409 int wire = MI_IS_WIREFRAME(mi);
413 bps = (toaster_configuration *)
414 calloc (MI_NUM_SCREENS(mi), sizeof (toaster_configuration));
416 fprintf(stderr, "%s: out of memory\n", progname);
420 bp = &bps[MI_SCREEN(mi)];
423 bp = &bps[MI_SCREEN(mi)];
425 bp->glx_context = init_GL(mi);
427 reshape_toasters (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
429 glShadeModel(GL_SMOOTH);
431 glEnable(GL_DEPTH_TEST);
432 glEnable(GL_NORMALIZE);
433 glEnable(GL_CULL_FACE);
437 GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
438 /* GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};*/
439 GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
440 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
441 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
443 glEnable(GL_LIGHTING);
445 glEnable(GL_DEPTH_TEST);
446 glEnable(GL_CULL_FACE);
448 glLightfv(GL_LIGHT0, GL_POSITION, pos);
449 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
450 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
451 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
454 if (!wire && do_texture)
457 bp->user_trackball = gltrackball_init ();
458 auto_track_init (mi);
460 bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint));
461 for (i = 0; i < countof(all_objs); i++)
462 bp->dlists[i] = glGenLists (1);
464 for (i = 0; i < countof(all_objs); i++)
466 struct gllist *gll = *all_objs[i];
468 gll->primitive = GL_LINE_LOOP;
470 glNewList (bp->dlists[i], GL_COMPILE);
472 glMatrixMode(GL_MODELVIEW);
474 glMatrixMode(GL_TEXTURE);
476 glMatrixMode(GL_MODELVIEW);
478 glRotatef (-90, 1, 0, 0);
479 glRotatef (180, 0, 0, 1);
482 glBindTexture (GL_TEXTURE_2D, 0);
484 if (i == BASE_TOASTER)
486 GLfloat color[4] = {1.00, 1.00, 1.00, 1.00};
487 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
488 GLfloat shiny = 20.0;
489 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
490 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
491 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
493 glBindTexture (GL_TEXTURE_2D, bp->chrome_texture);
494 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
495 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
497 else if (i == TOAST || i == TOAST_BITTEN)
499 GLfloat color[4] = {0.80, 0.80, 0.00, 1.0};
500 GLfloat spec[4] = {0.00, 0.00, 0.00, 1.0};
502 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
503 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
504 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
506 glBindTexture (GL_TEXTURE_2D, bp->toast_texture);
507 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
508 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
510 glMatrixMode(GL_TEXTURE);
511 glTranslatef(0.5, 0.5, 0);
512 glMatrixMode(GL_MODELVIEW);
514 else if (i == SLOTS || i == HANDLE_SLOT)
516 GLfloat color[4] = {0.30, 0.30, 0.40, 1.0};
517 GLfloat spec[4] = {0.40, 0.40, 0.70, 1.0};
518 GLfloat shiny = 128.0;
519 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
520 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
521 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
523 else if (i == HANDLE)
525 GLfloat color[4] = {0.80, 0.10, 0.10, 1.0};
526 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
527 GLfloat shiny = 20.0;
528 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
529 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
530 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
534 GLfloat color[4] = {0.80, 0.10, 0.10, 1.0};
535 GLfloat spec[4] = {0.00, 0.00, 0.00, 1.0};
537 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
538 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
539 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
541 else if (i == JET || i == JET_WING)
543 GLfloat color[4] = {0.70, 0.70, 0.70, 1.0};
544 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
545 GLfloat shiny = 20.0;
546 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
547 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
548 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
552 GLfloat color[4] = {0.50, 0.50, 0.50, 1.0};
553 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
554 GLfloat shiny = 20.0;
555 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
556 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
557 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
561 GLfloat color[4] = {1.00, 1.00, 1.00, 1.00};
562 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
563 GLfloat shiny = 128.0;
564 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
565 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
566 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
571 glMatrixMode(GL_TEXTURE);
573 glMatrixMode(GL_MODELVIEW);
579 bp->nfloaters = ntoasters + nslices;
580 bp->floaters = (floater *) calloc (bp->nfloaters, sizeof (floater));
582 for (i = 0; i < bp->nfloaters; i++)
584 floater *f = &bp->floaters[i];
585 /* arrange the list so that half the toasters are in front of bread,
586 and half are behind. */
587 f->toaster_p = ((i < ntoasters / 2) ||
588 (i >= (nslices + (ntoasters / 2))));
589 reset_floater (mi, f);
591 /* Position the first generation randomly, but make sure they aren't
592 on screen yet (until we rotate the view into position.)
595 GLfloat min = -GRID_DEPTH/2;
596 GLfloat max = GRID_DEPTH/3.5;
597 f->z = frand (max - min) + min;
604 draw_origin (ModeInfo *mi)
607 /* toaster_configuration *bp = &bps[MI_SCREEN(mi)];*/
609 if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING);
610 if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D);
615 glVertex3f(-1, 0, 0); glVertex3f(1, 0, 0);
616 glVertex3f(0, -1, 0); glVertex3f(0, 1, 0);
617 glVertex3f(0, 0, -1); glVertex3f(0, 0, 1);
621 if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING);
622 if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D);
628 draw_grid (ModeInfo *mi)
631 /* toaster_configuration *bp = &bps[MI_SCREEN(mi)];*/
633 if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING);
634 if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D);
636 glBegin(GL_LINE_LOOP);
637 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, 0);
638 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, 0);
639 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, 0);
640 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, 0);
642 glBegin(GL_LINE_LOOP);
643 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
644 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, GRID_DEPTH/2);
645 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, GRID_DEPTH/2);
646 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
648 glBegin(GL_LINE_LOOP);
649 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
650 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, GRID_DEPTH/2);
651 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, GRID_DEPTH/2);
652 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
655 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
656 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
657 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, GRID_DEPTH/2);
658 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, GRID_DEPTH/2);
659 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
660 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
661 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, GRID_DEPTH/2);
662 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, GRID_DEPTH/2);
666 if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING);
667 if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D);
673 draw_floater (ModeInfo *mi, floater *f)
675 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
681 glTranslatef (f->x, f->y, f->z);
685 glRotatef (180, 0, 1, 0);
686 glCallList (bp->dlists[BASE_TOASTER]);
687 mi->polygon_count += (*all_objs[BASE_TOASTER])->points / 3;
691 glTranslatef(0, 1.01, 0);
692 n = 0.91; glScalef(n,n,n);
693 glCallList (bp->dlists[SLOTS]);
694 mi->polygon_count += (*all_objs[SLOTS])->points / 3;
698 glRotatef (180, 0, 1, 0);
699 glTranslatef(0, -0.4, -2.38);
700 n = 0.33; glScalef(n,n,n);
701 glCallList (bp->dlists[HANDLE_SLOT]);
702 mi->polygon_count += (*all_objs[HANDLE_SLOT])->points / 3;
706 glTranslatef(0, -1.1, 3);
707 n = 0.3; glScalef (n,n,n);
708 glTranslatef(0, f->handle_pos * 4.8, 0);
709 glCallList (bp->dlists[HANDLE]);
710 mi->polygon_count += (*all_objs[HANDLE])->points / 3;
714 glRotatef (180, 0, 1, 0);
715 glTranslatef(0, -1.1, -3); /* where the handle is */
716 glTranslatef (1, -0.4, 0); /* down and to the left */
717 n = 0.08; glScalef (n,n,n);
718 glRotatef (f->knob_pos, 0, 0, 1);
719 glCallList (bp->dlists[KNOB]);
720 mi->polygon_count += (*all_objs[KNOB])->points / 3;
724 glRotatef (180, 0, 1, 0);
725 glTranslatef (0, -2.3, 0);
726 glCallList (bp->dlists[BASE]);
727 mi->polygon_count += (*all_objs[BASE])->points / 3;
731 glTranslatef(-4.8, 0, 0);
732 glCallList (bp->dlists[JET_WING]);
733 mi->polygon_count += (*all_objs[JET_WING])->points / 3;
734 glScalef (0.5, 0.5, 0.5);
735 glTranslatef (-2, -1, 0);
736 glCallList (bp->dlists[JET]);
737 mi->polygon_count += (*all_objs[JET])->points / 3;
741 glTranslatef(4.8, 0, 0);
744 glCallList (bp->dlists[JET_WING]);
745 mi->polygon_count += (*all_objs[JET_WING])->points / 3;
746 glScalef (0.5, 0.5, 0.5);
747 glTranslatef (-2, -1, 0);
748 glCallList (bp->dlists[JET]);
749 mi->polygon_count += (*all_objs[JET])->points / 3;
756 glTranslatef(0, 1.01, 0);
757 n = 0.91; glScalef(n,n,n);
758 glRotatef (90, 0, 0, 1);
759 glRotatef (90, 0, 1, 0);
760 glTranslatef(0, 0, -0.95);
761 glTranslatef(0, 0.72, 0);
764 glCallList (bp->dlists[TOAST]);
765 mi->polygon_count += (*all_objs[TOAST])->points / 3;
767 glTranslatef(0, -1.46, 0);
770 glCallList (bp->dlists[TOAST]);
771 mi->polygon_count += (*all_objs[TOAST])->points / 3;
778 glScalef (0.7, 0.7, 0.7);
779 if (f->toast_type == 0)
781 glCallList (bp->dlists[TOAST]);
782 mi->polygon_count += (*all_objs[TOAST])->points / 3;
786 glCallList (bp->dlists[TOAST_BITTEN]);
787 mi->polygon_count += (*all_objs[TOAST_BITTEN])->points / 3;
797 draw_toasters (ModeInfo *mi)
799 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
800 Display *dpy = MI_DISPLAY(mi);
801 Window window = MI_WINDOW(mi);
804 if (!bp->glx_context)
807 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
810 glRotatef(bp->view_x, 1, 0, 0);
811 glRotatef(bp->view_y, 0, 1, 0);
812 gltrackball_rotate (bp->user_trackball);
824 F.dx = F.dy = F.dz = 0;
827 if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING);
828 if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D);
830 glVertex3f(-10, 0, 0); glVertex3f(10, 0, 0);
831 glVertex3f(0, -10, 0); glVertex3f(0, 10, 0);
832 glVertex3f(0, 0, -10); glVertex3f(0, 0, 10);
834 if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING);
835 if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D);
837 draw_floater (mi, &F);
839 if (mi->fps_p) do_fps (mi);
841 glXSwapBuffers(dpy, window);
846 glScalef (0.5, 0.5, 0.5);
848 glTranslatef (0, 0, -GRID_DEPTH/2.5);
851 mi->polygon_count = 0;
852 for (i = 0; i < bp->nfloaters; i++)
854 floater *f = &bp->floaters[i];
855 draw_floater (mi, f);
856 tick_floater (mi, f);
862 if (mi->fps_p) do_fps (mi);
865 glXSwapBuffers(dpy, window);