+
+ if (!freed_p) abort();
+ free (sp);
+ sp = 0;
+
+ img->refcount--;
+ if (img->refcount < 0) abort();
+ if (img->refcount == 0)
+ destroy_image (mi, img);
+}
+
+
+/* Updates the sprite for the current frame of the animation based on
+ its creation time compared to the current wall clock.
+ */
+static void
+tick_sprite (ModeInfo *mi, sprite *sp)
+{
+ slideshow_state *ss = &sss[MI_SCREEN(mi)];
+ image *img = sp->img;
+ double now = ss->now;
+ double secs;
+ double ratio;
+ rect prev_rect = sp->current;
+ GLfloat prev_opacity = sp->opacity;
+
+ if (! sp->img) abort();
+ if (! img->loaded_p) abort();
+
+ secs = now - sp->start_time;
+ ratio = secs / (pan_seconds + fade_seconds);
+ if (ratio > 1) ratio = 1;
+
+ sp->current.x = sp->from.x + ratio * (sp->to.x - sp->from.x);
+ sp->current.y = sp->from.y + ratio * (sp->to.y - sp->from.y);
+ sp->current.w = sp->from.w + ratio * (sp->to.w - sp->from.w);
+ sp->current.h = sp->from.h + ratio * (sp->to.h - sp->from.h);
+
+ sp->prev_state = sp->state;
+
+ if (secs < fade_seconds)
+ {
+ sp->state = IN;
+ sp->opacity = secs / (GLfloat) fade_seconds;
+ }
+ else if (secs < pan_seconds)
+ {
+ sp->state = FULL;
+ sp->opacity = 1;
+ }
+ else if (secs < pan_seconds + fade_seconds)
+ {
+ sp->state = OUT;
+ sp->opacity = 1 - ((secs - pan_seconds) / (GLfloat) fade_seconds);
+ }
+ else
+ {
+ sp->state = DEAD;
+ sp->opacity = 0;
+ }
+
+ if (sp->state != sp->prev_state &&
+ (sp->prev_state == IN ||
+ sp->prev_state == FULL))
+ {
+ double secs = now - sp->state_time;
+
+ if (debug_p)
+ fprintf (stderr,
+ "%s: %s %3d frames %2.0f sec %5.1f fps (%.1f fps?)\n",
+ blurb(),
+ (sp->prev_state == IN ? "fade" : "pan "),
+ sp->frame_count,
+ secs,
+ sp->frame_count / secs,
+ ss->theoretical_fps);
+
+ sp->state_time = now;
+ sp->frame_count = 0;
+ }
+
+ sp->frame_count++;
+
+ if (sp->state != DEAD &&
+ (prev_rect.x != sp->current.x ||
+ prev_rect.y != sp->current.y ||
+ prev_rect.w != sp->current.w ||
+ prev_rect.h != sp->current.h ||
+ prev_opacity != sp->opacity))
+ ss->redisplay_needed_p = True;
+}
+
+
+/* Draw the given sprite at the phase of its animation dictated by
+ its creation time compared to the current wall clock.
+ */
+static void
+draw_sprite (ModeInfo *mi, sprite *sp)
+{
+ slideshow_state *ss = &sss[MI_SCREEN(mi)];
+ int wire = MI_IS_WIREFRAME(mi);
+ image *img = sp->img;
+
+ if (! sp->img) abort();
+ if (! img->loaded_p) abort();
+
+ glPushMatrix();
+ {
+ glTranslatef (sp->current.x, sp->current.y, 0);
+ glScalef (sp->current.w, sp->current.h, 1);
+
+ if (wire) /* Draw a grid inside the box */
+ {
+ GLfloat dy = 0.1;
+ GLfloat dx = dy * img->w / img->h;
+ GLfloat x, y;
+
+ if (sp->id & 1)
+ glColor4f (sp->opacity, 0, 0, 1);
+ else
+ glColor4f (0, 0, sp->opacity, 1);
+
+ glBegin(GL_LINES);
+ glVertex3f (0, 0, 0); glVertex3f (1, 1, 0);
+ glVertex3f (1, 0, 0); glVertex3f (0, 1, 0);
+
+ for (y = 0; y < 1+dy; y += dy)
+ {
+ GLfloat yy = (y > 1 ? 1 : y);
+ for (x = 0.5; x < 1+dx; x += dx)
+ {
+ GLfloat xx = (x > 1 ? 1 : x);
+ glVertex3f (0, xx, 0); glVertex3f (1, xx, 0);
+ glVertex3f (yy, 0, 0); glVertex3f (yy, 1, 0);
+ }
+ for (x = 0.5; x > -dx; x -= dx)
+ {
+ GLfloat xx = (x < 0 ? 0 : x);
+ glVertex3f (0, xx, 0); glVertex3f (1, xx, 0);
+ glVertex3f (yy, 0, 0); glVertex3f (yy, 1, 0);
+ }
+ }
+ glEnd();
+ }
+ else /* Draw the texture quad */
+ {
+ GLfloat texw = img->geom.width / (GLfloat) img->tw;
+ GLfloat texh = img->geom.height / (GLfloat) img->th;
+ GLfloat texx1 = img->geom.x / (GLfloat) img->tw;
+ GLfloat texy1 = img->geom.y / (GLfloat) img->th;
+ GLfloat texx2 = texx1 + texw;
+ GLfloat texy2 = texy1 + texh;
+
+ glBindTexture (GL_TEXTURE_2D, img->texid);
+ glColor4f (1, 1, 1, sp->opacity);
+ glNormal3f (0, 0, 1);
+ glBegin (GL_QUADS);
+ glTexCoord2f (texx1, texy2); glVertex3f (0, 0, 0);
+ glTexCoord2f (texx2, texy2); glVertex3f (1, 0, 0);
+ glTexCoord2f (texx2, texy1); glVertex3f (1, 1, 0);
+ glTexCoord2f (texx1, texy1); glVertex3f (0, 1, 0);
+ glEnd();
+
+ if (debug_p) /* Draw a border around the image */
+ {
+ if (!wire) glDisable (GL_TEXTURE_2D);
+
+ if (sp->id & 1)
+ glColor4f (sp->opacity, 0, 0, 1);
+ else
+ glColor4f (0, 0, sp->opacity, 1);
+
+ glBegin (GL_LINE_LOOP);
+ glVertex3f (0, 0, 0);
+ glVertex3f (0, 1, 0);
+ glVertex3f (1, 1, 0);
+ glVertex3f (1, 0, 0);
+ glEnd();
+
+ if (!wire) glEnable (GL_TEXTURE_2D);
+ }
+ }
+
+
+ if (do_titles &&
+ img->title && *img->title)