示例#1
0
ENTRYPOINT void
draw_sonar (ModeInfo *mi)
{
  sonar_configuration *sp = &sps[MI_SCREEN(mi)];
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);

  if (!sp->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(sp->glx_context));

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix ();
  { GLfloat s = 7; glScalef (s,s,s); }

  gltrackball_rotate (sp->trackball);

  if (wobble_p)
    {
      double x, y, z;
      double max = 40;
      get_position (sp->rot, &x, &y, &z, !sp->button_down_p);
      glRotatef (max/2 - x*max, 1, 0, 0);
      glRotatef (max/2 - z*max, 0, 1, 0);
    }

  mi->polygon_count = 0;

  glPushMatrix();					/* table */
  glCallList (sp->table_list);
  mi->polygon_count += sp->table_polys;
  glPopMatrix();

  glPushMatrix();					/* text */
  glTranslatef (0, 0, -0.01);
  mi->polygon_count += draw_bogies (mi);
  glPopMatrix();

  glCallList (sp->screen_list);				/* glass */
  mi->polygon_count += sp->screen_polys;

  glTranslatef (0, 0, 0.004);				/* sweep */
  glPushMatrix();
  glRotatef ((sp->sweep_th * 180 / M_PI), 0, 0, 1);
  if (sp->sweep_th >= 0)
    glCallList (sp->sweep_list);
  mi->polygon_count += sp->sweep_polys;
  glPopMatrix();

  glTranslatef (0, 0, 0.004);				/* grid */
  glCallList (sp->grid_list);
  mi->polygon_count += sp->screen_polys;

  if (! sp->ssd || sp->error)
    draw_startup_blurb(mi);

  glPopMatrix ();

  if (mi->fps_p) do_fps (mi);
  glFinish();

  glXSwapBuffers(dpy, window);

  if (! sp->ssd)
    /* Just starting up.  "Resolving hosts" text printed.  Go stall. */
    init_sensor (mi);
  else
    sweep (sp);
}
示例#2
0
ENTRYPOINT void
draw_toasters (ModeInfo *mi)
{
  toaster_configuration *bp = &bps[MI_SCREEN(mi)];
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);
  int i;

  if (!bp->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix ();
  glRotatef(current_device_rotation(), 0, 0, 1);
  glRotatef(bp->view_x, 1, 0, 0);
  glRotatef(bp->view_y, 0, 1, 0);

  /* Rotate the scene around a point that's a little deeper in. */
  glTranslatef (0, 0, -50);
  gltrackball_rotate (bp->user_trackball);
  glTranslatef (0, 0,  50);

#if 0
  {
    floater F;
    F.toaster_p = 0;
    F.toast_type = 1;
    F.handle_pos = 0;
    F.knob_pos = -90;
    F.loaded = 3;
    F.x = F.y = F.z = 0;
    F.dx = F.dy = F.dz = 0;

    glScalef(2,2,2);
    if (!MI_IS_WIREFRAME(mi)) glDisable(GL_LIGHTING);
    if (!MI_IS_WIREFRAME(mi) && do_texture) glDisable(GL_TEXTURE_2D);
    glBegin(GL_LINES);
    glVertex3f(-10, 0, 0); glVertex3f(10, 0, 0);
    glVertex3f(0, -10, 0); glVertex3f(0, 10, 0);
    glVertex3f(0, 0, -10); glVertex3f(0, 0, 10);
    glEnd();
    if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING);
    if (!MI_IS_WIREFRAME(mi) && do_texture) glEnable(GL_TEXTURE_2D);

    draw_floater (mi, &F);
    glPopMatrix ();
    if (mi->fps_p) do_fps (mi);
    glFinish();
    glXSwapBuffers(dpy, window);
    return;
  }
#endif

  glScalef (0.5, 0.5, 0.5);
  draw_origin (mi);
  glTranslatef (0, 0, -GRID_DEPTH/2.5);
  draw_grid (mi);

  mi->polygon_count = 0;
  for (i = 0; i < bp->nfloaters; i++)
    {
      floater *f = &bp->floaters[i];
      draw_floater (mi, f);
      tick_floater (mi, f);
    }
  auto_track (mi);

  glPopMatrix ();

  if (mi->fps_p) do_fps (mi);
  glFinish();

  glXSwapBuffers(dpy, window);
}
示例#3
0
static void
draw(ModeInfo *mi)
{
  Bool wireframe_p = MI_IS_WIREFRAME(mi);
  gasketstruct *gp = &gasket[MI_SCREEN(mi)];
  
  static const GLfloat pos[]    = {-4.0, 3.0, 10.0, 1.0};
  static const GLfloat white[]  = {1.0, 1.0, 1.0, 1.0};

  GLfloat color0[] = {0.0, 0.0, 0.0, 1.0};
  GLfloat color1[] = {0.0, 0.0, 0.0, 1.0};
  GLfloat color2[] = {0.0, 0.0, 0.0, 1.0};
  GLfloat color3[] = {0.0, 0.0, 0.0, 1.0};

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  if (!wireframe_p)
    {
      glColor4fv (white);

      glLightfv(GL_LIGHT0, GL_POSITION,  pos);

      color0[0] = gp->colors[gp->ccolor0].red   / 65536.0;
      color0[1] = gp->colors[gp->ccolor0].green / 65536.0;
      color0[2] = gp->colors[gp->ccolor0].blue  / 65536.0;

      color1[0] = gp->colors[gp->ccolor1].red   / 65536.0;
      color1[1] = gp->colors[gp->ccolor1].green / 65536.0;
      color1[2] = gp->colors[gp->ccolor1].blue  / 65536.0;

      color2[0] = gp->colors[gp->ccolor2].red   / 65536.0;
      color2[1] = gp->colors[gp->ccolor2].green / 65536.0;
      color2[2] = gp->colors[gp->ccolor2].blue  / 65536.0;

      color3[0] = gp->colors[gp->ccolor3].red   / 65536.0;
      color3[1] = gp->colors[gp->ccolor3].green / 65536.0;
      color3[2] = gp->colors[gp->ccolor3].blue  / 65536.0;

      gp->ccolor0++;
      gp->ccolor1++;
      gp->ccolor2++;
      gp->ccolor3++;
      if (gp->ccolor0 >= gp->ncolors) gp->ccolor0 = 0;
      if (gp->ccolor1 >= gp->ncolors) gp->ccolor1 = 0;
      if (gp->ccolor2 >= gp->ncolors) gp->ccolor2 = 0;
      if (gp->ccolor3 >= gp->ncolors) gp->ccolor3 = 0;

      glShadeModel(GL_SMOOTH);

      glEnable(GL_LIGHTING);
      glEnable(GL_LIGHT0);
    }

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glEnable(GL_CULL_FACE);

  glPushMatrix();

  {
    double x, y, z;
    get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
    glTranslatef((x - 0.5) * 10,
                 (y - 0.5) * 10,
                 (z - 0.5) * 20);

    gltrackball_rotate (gp->trackball);

    get_rotation (gp->rot, &x, &y, &z, !gp->button_down_p);
    glRotatef (x * 360, 1.0, 0.0, 0.0);
    glRotatef (y * 360, 0.0, 1.0, 0.0);
    glRotatef (z * 360, 0.0, 0.0, 1.0);
  }

  glScalef( 8.0, 8.0, 8.0 );

  glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color0);
  glCallList(gp->gasket0);
  glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);
  glCallList(gp->gasket1);
  glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);
  glCallList(gp->gasket2);
  glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color3);
  glCallList(gp->gasket3);

  glPopMatrix();


  if (gp->tick++ >= speed)
    {
      gp->tick = 0;
      if (gp->current_depth >= max_depth)
        gp->current_depth = -max_depth;
      gp->current_depth++;

      /* We make four different lists so that each face of the tetrahedrons
         can have a different color (all triangles facing in the same
         direction have the same color, which is different from all
         triangles facing in other directions.)
       */
      glDeleteLists (gp->gasket0, 1);
      glDeleteLists (gp->gasket1, 1);
      glDeleteLists (gp->gasket2, 1);
      glDeleteLists (gp->gasket3, 1);

      mi->polygon_count = 0;
      glNewList (gp->gasket0, GL_COMPILE); compile_gasket (mi, 0); glEndList();
      glNewList (gp->gasket1, GL_COMPILE); compile_gasket (mi, 1); glEndList();
      glNewList (gp->gasket2, GL_COMPILE); compile_gasket (mi, 2); glEndList();
      glNewList (gp->gasket3, GL_COMPILE); compile_gasket (mi, 3); glEndList();

    }
}
示例#4
0
ENTRYPOINT void
draw_tunnel (ModeInfo *mi)
{
  tunnel_configuration *tc = &tconf[MI_SCREEN(mi)];
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);


  if (!tc->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));

  glShadeModel(GL_SMOOTH);

  glEnable(GL_NORMALIZE);
  /* glEnable(GL_CULL_FACE); */

  glClear(GL_COLOR_BUFFER_BIT );

  update_animation(tc);


  glPushMatrix ();

	glRotatef(180., 0., 1., 0.);
    gltrackball_rotate (tc->trackball);
	glRotatef(180., 0., 1., 0.);



  mi->polygon_count = 0;

  update_fog(tc->effects[4].state[0],  /*color*/
	     tc->effects[4].state[1],  /*density*/
	     tc->effects[4].state[2],  /*start*/
	     tc->effects[4].state[3]); /*end*/

  /* --- begin composite image assembly --- */

  /* head mask and draw diamond tunnel */

  glEnable(GL_BLEND);
  draw_cyl(mi, tc, tc->effects[6].state[0], 5, tc->diamondlist, 2); 
  if (drawlogo)
  	draw_sign(mi, tc,tc->effects[12].state[0], tc->effects[12].state[1],  1.0 / 1.33, 9, 1); 
  glDisable(GL_BLEND);
  /* then tardis tunnel */
  make_wall_tunnel(mi, tc, tc->effects[1].state[0], tc->effects[7].state[0]);

  /* then cylinder tunnel */
  glEnable(GL_BLEND);
  draw_cyl(mi, tc, tc->effects[3].state[0], 2, tc->cyllist, 1); 

       /*void draw_sign(mi, tc,z,alpha,aspect,tex,blendmode)*/
  /* tardis */
  if (drawlogo)
  	draw_sign(mi, tc, tc->effects[2].state[0], tc->effects[2].state[1], 2.0, 1, 0);
  /* marquee */
  if (drawlogo)
  	draw_sign(mi, tc, tc->effects[5].state[0], tc->effects[5].state[1], 1.0, 3, 0);
  /*who head brite*/
  if (drawlogo)
  	draw_sign(mi, tc,1.0, tc->effects[10].state[0],  1.0 / 1.33, 6, 2);
  /*who head psychadelic REMOVED*/
  /* draw_sign(mi, tc,1.0, tc->effects[11].state[0],  1.0 / 1.33, 8, 0); */

  /* star */
  /* draw_sign(mi, tc, tc->effects[8].state[0]tc->effects[8].state[0], 1.0 , 1.0, 4, 1); */
  draw_sign(mi, tc,  tc->effects[8].state[0],  tc->effects[8].state[0],  1.0, 4, 1);
 
  /* normal head */
  if (drawlogo)
  	draw_sign(mi, tc,1.0, tc->effects[9].state[0], 1.0 /  1.33, 6, 0);

  /* --- end composite image assembly --- */


  glPopMatrix ();

  if (mi->fps_p) do_fps (mi);
  glFinish();

  check_gl_error("drawing done, calling swap buffers");
  glXSwapBuffers(dpy, window);
}
示例#5
0
ENTRYPOINT void
draw_mgears (ModeInfo *mi)
{
  mgears_configuration *bp = &bps[MI_SCREEN(mi)];
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);
  int i;

  if (!bp->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));

  glShadeModel(GL_SMOOTH);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glEnable(GL_CULL_FACE);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix ();

  glScalef(1.1, 1.1, 1.1);

  {
    double x, y, z;
    get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
    glTranslatef ((x - 0.5) * 4,
                  (y - 0.5) * 4,
                  (z - 0.5) * 7);

    /* Do it twice because we don't track the device's orientation. */
    glRotatef( current_device_rotation(), 0, 0, 1);
    gltrackball_rotate (bp->trackball);
    glRotatef(-current_device_rotation(), 0, 0, 1);

    get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);

    /* add a little rotation for -no-spin mode */
    x -= 0.14;
    y -= 0.06;

    glRotatef (x * 360, 1.0, 0.0, 0.0);
    glRotatef (y * 360, 0.0, 1.0, 0.0);
    glRotatef (z * 360, 0.0, 0.0, 1.0);
  }

  mi->polygon_count = 0;

  glScalef (1.5, 1.5, 1.5);

/*#define DEBUG*/

#ifdef DEBUG
  glScalef (.5, .5, .5);
  glTranslatef (0, -bp->gears[0].g.r * bp->ngears, 0);
#endif

  for (i = 0; i < bp->ngears; i++)
    {
      mogear *mg = &bp->gears[i];
      gear *g = &mg->g;

      glPushMatrix();
#ifndef DEBUG
      glRotatef (mg->pos_th  * 180 / M_PI, 0, 0, 1);  /* rotation on ring */
      glTranslatef (bp->ring_r, 0, 0);                /* position on ring */
      glRotatef (mg->pos_thz * 180 / M_PI, 0, 1, 0);  /* twist a bit */

      if (do_roll)
        {
          glRotatef (bp->roll_th * 180 / M_PI, 0, 1, 0);
          bp->roll_th += speed * 0.0005;
        }
#else
      glTranslatef (0, i * 2 * g->r, 0);
#endif
      glRotatef (g->th * 180 / M_PI, 0, 0, 1);

      glCallList (g->dlist);
      mi->polygon_count += g->polygons;
      glPopMatrix ();
    }

  glPopMatrix ();

#ifndef DEBUG
  /* spin gears */
  for (i = 0; i < bp->ngears; i++)
    {
      mogear *mg = &bp->gears[i];
      mg->g.th += speed * (M_PI / 100) * (i & 1 ? 1 : -1);
    }
#endif

  if (mi->fps_p) do_fps (mi);
  glFinish();

  glXSwapBuffers(dpy, window);
}
示例#6
0
ENTRYPOINT void
draw_planet (ModeInfo * mi)
{
  planetstruct *gp = &planets[MI_SCREEN(mi)];
  int wire = MI_IS_WIREFRAME(mi);
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);
  double x, y, z;

  if (!gp->glx_context)
	return;

  glDrawBuffer(GL_BACK);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glXMakeCurrent (dpy, window, *(gp->glx_context));

  mi->polygon_count = 0;

  if (gp->button_down_p)
    gp->draw_axis = 60;
  else if (!gp->draw_axis && !(random() % 1000))
    gp->draw_axis = 60 + (random() % 90);

  if (do_rotate && !gp->button_down_p)
    {
      gp->z -= 0.001;     /* the sun sets in the west */
      if (gp->z < 0) gp->z += 1;
    }

  glEnable(GL_LINE_SMOOTH);
  glEnable(GL_POINT_SMOOTH);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);
  glCullFace(GL_BACK); 

  glPushMatrix();

  get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
  x = (x - 0.5) * 6;
  y = (y - 0.5) * 6;
  z = (z - 0.5) * 3;
  glTranslatef(x, y, z);

  gltrackball_rotate (gp->trackball);

  if (do_roll)
    {
      get_rotation (gp->rot, &x, &y, 0, !gp->button_down_p);
      glRotatef (x * 360, 1.0, 0.0, 0.0);
      glRotatef (y * 360, 0.0, 1.0, 0.0);
    }
  else
    glRotatef (current_device_rotation(), 0, 0, 1);

  if (do_stars)
    {
      glDisable(GL_TEXTURE_2D);
      glPushMatrix();
      glScalef (60, 60, 60);
      glRotatef (90, 1, 0, 0);
      glRotatef (35, 1, 0, 0);
      glCallList (gp->starlist);
      mi->polygon_count += gp->starcount;
      glPopMatrix();
      glClear(GL_DEPTH_BUFFER_BIT);
    }

  glRotatef (90, 1, 0, 0);
  glRotatef (35, 1, 0, 0);
  glRotatef (10, 0, 1, 0);
  glRotatef (120, 0, 0, 1);

  glScalef (3, 3, 3);

# ifdef HAVE_MOBILE
  glScalef (2, 2, 2);
# endif

  if (wire)
    glColor3f (0.5, 0.5, 1);
  else
    glColor3f (1, 1, 1);

  if (do_texture)
    {
      glEnable(GL_TEXTURE_2D);
      glBindTexture (GL_TEXTURE_2D, gp->tex1);
    }

  glPushMatrix();
  glRotatef (gp->z * 360, 0, 0, 1);
  glCallList (gp->platelist);
  mi->polygon_count += resolution*resolution;
  glPopMatrix();

  /* Originally we just used GL_LIGHT0 to produce the day/night sides of
     the planet, but that always looked crappy, even with a vast number of
     polygons, because the day/night terminator didn't exactly line up with
     the polygon edges.

     So instead, draw the full "day" sphere; clear the depth buffer; draw
     a rotated/tilted half-sphere into the depth buffer only; then draw
     the "night" sphere.  That lets us divide the sphere into the two maps,
     and the dividing line can be at any angle, regardless of polygon layout.

     The half-sphere is scaled slightly larger to avoid polygon fighting,
     since those triangles won't exactly line up because of the rotation.

     The downside of this is that the day/night terminator is 100% sharp.
     It would be nice if it was a little blurry.
   */

  if (wire)
    {
      glPushMatrix();
      glRotatef (gp->tilt, 1, 0, 0);
      glColor3f(0, 0, 0);
      glLineWidth(4);
      glCallList (gp->shadowlist);
      glLineWidth(1);
      mi->polygon_count += resolution*(resolution/2);
      glPopMatrix();
    }
  else if (do_texture && gp->tex2)
    {
      glClear(GL_DEPTH_BUFFER_BIT);
      glDisable(GL_TEXTURE_2D);
      glColorMask (0, 0, 0, 0);
      glPushMatrix();
      glRotatef (gp->tilt, 1, 0, 0);
      glScalef (1.01, 1.01, 1.01);
      glCallList (gp->shadowlist);
      mi->polygon_count += resolution*(resolution/2);
      glPopMatrix();
      glColorMask (1, 1, 1, 1);
      glEnable(GL_TEXTURE_2D);

      glBindTexture (GL_TEXTURE_2D, gp->tex2);
      glPushMatrix();
      glRotatef (gp->z * 360, 0, 0, 1);
      glCallList (gp->platelist);
      mi->polygon_count += resolution*resolution;
      glPopMatrix();
    }

  if (gp->draw_axis)
    {
      glPushMatrix();
      glRotatef (gp->z * 360, 0.0, 0.0, 1.0);
      glScalef (1.02, 1.02, 1.02);
      glDisable (GL_TEXTURE_2D);
      glDisable (GL_LIGHTING);
      glDisable (GL_LINE_SMOOTH);
      glColor3f (0.1, 0.3, 0.1);
      glCallList (gp->latlonglist);
      mi->polygon_count += 24*24;
      glPopMatrix();
      if (gp->draw_axis) gp->draw_axis--;
    }
  glPopMatrix();

  if (mi->fps_p) do_fps (mi);
  glFinish();
  glXSwapBuffers(dpy, window);
}
示例#7
0
ENTRYPOINT void
draw_carousel (ModeInfo *mi)
{
  carousel_state *ss = &sss[MI_SCREEN(mi)];
  int i;

  if (!ss->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(ss->glx_context));

  if (ss->awaiting_first_images_p)
    if (!load_initial_images (mi))
      return;

  /* Only check the wall clock every 10 frames */
  {
    if (ss->now == 0 || ss->draw_tick++ > 10)
      {
        ss->now = time((time_t *) 0);
        if (ss->last_time == 0) ss->last_time = ss->now;
        ss->draw_tick = 0;
      }
  }


  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix();

  glRotatef(current_device_rotation(), 0, 0, 1);


  /* Run the startup "un-shrink" animation.
   */
  switch (ss->mode)
    {
    case IN:
      if (--ss->mode_tick <= 0)
        {
          ss->mode = NORMAL;
          ss->last_time = time((time_t *) 0);
        }
      break;
    case NORMAL:
      break;
    default:
      abort();
    }


  /* Scale as per the startup "un-shrink" animation.
   */
  if (ss->mode != NORMAL)
    {
      GLfloat s = (ss->mode == OUT
                   ? ss->mode_tick / (fade_ticks / speed)
                   : (((fade_ticks / speed) - ss->mode_tick + 1) /
                      (fade_ticks / speed)));
      glScalef (s, s, s);
    }

  /* Rotate and tilt as per the user, and the motion modeller.
   */
  {
    double x, y, z;
    gltrackball_rotate (ss->trackball);

    /* Tilt the tube up or down by up to 30 degrees */
    get_position (ss->rot, &x, &y, &z, !ss->button_down_p);
    if (tilt_x_p)
      glRotatef (15 - (x * 30), 1, 0, 0);
    if (tilt_y_p)
      glRotatef (7  - (y * 14), 0, 0, 1);

    /* Only use the Y component of the rotator. */
    get_rotation (ss->rot, &x, &y, &z, !ss->button_down_p);
    glRotatef (y * 360, 0, 1, 0);
  }

  /* First draw each image, then draw the titles.  GL insists that you
     draw back-to-front in order to make alpha blending work properly,
     so we need to draw all of the 100% opaque images before drawing
     any of the not-100%-opaque titles.
   */
  for (i = 0; i < ss->nframes; i++)
    draw_frame (mi, ss->frames[i], ss->now, True);
  if (titles_p)
    for (i = 0; i < ss->nframes; i++)
      draw_frame (mi, ss->frames[i], ss->now, False);

  glPopMatrix();

  if (mi->fps_p) do_fps (mi);
  glFinish();
  glXSwapBuffers (MI_DISPLAY (mi), MI_WINDOW(mi));
}
示例#8
0
static int display(ModeInfo *mi, Queenscreen *qs) 
{
  int max = 1024;
  int polys = 0;
  glClear(clearbits);
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  glRotatef(current_device_rotation(), 0, 0, 1);

  /* setup light attenuation */
  /* #### apparently this does nothing */
  glEnable(GL_COLOR_MATERIAL);
  glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.8/(0.01+findAlpha(qs)));
  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.06);

  /** setup perspective */
  glTranslatef(0.0, 0.0, -1.5*qs->BOARDSIZE);
  glRotatef(30.0, 1.0, 0.0, 0.0);
  gltrackball_rotate (qs->trackball);
  glRotatef(qs->theta*100, 0.0, 1.0, 0.0);
  glTranslatef(-0.5*qs->BOARDSIZE, 0.0, -0.5*qs->BOARDSIZE);

  /* find light positions */
  qs->position[0] = qs->BOARDSIZE/2.0 + qs->BOARDSIZE/1.4*-sin(qs->theta*100*M_PI/180.0);
  qs->position[2] = qs->BOARDSIZE/2.0 + qs->BOARDSIZE/1.4*cos(qs->theta*100*M_PI/180.0);
  qs->position[1] = 6.0;

  if(!wire) {
    glEnable(GL_LIGHTING);
    glLightfv(GL_LIGHT0, GL_POSITION, qs->position);
    glEnable(GL_LIGHT0);
  }

  /* Since the lighting attenuation trick up there doesn't seem to be working,
     let's drop the old board down and drop the new board in. */
  if (qs->steps < (max/8.0)) {
    GLfloat y = qs->steps / (max/8.0);
    y = sin (M_PI/2 * y);
    glTranslatef (0, 10 - (y * 10), 0);
  } else if (qs->steps > max-(max/8.0)) {
    GLfloat y = (qs->steps - (max-(max/8.0))) / (GLfloat) (max/8.0);
    y = 1 - sin (M_PI/2 * (1-y));
    glTranslatef (0, -y * 15, 0);
  }

  /* draw reflections */
  if(!wire) {
    polys += draw_reflections(qs);
    glEnable(GL_BLEND);
  }
  polys += drawBoard(qs);
  if(!wire)
    glDisable(GL_BLEND);

  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.1);

  glTranslatef(0.5, 0.0, 0.5);
  polys += drawPieces(qs);

  /* rotate camera */
  if(!qs->button_down_p)
    qs->theta += .002;

  /* zero out board, find new solution of size MINBOARD <= i <= MAXBOARD */
  if(++qs->steps == max) {
    qs->steps = 0;
    blank(qs);
    qs->BOARDSIZE = MINBOARD + (random() % (MAXBOARD - MINBOARD + 1));
    qs->colorset = (qs->colorset+1)%COLORSETS;
    go(qs);
  }
  return polys;
}
示例#9
0
static void DrawFire(ModeInfo * mi)
{
    int j;
    firestruct *fs = &fire[MI_SCREEN(mi)];
    Bool wire = MI_IS_WIREFRAME(mi);

    mi->polygon_count = 0;

    if (do_wander && !fs->button_down_p)
    {
	GLfloat x, y, z;

#       define SINOID(SCALE,SIZE) \
        ((((1 + sin((fs->frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)

        x = SINOID(0.031, 0.85);
        y = SINOID(0.017, 0.25);
        z = SINOID(0.023, 0.85);
        fs->frame++;
        fs->obs[0] = x + DEF_OBS[0];
        fs->obs[1] = y + DEF_OBS[1];
        fs->obs[2] = z + DEF_OBS[2];
        fs->dir[1] = y;
        fs->dir[2] = z;
    }

    glEnable(GL_DEPTH_TEST);

    if (fs->fog)
	glEnable(GL_FOG);
    else
	glDisable(GL_FOG);

    glDepthMask(GL_TRUE);
    glClearColor(0.5, 0.5, 0.8, 1.0);	/* sky in the distance */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();

    calcposobs(fs);

    gltrackball_rotate (fs->trackball);

    gluLookAt(fs->obs[0], fs->obs[1], fs->obs[2],
              fs->obs[0] + fs->dir[0], 
              fs->obs[1] + fs->dir[1],
              fs->obs[2] + fs->dir[2],
              0.0, 1.0, 0.0);

    glEnable(GL_TEXTURE_2D);

    /* draw ground using the computed texture */
    if (do_texture) {
	glColor4f(1.0,1.0,1.0,1.0);	/* white to get texture in it's true color */
#ifdef HAVE_GLBINDTEXTURE
	glBindTexture(GL_TEXTURE_2D, fs->groundid);
#endif /* HAVE_GLBINDTEXTURE */
    }
    else
        glColor4f(0.54, 0.27, 0.07, 1.0);	/* untextured ground color */
    glBegin(GL_QUADS);
    glTexCoord2fv(qt[0]);
    glVertex3fv(q[0]);
    glTexCoord2fv(qt[1]);
    glVertex3fv(q[1]);
    glTexCoord2fv(qt[2]);
    glVertex3fv(q[2]);
    glTexCoord2fv(qt[3]);
    glVertex3fv(q[3]);
    mi->polygon_count++;
    glEnd();

    glAlphaFunc(GL_GEQUAL, 0.9);
    if (fs->num_trees)
    {
	/* here do_texture IS True - and color used is white */
	glEnable(GL_ALPHA_TEST);
#ifdef HAVE_GLBINDTEXTURE
	glBindTexture(GL_TEXTURE_2D,fs->treeid);
#endif /* HAVE_GLBINDTEXTURE */
	for(j=0;j<fs->num_trees;j++)
      mi->polygon_count += drawtree(fs->treepos[j].x ,fs->treepos[j].y ,fs->treepos[j].z );
    	glDisable(GL_ALPHA_TEST);
    }
    glDisable(GL_TEXTURE_2D);
    glDepthMask(GL_FALSE);

    if (fs->shadows) {
	/* draw shadows with black color */
	glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
	for (j = 0; j < fs->np; j++) {
	    glColor4f(black[0], black[1], black[2], fs->p[j].c[0][3]);
	    glVertex3f(fs->p[j].p[0][0], 0.1, fs->p[j].p[0][2]);

	    glColor4f(black[0], black[1], black[2], fs->p[j].c[1][3]);
	    glVertex3f(fs->p[j].p[1][0], 0.1, fs->p[j].p[1][2]);

	    glColor4f(black[0], black[1], black[2], fs->p[j].c[2][3]);
	    glVertex3f(fs->p[j].p[2][0], 0.1, fs->p[j].p[2][2]);
        mi->polygon_count++;
	}
	glEnd();
    }

    glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
    for (j = 0; j < fs->np; j++) {
	/* draw particles: colors are computed in setpart */
	glColor4fv(fs->p[j].c[0]);
	glVertex3fv(fs->p[j].p[0]);

	glColor4fv(fs->p[j].c[1]);
	glVertex3fv(fs->p[j].p[1]);

	glColor4fv(fs->p[j].c[2]);
	glVertex3fv(fs->p[j].p[2]);
    mi->polygon_count++;

	setpart(fs, &fs->p[j]);
    }
    glEnd();

    /* draw rain particles if no fire particles */
    if (!fs->np)
    {
        float timeused = gettimerain();
        glDisable(GL_TEXTURE_2D);
	glShadeModel(GL_SMOOTH);
	glBegin(GL_LINES);
	for (j = 0; j < NUMPART; j++) {
	    glColor4f(0.7f,0.95f,1.0f,0.0f);
	    glVertex3fv(fs->r[j].oldpos);
	    glColor4f(0.3f,0.7f,1.0f,1.0f);
	    glVertex3fv(fs->r[j].pos);
	    setpartrain(fs, &fs->r[j],timeused);
        mi->polygon_count++;
	}
	glEnd();
	glShadeModel(GL_FLAT);
    }

    glDisable(GL_TEXTURE_2D);
    glDisable(GL_ALPHA_TEST);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_FOG);

    /* manage framerate display */
    if (MI_IS_FPS(mi)) do_fps (mi);
    glPopMatrix();
}
示例#10
0
ENTRYPOINT void
draw_gears (ModeInfo *mi)
{
  gears_configuration *bp = &bps[MI_SCREEN(mi)];
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);
  int i;

  if (!bp->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));

  glShadeModel(GL_SMOOTH);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glEnable(GL_CULL_FACE);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix ();

  {
    double x, y, z;
    get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
    glTranslatef ((x - 0.5) * 4,
                  (y - 0.5) * 4,
                  (z - 0.5) * 7);

    /* Do it twice because we don't track the device's orientation. */
    glRotatef( current_device_rotation(), 0, 0, 1);
    gltrackball_rotate (bp->trackball);
    glRotatef(-current_device_rotation(), 0, 0, 1);

    get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);

    /* add a little rotation for -no-spin mode */
    x -= 0.14;
    y -= 0.06;

    glRotatef (x * 360, 1.0, 0.0, 0.0);
    glRotatef (y * 360, 0.0, 1.0, 0.0);
    glRotatef (z * 360, 0.0, 0.0, 1.0);
  }

  /* Center the scene's bounding box in the window,
     and scale it to fit. 
   */
  {
    GLfloat w = bp->bbox.x2 - bp->bbox.x1;
    GLfloat h = bp->bbox.y2 - bp->bbox.y1;
    GLfloat s = 10.0 / (w > h ? w : h);
    glScalef (s, s, s);
    glTranslatef (-(bp->bbox.x1 + w/2),
                  -(bp->bbox.y1 + h/2),
                  0);
  }

  mi->polygon_count = 0;

  for (i = 0; i < bp->ngears; i++)
    {
      gear *g = bp->gears[i];

      glPushMatrix();

      glTranslatef (g->x, g->y, g->z);
      glRotatef (g->th, 0, 0, 1);

      glCallList (g->dlist);
      mi->polygon_count += g->polygons;

      glPopMatrix ();
    }

  if (bp->planetary_p)
    {
      glCallList (bp->armature_dlist);
      mi->polygon_count += bp->armature_polygons;
    }

  glPopMatrix ();

  /* spin gears */
  if (!bp->button_down_p)
    for (i = 0; i < bp->ngears; i++)
      {
        gear *g = bp->gears[i];
        double off = g->ratio * 5 * speed;
        if (g->th > 0)
          g->th += off;
        else
          g->th -= off;
      }

  if (mi->fps_p) do_fps (mi);
  glFinish();

  glXSwapBuffers(dpy, window);
}
示例#11
0
ENTRYPOINT void
draw_cube (ModeInfo *mi)
{
  cube_configuration *cc = &ccs[MI_SCREEN(mi)];
  int wire = MI_IS_WIREFRAME(mi);
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);
  int i;

  if (!cc->glx_context)
    return;

  mi->polygon_count = 0;
  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *cc->glx_context);

  interference (mi);
  animate_cubes (mi);

  glShadeModel(GL_FLAT);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glEnable(GL_CULL_FACE);
  /* glEnable (GL_POLYGON_OFFSET_FILL); */

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix ();

  glRotatef(current_device_rotation(), 0, 0, 1);
  gltrackball_rotate (cc->trackball);
  glRotatef (-180, 1, 0, 0);

  {
    GLfloat s = 15;
    glScalef (s, s, s);
  }
  glRotatef (-90, 1, 0, 0);

  glTranslatef (-0.18, 0, -0.18);
  glRotatef (37, 1, 0, 0);
  glRotatef (20, 0, 0, 1);

  glScalef (2.1, 2.1, 2.1);

  /* Position lights after device rotation. */
  if (!wire)
    {
      static const GLfloat pos[4] = {0.0, 0.25, -1.0, 0.0};
      static const GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
      static const GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};

      glLightfv(GL_LIGHT0, GL_POSITION, pos);
      glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
      glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);

      glEnable(GL_LIGHTING);
      glEnable(GL_LIGHT0);
      glEnable(GL_DEPTH_TEST);
      glEnable(GL_CULL_FACE);
    }

  glBegin (wire ? GL_LINES : GL_QUADS);

  for (i = 0; i < cc->ncubes; i++)
    {
      cube *cube = &cc->cubes[i];
      GLfloat cth = cube->cth;
      GLfloat sth = cube->sth;
      GLfloat x =  cth*cube->x + sth*cube->y;
      GLfloat y = -sth*cube->x + cth*cube->y;
      GLfloat w = cube->w/2;
      GLfloat h = cube->h/2;
      GLfloat d = cube->d/2;
      GLfloat bottom = 5;

      GLfloat xw =  cth*w, xd = sth*d;
      GLfloat yw = -sth*w, yd = cth*d;

      GLfloat color[4];
      int c = cube->h * cc->ncolors * 0.7;
      c %= cc->ncolors;

      color[0] = cc->colors[c].red   / 65536.0;
      color[1] = cc->colors[c].green / 65536.0;
      color[2] = cc->colors[c].blue  / 65536.0;
      color[3] = 1.0;
      glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);

      /* Putting this in a display list makes no performance difference. */

      if (! wire)
        {
          glNormal3f (0, 0, -1);				/* top */
          glVertex3f (x+xw+xd, y+yw+yd, -h);
          glVertex3f (x+xw-xd, y+yw-yd, -h);
          glVertex3f (x-xw-xd, y-yw-yd, -h);
          glVertex3f (x-xw+xd, y-yw+yd, -h);
          mi->polygon_count++;

          glNormal3f (sth, cth, 0);				/* front */
          glVertex3f (x+xw+xd, y+yw+yd, bottom);
          glVertex3f (x+xw+xd, y+yw+yd, -h);
          glVertex3f (x-xw+xd, y-yw+yd, -h);
          glVertex3f (x-xw+xd, y-yw+yd, bottom);
          mi->polygon_count++;

          glNormal3f (cth, -sth, 0);				/* right */
          glVertex3f (x+xw-xd, y+yw-yd, -h);
          glVertex3f (x+xw+xd, y+yw+yd, -h);
          glVertex3f (x+xw+xd, y+yw+yd, bottom);
          glVertex3f (x+xw-xd, y+yw-yd, bottom);
          mi->polygon_count++;

# if 0    /* Omitting these makes no performance difference. */

          glNormal3f (-cth, sth, 0);			/* left */
          glVertex3f (x-xw+xd, y-yw+yd, -h);
          glVertex3f (x-xw-xd, y-yw-yd, -h);
          glVertex3f (x-xw-xd, y-yw-yd, bottom);
          glVertex3f (x-xw+xd, y-yw+yd, bottom);
          mi->polygon_count++;

          glNormal3f (-sth, -cth, 0);			/* back */
          glVertex3f (x-xw-xd, y-yw-yd, bottom);
          glVertex3f (x-xw-xd, y-yw-yd, -h);
          glVertex3f (x+xw-xd, y+yw-yd, -h);
          glVertex3f (x+xw-xd, y+yw-yd, bottom);
          mi->polygon_count++;
# endif
        }
      else
        {
          glNormal3f (0, 0, -1);				/* top */
          glVertex3f (x+xw+xd, y+yw+yd, -h);
          glVertex3f (x+xw-xd, y+yw-yd, -h);

          glVertex3f (x+xw-xd, y+yw-yd, -h);
          glVertex3f (x-xw-xd, y-yw-yd, -h);

          glVertex3f (x-xw-xd, y-yw-yd, -h);
          glVertex3f (x-xw+xd, y-yw+yd, -h);

          glVertex3f (x-xw+xd, y-yw+yd, -h);
          glVertex3f (x+xw+xd, y+yw+yd, -h);
          mi->polygon_count++;
        }
    }
  glEnd();

  glPolygonOffset (0, 0);

# if 0
  glDisable(GL_DEPTH_TEST);	/* Outline the playfield */
  glColor3f(1,1,1);
  glBegin(GL_LINE_LOOP);
  glVertex3f (-0.5, -0.5, 0);
  glVertex3f (-0.5,  0.5, 0);
  glVertex3f ( 0.5,  0.5, 0);
  glVertex3f ( 0.5, -0.5, 0);
  glEnd();
# endif

  glPopMatrix();

  if (mi->fps_p) do_fps (mi);
  glFinish();

  glXSwapBuffers(dpy, window);
}
示例#12
0
ENTRYPOINT void
draw_logo (ModeInfo *mi)
{
  logo_configuration *dc = &dcs[MI_SCREEN(mi)];
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);
  int wire = MI_IS_WIREFRAME(mi);
  GLfloat gcolor[4];
  GLfloat specular[]  = {0.8, 0.8, 0.8, 1.0};
  GLfloat shininess   = 50.0;

  if (!dc->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(dc->glx_context));

  if (dc->wire_overlay == 0 &&
      (random() % (int) (PROBABILITY_SCALE / 0.2)) == 0)
    dc->wire_overlay = ((random() % 200) +
                        (random() % 200) +
                        (random() % 200));
      
  tick_spinner (mi, &dc->gasket_spinnerx);
  tick_spinner (mi, &dc->gasket_spinnery);
  tick_spinner (mi, &dc->gasket_spinnerz);
  tick_spinner (mi, &dc->helix_spinnerz);
  tick_spinner (mi, &dc->scene_spinnerx);
  tick_spinner (mi, &dc->scene_spinnery);
  link_spinners (mi, &dc->scene_spinnerx, &dc->scene_spinnery);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix ();
  {
    glScalef(3.3, 3.3, 3.3);

    gltrackball_rotate (dc->trackball);

    glRotatef(90, 1, 0, 0);
    glRotatef(90, 0, 0, 1);

    glColor3f(dc->color[0], dc->color[1], dc->color[2]);

    glRotatef (360 * sin (M_PI/2 * dc->scene_spinnerx.position), 0, 1, 0);
    glRotatef (360 * sin (M_PI/2 * dc->scene_spinnery.position), 0, 0, 1);

    glPushMatrix();
    {
      glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerx.position), 0, 1, 0);
      glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnery.position), 0, 0, 1);
      glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerz.position), 1, 0, 0);

      memcpy (gcolor, dc->color, sizeof (dc->color));
      if (dc->wire_overlay != 0)
        {
          gcolor[0]   = gcolor[1]   = gcolor[2]   = 0;
          specular[0] = specular[1] = specular[2] = 0;
          shininess = 0;
        }
      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gcolor);
      glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,  specular);
      glMaterialf  (GL_FRONT_AND_BACK, GL_SHININESS, shininess);

      if (wire)
        glCallList (dc->gasket_list_wire);
      else if (dc->wire_overlay != 0)
        {
          glCallList (dc->gasket_list);
          glDisable (GL_LIGHTING);
          glCallList (dc->gasket_list_wire);
          if (!wire) glEnable (GL_LIGHTING);
        }
      else
        glCallList (dc->gasket_list);
    }
    glPopMatrix();

    glRotatef (360 * sin (M_PI/2 * dc->helix_spinnerz.position), 0, 0, 1);

    if (wire)
      glCallList (dc->helix_list_wire);
    else if (dc->wire_overlay != 0)
      {
        glCallList (dc->helix_list_facetted);
        glDisable (GL_LIGHTING);
        glCallList (dc->helix_list_wire);
        if (!wire) glEnable (GL_LIGHTING);
      }
    else
      glCallList (dc->helix_list);
  }
  glPopMatrix();

  if (dc->wire_overlay > 0)
    dc->wire_overlay--;

  if (mi->fps_p) do_fps (mi);
  glFinish();

  glXSwapBuffers(dpy, window);
}
示例#13
0
ENTRYPOINT void
draw_stairs (ModeInfo * mi)
{
	stairsstruct *sp = &stairs[MI_SCREEN(mi)];
    GLfloat rot = current_device_rotation();

	Display    *display = MI_DISPLAY(mi);
	Window      window = MI_WINDOW(mi);

	if (!sp->glx_context)
		return;

	glXMakeCurrent(display, window, *(sp->glx_context));

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glPushMatrix();

    glRotatef(rot, 0, 0, 1);

	glTranslatef(0.0, 0.0, -10.0);

	if (!MI_IS_ICONIC(mi)) {
		glScalef(Scale4Window * sp->WindH / sp->WindW, Scale4Window, Scale4Window);
	} else {
		glScalef(Scale4Iconic * sp->WindH / sp->WindW, Scale4Iconic, Scale4Iconic);
	}

# ifdef HAVE_MOBILE	/* Keep it the same relative size when rotated. */
  {
    GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
    if (rot != 0 && rot != 180 && rot != -180)
      glScalef (1/h, 1/h, 1/h);
  }
# endif

    gltrackball_rotate (sp->trackball);

    glTranslatef(0, 0.5, 0);
	glRotatef(44.5, 1, 0, 0);
    glRotatef(50, 0, 1, 0);

    if (!sp->rotating) {
      if ((LRAND() % 500) == 0)
        sp->rotating = (LRAND() & 1) ? 1 : -1;
    }

    if (sp->rotating) {
      glRotatef(sp->rotating * sp->step, 0, 1, 0);
      if (sp->step >= 360) {
        sp->rotating = 0;
		sp->step = 0;
      }

# ifndef DEBUG
      if (!sp->button_down_p)
        sp->step += 2;
# endif /* DEBUG */
    }

	draw_stairs_internal(mi);


# ifdef DEBUG
    {
      int i, j;
#  ifdef DEBUG_PATH
      glDisable(GL_LIGHTING);
      glDisable(GL_TEXTURE_2D);
      glBegin (GL_LINE_LOOP);
#  endif /* DEBUG_PATH */
      for (i = 0; i < NPOSITIONS; i ++)
        for (j = 0; j < SPHERE_TICKS; j++)
          mi->polygon_count += draw_sphere(i, j);
#  ifdef DEBUG_PATH
      glEnd();
      glEnable(GL_LIGHTING);
      glEnable(GL_TEXTURE_2D);
#  endif /* DEBUG_PATH */
    }
#else  /* !DEBUG */
    mi->polygon_count += draw_sphere(sp->sphere_position, sp->sphere_tick);
#endif /* !DEBUG */

    if (sp->button_down_p)
      ;
    else if (++sp->sphere_tick >= SPHERE_TICKS)
      {
        sp->sphere_tick = 0;
        if (++sp->sphere_position >= NPOSITIONS)
          sp->sphere_position = 0;
      }

	glPopMatrix();

    if (mi->fps_p) do_fps (mi);
	glFlush();

	glXSwapBuffers(display, window);
}
示例#14
0
ENTRYPOINT void
draw_unicrud (ModeInfo *mi)
{
  unicrud_configuration *bp = &bps[MI_SCREEN(mi)];
  Display *dpy = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);

  if (!bp->glx_context)
    return;

  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));

  glShadeModel (GL_FLAT);
  glEnable (GL_NORMALIZE);
  glDisable (GL_CULL_FACE);
  glDisable (GL_LIGHTING);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  if (! bp->button_down_p)
    switch (bp->state) {
    case IN:     bp->ratio += speed * 0.05;  break;
    case OUT:    bp->ratio += speed * 0.05;  break;
    case LINGER: bp->ratio += speed * 0.005; break;
    default:     abort();
    }

  if (bp->ratio > 1.0)
    {
      bp->ratio = 0;
      switch (bp->state) {
      case IN:
        bp->state = LINGER;
        break;
      case LINGER:
        bp->state = OUT;
        bp->spin_direction = (random() & 1) ? 1 : -1;
        break;
      case OUT:
        bp->state = IN;
        pick_unichar(mi);
        break;
      default:     abort();
      }
    }

  glPushMatrix ();

  {
    double x, y, z;
    get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
    glTranslatef((x - 0.5) * 6,
                 (y - 0.5) * 6,
                 (z - 0.5) * 6);

    gltrackball_rotate (bp->trackball);

    get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
    x = y = 0;
    glRotatef (x * 360, 1.0, 0.0, 0.0);
    glRotatef (y * 360, 0.0, 1.0, 0.0);
    glRotatef (z * 360, 0.0, 0.0, 1.0);
  }

# define SINOID(N) (sin(M_PI - (N) / 2 * M_PI))
  {
    GLfloat s;
    switch (bp->state) {
    case IN:  s = SINOID (bp->ratio);   break;
    case OUT: s = SINOID (1-bp->ratio); break;
    default:  s = 1; break;
    }
    glScalef (s, s, s);
    glRotatef (360 * s * bp->spin_direction * (bp->state == IN ? -1 : 1),
               0, 0, 1);
  }

  draw_unichar (mi);

  glPopMatrix ();

  if (mi->fps_p) do_fps (mi);
  glFinish();

  glXSwapBuffers(dpy, window);
}