1 /* flyingtoasters, Copyright (c) 2003-2018 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 #define DEFAULTS "*delay: 30000 \n" \
30 "*showFPS: False \n" \
31 "*wireframe: False \n" \
35 # define free_toasters 0
36 # define release_toasters 0
38 #define countof(x) (sizeof((x))/sizeof((*x)))
40 #define DEF_SPEED "1.0"
41 #define DEF_NTOASTERS "20"
42 #define DEF_NSLICES "25"
43 #define DEF_TEXTURE "True"
46 #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
48 #include "xlockmore.h"
49 #include "gltrackball.h"
50 #include "ximage-loader.h"
55 # include "images/gen/chromesphere_png.h"
56 # include "images/gen/toast_png.h"
57 #endif /* HAVE_TEXTURE */
60 #ifdef USE_GL /* whole file */
64 extern const struct gllist
65 *toaster, *toaster_base, *toaster_handle, *toaster_handle2, *toaster_jet,
66 *toaster_knob, *toaster_slots, *toaster_wing, *toast, *toast2;
68 static const struct gllist * const *all_objs[] = {
69 &toaster, &toaster_base, &toaster_handle, &toaster_handle2, &toaster_jet,
70 &toaster_knob, &toaster_slots, &toaster_wing, &toast, &toast2
73 #define BASE_TOASTER 0
82 #define TOAST_BITTEN 9
85 #define GRID_DEPTH 500
88 static const struct { GLfloat x, y; } nice_views[] = {
91 { 12, 28 }, /* this is a list of viewer rotations that look nice. */
92 { 12, -28 }, /* every now and then we switch to a new one. */
93 {-10, -28 }, /* (but we only use the first two at start-up.) */
107 int toast_type; /* 0, 1 */
108 GLfloat handle_pos; /* 0.0 - 1.0 */
109 GLfloat knob_pos; /* degrees */
110 int loaded; /* 2 bits */
114 GLXContext *glx_context;
115 trackball_state *user_trackball;
118 int last_view, target_view;
119 GLfloat view_x, view_y;
120 int view_steps, view_tick;
121 Bool auto_tracking_p;
127 GLuint chrome_texture;
128 GLuint toast_texture;
134 } toaster_configuration;
136 static toaster_configuration *bps = NULL;
138 static GLfloat speed;
139 static int ntoasters;
141 static int do_texture;
143 static XrmOptionDescRec opts[] = {
144 { "-speed", ".speed", XrmoptionSepArg, 0 },
145 { "-ntoasters", ".ntoasters", XrmoptionSepArg, 0 },
146 { "-nslices", ".nslices", XrmoptionSepArg, 0 },
147 {"-texture", ".texture", XrmoptionNoArg, "True" },
148 {"+texture", ".texture", XrmoptionNoArg, "False" },
151 static argtype vars[] = {
152 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
153 {&ntoasters, "ntoasters", "Count", DEF_NTOASTERS, t_Int},
154 {&nslices, "nslices", "Count", DEF_NSLICES, t_Int},
155 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
158 ENTRYPOINT ModeSpecOpt toasters_opts = {countof(opts), opts, countof(vars), vars, NULL};
162 reset_floater (ModeInfo *mi, floater *f)
164 /* toaster_configuration *bp = &bps[MI_SCREEN(mi)]; */
166 GLfloat n = GRID_SIZE/2.0;
167 GLfloat n2 = GRID_DEPTH/2.0;
168 GLfloat delta = GRID_SIZE * speed / 200.0;
174 f->dz += BELLRAND(delta) - delta/3;
176 if (! (random() % 5)) {
177 f->dx += (BELLRAND(delta*2) - delta);
178 f->dy += (BELLRAND(delta*2) - delta);
181 if (! (random() % 40)) f->dz *= 10; /* occasional speedy one */
183 f->x = frand(n) - n/2;
184 f->y = frand(n) - n/2;
185 f->z = -n2 - frand(delta * 4);
190 f->knob_pos = frand(180) - 90;
191 f->handle_pos = ((random() & 1) ? 0.0 : 1.0);
193 if (f->handle_pos > 0.8 && (! (random() % 5)))
194 f->loaded = (random() & 3); /* let's toast! */
198 if (! (random() % 10))
199 f->toast_type = 1; /* toast_bitten */
205 tick_floater (ModeInfo *mi, floater *f)
207 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
209 GLfloat n1 = GRID_DEPTH/2.0;
210 GLfloat n2 = GRID_SIZE*4;
212 if (bp->button_down_p) return;
218 if (! (random() % 50000)) /* sudden gust of gravity */
221 if (f->x < -n2 || f->x > n2 ||
222 f->y < -n2 || f->y > n2 ||
224 reset_floater (mi, f);
229 auto_track_init (ModeInfo *mi)
231 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
232 bp->last_view = (random() % 2);
233 bp->target_view = bp->last_view + 2;
234 bp->view_x = nice_views[bp->last_view].x;
235 bp->view_y = nice_views[bp->last_view].y;
236 bp->view_steps = 100;
238 bp->auto_tracking_p = True;
243 auto_track (ModeInfo *mi)
245 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
247 if (bp->button_down_p)
250 /* if we're not moving, maybe start moving. Otherwise, do nothing. */
251 if (! bp->auto_tracking_p)
253 if (++bp->track_tick < 200/speed) return;
255 if (! (random() % 5))
256 bp->auto_tracking_p = True;
263 GLfloat ox = nice_views[bp->last_view].x;
264 GLfloat oy = nice_views[bp->last_view].y;
265 GLfloat tx = nice_views[bp->target_view].x;
266 GLfloat ty = nice_views[bp->target_view].y;
268 /* move from A to B with sinusoidal deltas, so that it doesn't jerk
270 GLfloat th = sin ((M_PI / 2) * (double) bp->view_tick / bp->view_steps);
272 bp->view_x = (ox + ((tx - ox) * th));
273 bp->view_y = (oy + ((ty - oy) * th));
276 if (bp->view_tick >= bp->view_steps)
279 bp->view_steps = (350.0 / speed);
280 bp->last_view = bp->target_view;
281 bp->target_view = (random() % (countof(nice_views) - 2)) + 2;
282 bp->auto_tracking_p = False;
288 /* Window management, etc
291 reshape_toasters (ModeInfo *mi, int width, int height)
293 GLfloat h = (GLfloat) height / (GLfloat) width;
296 if (width > height * 5) { /* tiny window: show middle */
297 height = width * 9/16;
299 h = height / (GLfloat) width;
302 glViewport (0, y, (GLint) width, (GLint) height);
304 glMatrixMode(GL_PROJECTION);
306 gluPerspective (40.0, 1/h, 1.0, 250);
308 glMatrixMode(GL_MODELVIEW);
310 gluLookAt( 0.0, 2.0, 30.0,
314 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
316 int o = (int) current_device_rotation();
317 if (o != 0 && o != 180 && o != -180)
318 glScalef (1/h, 1/h, 1/h);
322 glClear(GL_COLOR_BUFFER_BIT);
327 toasters_handle_event (ModeInfo *mi, XEvent *event)
329 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
331 if (gltrackball_event_handler (event, bp->user_trackball,
332 MI_WIDTH (mi), MI_HEIGHT (mi),
343 load_textures (ModeInfo *mi)
345 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
348 xi = image_data_to_ximage (mi->dpy, mi->xgwa.visual,
349 chromesphere_png, sizeof(chromesphere_png));
352 #ifndef HAVE_JWZGLES /* No SPHERE_MAP yet */
353 glGenTextures (1, &bp->chrome_texture);
354 glBindTexture (GL_TEXTURE_2D, bp->chrome_texture);
355 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
356 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
357 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
358 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
359 xi->width, xi->height, 0,
360 GL_RGBA, GL_UNSIGNED_BYTE, xi->data);
361 check_gl_error("texture");
366 xi = image_data_to_ximage (mi->dpy, mi->xgwa.visual,
367 toast_png, sizeof(toast_png));
369 glGenTextures (1, &bp->toast_texture);
370 glBindTexture (GL_TEXTURE_2D, bp->toast_texture);
371 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
372 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
373 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
374 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
375 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
376 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
377 xi->width, xi->height, 0,
378 GL_RGBA, GL_UNSIGNED_BYTE, xi->data);
379 check_gl_error("texture");
384 #endif /* HAVE_TEXTURE */
389 init_toasters (ModeInfo *mi)
391 toaster_configuration *bp;
392 int wire = MI_IS_WIREFRAME(mi);
397 bp = &bps[MI_SCREEN(mi)];
399 bp->glx_context = init_GL(mi);
401 reshape_toasters (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
403 glShadeModel(GL_SMOOTH);
405 glEnable(GL_DEPTH_TEST);
406 glEnable(GL_NORMALIZE);
407 glEnable(GL_CULL_FACE);
411 GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
412 /* GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};*/
413 GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
414 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
415 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
417 glEnable(GL_LIGHTING);
419 glEnable(GL_DEPTH_TEST);
420 glEnable(GL_CULL_FACE);
422 glLightfv(GL_LIGHT0, GL_POSITION, pos);
423 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
424 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
425 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
429 if (!wire && do_texture)
433 bp->user_trackball = gltrackball_init (False);
434 auto_track_init (mi);
436 bp->dlists = (GLuint *) calloc (countof(all_objs)+1, sizeof(GLuint));
437 for (i = 0; i < countof(all_objs); i++)
438 bp->dlists[i] = glGenLists (1);
440 for (i = 0; i < countof(all_objs); i++)
442 const struct gllist *gll = *all_objs[i];
444 glNewList (bp->dlists[i], GL_COMPILE);
446 glMatrixMode(GL_MODELVIEW);
448 glMatrixMode(GL_TEXTURE);
450 glMatrixMode(GL_MODELVIEW);
452 glRotatef (-90, 1, 0, 0);
453 glRotatef (180, 0, 0, 1);
456 glBindTexture (GL_TEXTURE_2D, 0);
457 glDisable (GL_TEXTURE_2D);
459 if (i == BASE_TOASTER)
461 GLfloat color[4] = {1.00, 1.00, 1.00, 1.00};
462 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
463 GLfloat shiny = 20.0;
464 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
465 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
466 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
470 #ifndef HAVE_JWZGLES /* No SPHERE_MAP yet */
471 glEnable (GL_TEXTURE_2D);
472 glEnable (GL_TEXTURE_GEN_S);
473 glEnable (GL_TEXTURE_GEN_T);
474 glBindTexture (GL_TEXTURE_2D, bp->chrome_texture);
475 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
476 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
481 else if (i == TOAST || i == TOAST_BITTEN)
483 GLfloat color[4] = {0.80, 0.80, 0.00, 1.0};
484 GLfloat spec[4] = {0.00, 0.00, 0.00, 1.0};
486 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
487 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
488 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
492 glEnable (GL_TEXTURE_2D);
493 glEnable (GL_TEXTURE_GEN_S);
494 glEnable (GL_TEXTURE_GEN_T);
495 glBindTexture (GL_TEXTURE_2D, bp->toast_texture);
496 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
497 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
501 glMatrixMode(GL_TEXTURE);
502 glTranslatef(0.5, 0.5, 0);
503 glMatrixMode(GL_MODELVIEW);
505 else if (i == SLOTS || i == HANDLE_SLOT)
507 GLfloat color[4] = {0.30, 0.30, 0.40, 1.0};
508 GLfloat spec[4] = {0.40, 0.40, 0.70, 1.0};
509 GLfloat shiny = 128.0;
510 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
511 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
512 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shiny);
514 else if (i == HANDLE)
516 GLfloat color[4] = {0.80, 0.10, 0.10, 1.0};
517 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
518 GLfloat shiny = 20.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);
525 GLfloat color[4] = {0.80, 0.10, 0.10, 1.0};
526 GLfloat spec[4] = {0.00, 0.00, 0.00, 1.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);
532 else if (i == JET || i == JET_WING)
534 GLfloat color[4] = {0.70, 0.70, 0.70, 1.0};
535 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
536 GLfloat shiny = 20.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);
543 GLfloat color[4] = {0.50, 0.50, 0.50, 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] = {1.00, 1.00, 1.00, 1.00};
553 GLfloat spec[4] = {1.00, 1.00, 1.00, 1.0};
554 GLfloat shiny = 128.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);
560 renderList (gll, wire);
562 glMatrixMode(GL_TEXTURE);
564 glMatrixMode(GL_MODELVIEW);
570 bp->nfloaters = ntoasters + nslices;
571 bp->floaters = (floater *) calloc (bp->nfloaters, sizeof (floater));
573 for (i = 0; i < bp->nfloaters; i++)
575 floater *f = &bp->floaters[i];
576 /* arrange the list so that half the toasters are in front of bread,
577 and half are behind. */
578 f->toaster_p = ((i < ntoasters / 2) ||
579 (i >= (nslices + (ntoasters / 2))));
580 reset_floater (mi, f);
582 /* Position the first generation randomly, but make sure they aren't
583 on screen yet (until we rotate the view into position.)
586 GLfloat min = -GRID_DEPTH/2;
587 GLfloat max = GRID_DEPTH/3.5;
588 f->z = frand (max - min) + min;
595 draw_origin (ModeInfo *mi)
598 /* toaster_configuration *bp = &bps[MI_SCREEN(mi)];*/
600 if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING);
601 if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D);
606 glVertex3f(-1, 0, 0); glVertex3f(1, 0, 0);
607 glVertex3f(0, -1, 0); glVertex3f(0, 1, 0);
608 glVertex3f(0, 0, -1); glVertex3f(0, 0, 1);
612 if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING);
613 if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D);
619 draw_grid (ModeInfo *mi)
622 /* toaster_configuration *bp = &bps[MI_SCREEN(mi)];*/
624 if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING);
625 if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D);
627 glBegin(GL_LINE_LOOP);
628 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, 0);
629 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, 0);
630 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, 0);
631 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, 0);
633 glBegin(GL_LINE_LOOP);
634 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
635 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, GRID_DEPTH/2);
636 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, GRID_DEPTH/2);
637 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
639 glBegin(GL_LINE_LOOP);
640 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
641 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, GRID_DEPTH/2);
642 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, GRID_DEPTH/2);
643 glVertex3f( GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
646 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, -GRID_DEPTH/2);
647 glVertex3f(-GRID_SIZE/2, GRID_SIZE/2, -GRID_DEPTH/2);
648 glVertex3f(-GRID_SIZE/2, -GRID_SIZE/2, GRID_DEPTH/2);
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);
653 glVertex3f( GRID_SIZE/2, GRID_SIZE/2, GRID_DEPTH/2);
657 if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING);
658 if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D);
664 draw_floater (ModeInfo *mi, floater *f)
666 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
672 glTranslatef (f->x, f->y, f->z);
676 glRotatef (180, 0, 1, 0);
678 glCallList (bp->dlists[BASE_TOASTER]);
679 mi->polygon_count += (*all_objs[BASE_TOASTER])->points / 3;
683 glTranslatef(0, 1.01, 0);
684 n = 0.91; glScalef(n,n,n);
685 glCallList (bp->dlists[SLOTS]);
686 mi->polygon_count += (*all_objs[SLOTS])->points / 3;
690 glRotatef (180, 0, 1, 0);
691 glTranslatef(0, -0.4, -2.38);
692 n = 0.33; glScalef(n,n,n);
693 glCallList (bp->dlists[HANDLE_SLOT]);
694 mi->polygon_count += (*all_objs[HANDLE_SLOT])->points / 3;
698 glTranslatef(0, -1.1, 3);
699 n = 0.3; glScalef (n,n,n);
700 glTranslatef(0, f->handle_pos * 4.8, 0);
701 glCallList (bp->dlists[HANDLE]);
702 mi->polygon_count += (*all_objs[HANDLE])->points / 3;
706 glRotatef (180, 0, 1, 0);
707 glTranslatef(0, -1.1, -3); /* where the handle is */
708 glTranslatef (1, -0.4, 0); /* down and to the left */
709 n = 0.08; glScalef (n,n,n);
710 glRotatef (f->knob_pos, 0, 0, 1);
711 glCallList (bp->dlists[KNOB]);
712 mi->polygon_count += (*all_objs[KNOB])->points / 3;
716 glRotatef (180, 0, 1, 0);
717 glTranslatef (0, -2.3, 0);
718 glCallList (bp->dlists[BASE]);
719 mi->polygon_count += (*all_objs[BASE])->points / 3;
723 glTranslatef(-4.8, 0, 0);
724 glCallList (bp->dlists[JET_WING]);
725 mi->polygon_count += (*all_objs[JET_WING])->points / 3;
726 glScalef (0.5, 0.5, 0.5);
727 glTranslatef (-2, -1, 0);
728 glCallList (bp->dlists[JET]);
729 mi->polygon_count += (*all_objs[JET])->points / 3;
733 glTranslatef(4.8, 0, 0);
736 glCallList (bp->dlists[JET_WING]);
737 mi->polygon_count += (*all_objs[JET_WING])->points / 3;
738 glScalef (0.5, 0.5, 0.5);
739 glTranslatef (-2, -1, 0);
740 glCallList (bp->dlists[JET]);
741 mi->polygon_count += (*all_objs[JET])->points / 3;
748 glTranslatef(0, 1.01, 0);
749 n = 0.91; glScalef(n,n,n);
750 glRotatef (90, 0, 0, 1);
751 glRotatef (90, 0, 1, 0);
752 glTranslatef(0, 0, -0.95);
753 glTranslatef(0, 0.72, 0);
756 glCallList (bp->dlists[TOAST]);
757 mi->polygon_count += (*all_objs[TOAST])->points / 3;
759 glTranslatef(0, -1.46, 0);
762 glCallList (bp->dlists[TOAST]);
763 mi->polygon_count += (*all_objs[TOAST])->points / 3;
770 glScalef (0.7, 0.7, 0.7);
771 if (f->toast_type == 0)
773 glCallList (bp->dlists[TOAST]);
774 mi->polygon_count += (*all_objs[TOAST])->points / 3;
778 glCallList (bp->dlists[TOAST_BITTEN]);
779 mi->polygon_count += (*all_objs[TOAST_BITTEN])->points / 3;
789 draw_toasters (ModeInfo *mi)
791 toaster_configuration *bp = &bps[MI_SCREEN(mi)];
792 Display *dpy = MI_DISPLAY(mi);
793 Window window = MI_WINDOW(mi);
796 if (!bp->glx_context)
799 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
801 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
804 glRotatef(current_device_rotation(), 0, 0, 1);
805 glRotatef(bp->view_x, 1, 0, 0);
806 glRotatef(bp->view_y, 0, 1, 0);
808 /* Rotate the scene around a point that's a little deeper in. */
809 glTranslatef (0, 0, -50);
810 gltrackball_rotate (bp->user_trackball);
811 glTranslatef (0, 0, 50);
822 F.dx = F.dy = F.dz = 0;
825 if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING);
826 if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D);
828 glVertex3f(-10, 0, 0); glVertex3f(10, 0, 0);
829 glVertex3f(0, -10, 0); glVertex3f(0, 10, 0);
830 glVertex3f(0, 0, -10); glVertex3f(0, 0, 10);
832 if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING);
833 if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D);
835 draw_floater (mi, &F);
837 if (mi->fps_p) do_fps (mi);
839 glXSwapBuffers(dpy, window);
844 glScalef (0.5, 0.5, 0.5);
846 glTranslatef (0, 0, -GRID_DEPTH/2.5);
849 mi->polygon_count = 0;
850 for (i = 0; i < bp->nfloaters; i++)
852 floater *f = &bp->floaters[i];
853 draw_floater (mi, f);
854 tick_floater (mi, f);
860 if (mi->fps_p) do_fps (mi);
863 glXSwapBuffers(dpy, window);
866 XSCREENSAVER_MODULE_2 ("FlyingToasters", flyingtoasters, toasters)