Change scale to four, since the new picture requires it
[cascardo/movie.git] / movie.c
1 /*
2  *  Copyright (C) 2008  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #define WIDTH 800
20 #define HEIGHT 600
21 #define HBORDER 32
22 #define VBORDER 8
23
24 #define STOP_INTERVAL (2*1000)
25 #define FPS (100)
26 #define FRAME_INTERVAL (1000/(FPS))
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <cairo.h>
33 #include <SDL.h>
34 #include <SDL_image.h>
35 #include <SDL_ttf.h>
36
37 #define SWAP(x, y) do { \
38         x ^= y; y ^= x; x ^= y; \
39         } while (0)
40
41 #define ABS(x) ((x) < 0 ? -(x) : (x))
42
43 #define IS_CENTER(cx, cy, x, y) \
44         ((x + WIDTH/2 == cx) && (y + HEIGHT/2 == cy))
45
46 TTF_Font *font;
47
48 SDL_Rect *points;
49 char **names;
50 int cur = -1;
51 int psize;
52 int stop = 0;
53
54 void
55 ReadPoints (char *filename)
56 {
57   FILE *file;
58   char *buffer;
59   char *next;
60   size_t len;
61   ssize_t r;
62   int i;
63   file = fopen (filename, "r");
64   fscanf (file, "%d\n", &psize);
65   points = malloc (sizeof (SDL_Rect) * psize);
66   names = malloc (sizeof (char *) * psize);
67   if (points == NULL || names == NULL)
68     abort ();
69   buffer = NULL;
70   len = 0;
71   for (i = 0; i < psize; i++)
72   {
73     r = getline (&buffer, &len, file);
74     buffer[r - 1] = '\0';
75     points[i].x = strtol (buffer, &next, 0);
76     points[i].y = strtol (next+1, &next, 0);
77     strtol (next, &next, 0);
78     while (isspace (*next)) next++;
79     names[i] = strdup (next);
80   }
81   fclose (file);
82 }
83
84 SDL_Rect
85 GetNextPoint (void)
86 {
87   static SDL_Rect rect = {0, 0, WIDTH, HEIGHT};
88   static int inc, err, thre, swap;
89   static int x1, y1, x2, y2;
90   static int x, y;
91   int next;
92   next = (cur + 1) % psize;
93   if ((points[next].x == rect.x && points[next].y == rect.y) || cur == -1)
94   {
95     stop = 1;
96     cur = next;
97     next = (cur + 1) % psize;
98     err = 0;
99     swap = 0;
100     x1 = points[cur].x;
101     y1 = points[cur].y;
102     x2 = points[next].x;
103     y2 = points[next].y;
104     inc = y2 - y1;
105     thre = x2 - x1;
106     if (ABS (inc) > ABS (thre))
107     {
108       SWAP (inc, thre);
109       SWAP (x1, y1);
110       SWAP (x2, y2);
111       swap = 1;
112     }
113     x = x1;
114     y = y1;
115   }
116   rect.x = (swap ? y : x);
117   rect.y = (swap ? x : y);
118   (x2 < x1) ? x-- : x++;
119   err += ABS (inc);
120   if (err >= ABS (thre))
121   {
122     err -= ABS (thre);
123     y += (inc < 0) ? -1 : 1;
124   }
125   return rect;
126 }
127
128 void
129 ShowPoint (SDL_Surface *screen, SDL_Surface *image)
130 {
131   SDL_BlitSurface (image, NULL, screen, NULL);
132   SDL_UpdateRect (screen, 0, 0, 0, 0);
133 }
134
135 cairo_surface_t *
136 CairoFromSDL (SDL_Surface *surface)
137 {
138   return cairo_image_surface_create_for_data (surface->pixels,
139                                               CAIRO_FORMAT_ARGB32,
140                                               surface->w, surface->h,
141                                               surface->pitch);
142 }
143
144 SDL_Surface *
145 CairoToSDL (cairo_surface_t *surface)
146 {
147   return SDL_CreateRGBSurfaceFrom (cairo_image_surface_get_data (surface),
148                                    cairo_image_surface_get_width (surface),
149                                    cairo_image_surface_get_height (surface),
150                                    32,
151                                    cairo_image_surface_get_stride (surface),
152                                    0x00ff0000, 0x0000ff00, 0x000000ff,
153                                    0xff000000);
154 }
155
156 SDL_Surface *
157 CairoTarget (SDL_Surface *image)
158 {
159   static unsigned char *data = NULL;
160   static cairo_surface_t *surface = NULL;
161   static cairo_t *ctx = NULL;
162   cairo_surface_t *source;
163   if (data == NULL && surface == NULL && ctx == NULL)
164   {
165     data = malloc (WIDTH * HEIGHT * 4);
166     surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
167                                                    WIDTH, HEIGHT, WIDTH * 4);
168     ctx = cairo_create (surface);
169     cairo_scale (ctx, 4, 4);
170   }
171   source = CairoFromSDL (image);
172   cairo_set_source_surface (ctx, source, 0, 0);
173   cairo_paint (ctx);
174   cairo_surface_destroy (source);
175   return CairoToSDL (surface);
176 }
177
178 SDL_Surface *
179 GetNextImage (SDL_Surface *image)
180 {
181   SDL_Surface *slice;
182   SDL_Rect center;
183   SDL_Surface *scale;
184   SDL_Surface *text;
185   SDL_Rect box;
186   SDL_Color Yellow = { 255, 255, 0, 0};
187   center = GetNextPoint ();
188   slice = SDL_CreateRGBSurface (SDL_SWSURFACE, WIDTH/4, HEIGHT/4,
189                                 32,
190                                 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
191   center.x -= (WIDTH/2) / 4;
192   center.y -= (HEIGHT/2) / 4;
193   center.w /= 4;
194   center.h /= 4;
195   SDL_BlitSurface (image, &center, slice, NULL);
196   SDL_UpdateRect (slice, 0, 0, 0, 0);
197   scale = CairoTarget (slice);
198   SDL_FreeSurface (slice);
199   if (stop)
200   {
201     text = TTF_RenderUTF8_Solid (font, names[cur], Yellow);
202     box.w = text->w + HBORDER;
203     box.h = text->h + VBORDER;
204     box.x = (WIDTH - text->w - HBORDER) / 2;
205     box.y = HEIGHT - (text->h + 32 + VBORDER/2);
206     SDL_FillRect (scale, &box, SDL_MapRGB (scale->format, 0, 0, 0));
207     box.x += HBORDER/2;
208     box.y += VBORDER/2;
209     box.w -= HBORDER;
210     box.h -= VBORDER;
211     SDL_BlitSurface (text, NULL, scale, &box);
212     SDL_FreeSurface (text);
213   }
214   SDL_UpdateRect (scale, 0, 0, 0, 0);
215   return scale;
216 }
217
218 int
219 main (int argc, char **argv)
220 {
221   SDL_Surface *screen;
222   SDL_Surface *image;
223   SDL_Surface *slice;
224   Uint32 now, last;
225   int i;
226   ReadPoints ("pro-gnu");
227   SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER);
228   TTF_Init ();
229   font = TTF_OpenFont ("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 48);
230   screen = SDL_SetVideoMode (WIDTH, HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
231   image = IMG_Load ("/home/cascardo/fotos/debconf.jpg");
232   last = SDL_GetTicks ();
233   while (1)
234   {
235     now = SDL_GetTicks ();
236     /* skip */
237     while (!stop && now > last + FRAME_INTERVAL)
238     {
239       last += FRAME_INTERVAL;
240       GetNextPoint ();
241     }
242     slice = GetNextImage (image);
243     ShowPoint (screen, slice);
244     SDL_FreeSurface (slice);
245     if (stop)
246     {
247       stop = 0;
248       SDL_Delay (STOP_INTERVAL);
249       last = SDL_GetTicks ();
250     }
251     else
252     {
253       SDL_Delay (FRAME_INTERVAL - (now - last));
254     }
255   }
256   SDL_FreeSurface (image);
257   TTF_CloseFont (font);
258   TTF_Quit ();
259   SDL_Quit ();
260   free (points);
261   for (i = 0; i < psize; i++)
262     free (names[i]);
263   free (names);
264   return 0;
265 }