Use cairo to scale picture
[cascardo/movie.git] / movie.c
diff --git a/movie.c b/movie.c
index 4184b82..88dc03f 100644 (file)
--- a/movie.c
+++ b/movie.c
@@ -19,6 +19,9 @@
 #define WIDTH 800
 #define HEIGHT 600
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <cairo.h>
 #include <SDL.h>
 #include <SDL_image.h>
 
 #define IS_CENTER(cx, cy, x, y) \
        ((x + WIDTH/2 == cx) && (y + HEIGHT/2 == cy))
 
-SDL_Rect points[] = {
-  {400, 300, 800, 600},
-  {450, 350, 800, 600}
-};
+SDL_Rect *points;
+int psize;
 
-SDL_Rect *
+void
+ReadPoints (char *filename)
+{
+  FILE *file;
+  char *buffer;
+  char *next;
+  size_t len;
+  int i;
+  file = fopen (filename, "r");
+  fscanf (file, "%d\n", &psize);
+  points = malloc (sizeof (SDL_Rect) * psize);
+  if (points == NULL)
+    abort ();
+  buffer = NULL;
+  len = 0;
+  for (i = 0; i < psize; i++)
+  {
+    getline (&buffer, &len, file);
+    points[i].x = strtol (buffer, &next, 0);
+    points[i].y = strtol (next+1, NULL, 0);
+  }
+  fclose (file);
+}
+
+SDL_Rect
 GetNextPoint (void)
 {
   static SDL_Rect rect = {0, 0, WIDTH, HEIGHT};
@@ -45,11 +70,11 @@ GetNextPoint (void)
   static int x1, y1, x2, y2;
   static int x, y;
   int next;
-  next = (cur + 1) % (sizeof (points) / sizeof (SDL_Rect));
-  if (IS_CENTER (points[next].x, points[next].y, rect.x, rect.y) || cur == -1)
+  next = (cur + 1) % psize;
+  if ((points[next].x == rect.x && points[next].y == rect.y) || cur == -1)
   {
     cur = next;
-    next = (cur + 1) % (sizeof (points) / sizeof (SDL_Rect));
+    next = (cur + 1) % psize;
     err = 0;
     swap = 0;
     x1 = points[cur].x;
@@ -68,8 +93,8 @@ GetNextPoint (void)
     x = x1;
     y = y1;
   }
-  rect.x = (swap ? y : x) - WIDTH/2;
-  rect.y = (swap ? x : y) - HEIGHT/2;
+  rect.x = (swap ? y : x);
+  rect.y = (swap ? x : y);
   (x2 < x1) ? x-- : x++;
   err += ABS (inc);
   if (err >= ABS (thre))
@@ -77,16 +102,80 @@ 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);
 }
 
+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)
+{
+  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;
+  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, 2, 2);
+  }
+  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;
+  center = GetNextPoint (), GetNextPoint (), GetNextPoint ();
+  slice = SDL_CreateRGBSurface (SDL_SWSURFACE, WIDTH/2, HEIGHT/2,
+                                32,
+                               0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
+  center.x -= (WIDTH/2) / 2;
+  center.y -= (HEIGHT/2) / 2;
+  center.w /= 2;
+  center.h /= 2;
+  SDL_BlitSurface (image, &center, slice, NULL);
+  SDL_UpdateRect (slice, 0, 0, 0, 0);
+  scale = CairoTarget (slice);
+  SDL_FreeSurface (slice);
+  return scale;
+}
+
 Uint32
 ShowNext (Uint32 interval, void *data)
 {
@@ -102,9 +191,11 @@ main (int argc, char **argv)
 {
   SDL_Surface *screen;
   SDL_Surface *image;
+  SDL_Surface *slice;
   SDL_Event event;
+  ReadPoints ("pro-gnu");
   SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER);
-  screen = SDL_SetVideoMode (800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN);
+  screen = SDL_SetVideoMode (800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
   image = IMG_Load ("/home/cascardo/fotos/debconf.jpg");
   SDL_AddTimer (0, ShowNext, NULL);
   while (SDL_WaitEvent (&event))
@@ -112,9 +203,14 @@ main (int argc, char **argv)
     if (event.type == SDL_KEYDOWN)
       break;
     else if (event.type == SDL_USEREVENT)
-      ShowPoint (screen, image, GetNextPoint ());
+    {
+      slice = GetNextImage (image);
+      ShowPoint (screen, slice);
+      SDL_FreeSurface (slice);
+    }
   }
   SDL_FreeSurface (image);
   SDL_Quit ();
+  free (points);
   return 0;
 }