Scales must be multiplied by factor, not initial scale
[cascardo/movie.git] / movie.c
diff --git a/movie.c b/movie.c
index f5ef008..b7d65a8 100644 (file)
--- a/movie.c
+++ b/movie.c
 
 #define WIDTH 800
 #define HEIGHT 600
+#define HBORDER 32
+#define VBORDER 8
+#define RX (0.5)
+#define RY (0.5)
+
+#define STOP_INTERVAL (2*1000)
+#define FPS (100)
+#define FRAME_INTERVAL (1000/(FPS))
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <cairo.h>
 #include <SDL.h>
 #include <SDL_image.h>
+#include <SDL_ttf.h>
 
 #define SWAP(x, y) do { \
        x ^= y; y ^= x; x ^= y; \
 #define IS_CENTER(cx, cy, x, y) \
        ((x + WIDTH/2 == cx) && (y + HEIGHT/2 == cy))
 
+TTF_Font *font;
+
 SDL_Rect *points;
+char **names;
+int cur = -1;
 int psize;
+int stop = 0;
 
 void
 ReadPoints (char *filename)
@@ -43,28 +60,33 @@ ReadPoints (char *filename)
   char *buffer;
   char *next;
   size_t len;
+  ssize_t r;
   int i;
   file = fopen (filename, "r");
   fscanf (file, "%d\n", &psize);
   points = malloc (sizeof (SDL_Rect) * psize);
-  if (points == NULL)
+  names = malloc (sizeof (char *) * psize);
+  if (points == NULL || names == NULL)
     abort ();
   buffer = NULL;
   len = 0;
   for (i = 0; i < psize; i++)
   {
-    getline (&buffer, &len, file);
+    r = getline (&buffer, &len, file);
+    buffer[r - 1] = '\0';
     points[i].x = strtol (buffer, &next, 0);
-    points[i].y = strtol (next+1, NULL, 0);
+    points[i].y = strtol (next+1, &next, 0);
+    strtol (next, &next, 0);
+    while (isspace (*next)) next++;
+    names[i] = strdup (next);
   }
   fclose (file);
 }
 
-SDL_Rect *
+SDL_Rect
 GetNextPoint (void)
 {
   static SDL_Rect rect = {0, 0, WIDTH, HEIGHT};
-  static int cur = -1;
   static int inc, err, thre, swap;
   static int x1, y1, x2, y2;
   static int x, y;
@@ -72,6 +94,7 @@ GetNextPoint (void)
   next = (cur + 1) % psize;
   if ((points[next].x == rect.x && points[next].y == rect.y) || cur == -1)
   {
+    stop = 1;
     cur = next;
     next = (cur + 1) % psize;
     err = 0;
@@ -101,24 +124,112 @@ GetNextPoint (void)
     err -= ABS (thre);
     y += (inc < 0) ? -1 : 1;
   }
-  return &rect;
+  return rect;
 }
 
 void
-ShowPoint (SDL_Surface *screen, SDL_Surface *image, SDL_Rect *rect)
+ShowPoint (SDL_Surface *screen, SDL_Surface *image)
 {
-  SDL_BlitSurface (image, rect, screen, NULL);
+  SDL_BlitSurface (image, NULL, screen, NULL);
   SDL_UpdateRect (screen, 0, 0, 0, 0);
 }
 
-Uint32
-ShowNext (Uint32 interval, void *data)
+cairo_surface_t *
+CairoFromSDL (SDL_Surface *surface)
+{
+  return cairo_image_surface_create_for_data (surface->pixels,
+                                             CAIRO_FORMAT_ARGB32,
+                                             surface->w, surface->h,
+                                             surface->pitch);
+}
+
+SDL_Surface *
+CairoToSDL (cairo_surface_t *surface)
 {
-  SDL_UserEvent event;
-  event.type = SDL_USEREVENT;
-  event.code = 0;
-  SDL_PushEvent ((SDL_Event *) &event);
-  return 33;
+  return SDL_CreateRGBSurfaceFrom (cairo_image_surface_get_data (surface),
+                                   cairo_image_surface_get_width (surface),
+                                  cairo_image_surface_get_height (surface),
+                                  32,
+                                  cairo_image_surface_get_stride (surface),
+                                  0x00ff0000, 0x0000ff00, 0x000000ff,
+                                  0xff000000);
+}
+
+SDL_Surface *
+CairoTarget (SDL_Surface *image)
+{
+  static unsigned char *data = NULL;
+  static cairo_surface_t *surface = NULL;
+  static cairo_t *ctx = NULL;
+  cairo_surface_t *source;
+  static double rx = 1.0, ry = 1.0;
+  if (data == NULL && surface == NULL && ctx == NULL)
+  {
+    data = malloc (WIDTH * HEIGHT * 4);
+    surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
+                                                  WIDTH, HEIGHT, WIDTH * 4);
+    ctx = cairo_create (surface);
+  }
+  cairo_scale (ctx, 1.0/rx, 1.0/ry);
+  rx = (double) WIDTH / (double) image->w;
+  ry = (double) HEIGHT / (double) image->h;
+  cairo_scale (ctx, rx, ry);
+  source = CairoFromSDL (image);
+  cairo_set_source_surface (ctx, source, 0, 0);
+  cairo_paint (ctx);
+  cairo_surface_destroy (source);
+  return CairoToSDL (surface);
+}
+
+SDL_Surface *
+GetNextImage (SDL_Surface *image)
+{
+  SDL_Surface *slice;
+  SDL_Rect center;
+  SDL_Surface *scale;
+  SDL_Surface *text;
+  SDL_Rect box;
+  SDL_Color Yellow = { 255, 255, 0, 0};
+  static double rx = RX, ry = RY, factor = 0.5;
+  if (rx < 0.25)
+  {
+    factor = 1.05;
+  }
+  if (rx > 2)
+  {
+    factor = 0.95238095238095233;
+  }
+  rx *= factor;
+  ry *= factor;
+  center = GetNextPoint ();
+  slice = SDL_CreateRGBSurface (SDL_SWSURFACE, WIDTH*rx, HEIGHT*ry,
+                                32,
+                               0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
+  center.x -= (WIDTH/2) * rx;
+  center.y -= (HEIGHT/2) * ry;
+  center.w *= rx;
+  center.h *= ry;
+  SDL_BlitSurface (image, &center, slice, NULL);
+  SDL_UpdateRect (slice, 0, 0, 0, 0);
+  scale = CairoTarget (slice);
+  SDL_FreeSurface (slice);
+  if (stop)
+  {
+    text = TTF_RenderUTF8_Solid (font, names[cur], Yellow);
+    box.w = text->w + HBORDER;
+    box.h = text->h + VBORDER;
+    box.x = (WIDTH - text->w - HBORDER) / 2;
+    box.y = HEIGHT - (text->h + 32 + VBORDER/2);
+    SDL_FillRect (scale, &box, SDL_MapRGB (scale->format, 0, 0, 0));
+    box.x += HBORDER/2;
+    box.y += VBORDER/2;
+    box.w -= HBORDER;
+    box.h -= VBORDER;
+    SDL_BlitSurface (text, NULL, scale, &box);
+    SDL_FreeSurface (text);
+  }
+  SDL_UpdateRect (scale, 0, 0, 0, 0);
+  return scale;
 }
 
 int
@@ -126,21 +237,52 @@ main (int argc, char **argv)
 {
   SDL_Surface *screen;
   SDL_Surface *image;
+  SDL_Surface *slice;
   SDL_Event event;
+  Uint32 now, last;
+  int i;
   ReadPoints ("pro-gnu");
   SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER);
-  screen = SDL_SetVideoMode (800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
+  TTF_Init ();
+  font = TTF_OpenFont ("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 48);
+  screen = SDL_SetVideoMode (WIDTH, HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
   image = IMG_Load ("/home/cascardo/fotos/debconf.jpg");
-  SDL_AddTimer (0, ShowNext, NULL);
-  while (SDL_WaitEvent (&event))
+  last = SDL_GetTicks ();
+  while (1)
   {
-    if (event.type == SDL_KEYDOWN)
-      break;
-    else if (event.type == SDL_USEREVENT)
-      ShowPoint (screen, image, GetNextPoint ());
+    if (SDL_PollEvent (&event))
+    {
+      if (event.type == SDL_KEYDOWN)
+        break;
+    }
+    now = SDL_GetTicks ();
+    /* skip */
+    while (!stop && now > last + FRAME_INTERVAL)
+    {
+      last += FRAME_INTERVAL;
+      GetNextPoint ();
+    }
+    slice = GetNextImage (image);
+    ShowPoint (screen, slice);
+    SDL_FreeSurface (slice);
+    if (stop)
+    {
+      stop = 0;
+      SDL_Delay (STOP_INTERVAL);
+      last = SDL_GetTicks ();
+    }
+    else
+    {
+      SDL_Delay (FRAME_INTERVAL - (now - last));
+    }
   }
   SDL_FreeSurface (image);
+  TTF_CloseFont (font);
+  TTF_Quit ();
   SDL_Quit ();
   free (points);
+  for (i = 0; i < psize; i++)
+    free (names[i]);
+  free (names);
   return 0;
 }