Scales must be multiplied by factor, not initial scale
[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 #define RX (0.5)
24 #define RY (0.5)
25
26 #define STOP_INTERVAL (2*1000)
27 #define FPS (100)
28 #define FRAME_INTERVAL (1000/(FPS))
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <cairo.h>
35 #include <SDL.h>
36 #include <SDL_image.h>
37 #include <SDL_ttf.h>
38
39 #define SWAP(x, y) do { \
40         x ^= y; y ^= x; x ^= y; \
41         } while (0)
42
43 #define ABS(x) ((x) < 0 ? -(x) : (x))
44
45 #define IS_CENTER(cx, cy, x, y) \
46         ((x + WIDTH/2 == cx) && (y + HEIGHT/2 == cy))
47
48 TTF_Font *font;
49
50 SDL_Rect *points;
51 char **names;
52 int cur = -1;
53 int psize;
54 int stop = 0;
55
56 void
57 ReadPoints (char *filename)
58 {
59   FILE *file;
60   char *buffer;
61   char *next;
62   size_t len;
63   ssize_t r;
64   int i;
65   file = fopen (filename, "r");
66   fscanf (file, "%d\n", &psize);
67   points = malloc (sizeof (SDL_Rect) * psize);
68   names = malloc (sizeof (char *) * psize);
69   if (points == NULL || names == NULL)
70     abort ();
71   buffer = NULL;
72   len = 0;
73   for (i = 0; i < psize; i++)
74   {
75     r = getline (&buffer, &len, file);
76     buffer[r - 1] = '\0';
77     points[i].x = strtol (buffer, &next, 0);
78     points[i].y = strtol (next+1, &next, 0);
79     strtol (next, &next, 0);
80     while (isspace (*next)) next++;
81     names[i] = strdup (next);
82   }
83   fclose (file);
84 }
85
86 SDL_Rect
87 GetNextPoint (void)
88 {
89   static SDL_Rect rect = {0, 0, WIDTH, HEIGHT};
90   static int inc, err, thre, swap;
91   static int x1, y1, x2, y2;
92   static int x, y;
93   int next;
94   next = (cur + 1) % psize;
95   if ((points[next].x == rect.x && points[next].y == rect.y) || cur == -1)
96   {
97     stop = 1;
98     cur = next;
99     next = (cur + 1) % psize;
100     err = 0;
101     swap = 0;
102     x1 = points[cur].x;
103     y1 = points[cur].y;
104     x2 = points[next].x;
105     y2 = points[next].y;
106     inc = y2 - y1;
107     thre = x2 - x1;
108     if (ABS (inc) > ABS (thre))
109     {
110       SWAP (inc, thre);
111       SWAP (x1, y1);
112       SWAP (x2, y2);
113       swap = 1;
114     }
115     x = x1;
116     y = y1;
117   }
118   rect.x = (swap ? y : x);
119   rect.y = (swap ? x : y);
120   (x2 < x1) ? x-- : x++;
121   err += ABS (inc);
122   if (err >= ABS (thre))
123   {
124     err -= ABS (thre);
125     y += (inc < 0) ? -1 : 1;
126   }
127   return rect;
128 }
129
130 void
131 ShowPoint (SDL_Surface *screen, SDL_Surface *image)
132 {
133   SDL_BlitSurface (image, NULL, screen, NULL);
134   SDL_UpdateRect (screen, 0, 0, 0, 0);
135 }
136
137 cairo_surface_t *
138 CairoFromSDL (SDL_Surface *surface)
139 {
140   return cairo_image_surface_create_for_data (surface->pixels,
141                                               CAIRO_FORMAT_ARGB32,
142                                               surface->w, surface->h,
143                                               surface->pitch);
144 }
145
146 SDL_Surface *
147 CairoToSDL (cairo_surface_t *surface)
148 {
149   return SDL_CreateRGBSurfaceFrom (cairo_image_surface_get_data (surface),
150                                    cairo_image_surface_get_width (surface),
151                                    cairo_image_surface_get_height (surface),
152                                    32,
153                                    cairo_image_surface_get_stride (surface),
154                                    0x00ff0000, 0x0000ff00, 0x000000ff,
155                                    0xff000000);
156 }
157
158 SDL_Surface *
159 CairoTarget (SDL_Surface *image)
160 {
161   static unsigned char *data = NULL;
162   static cairo_surface_t *surface = NULL;
163   static cairo_t *ctx = NULL;
164   cairo_surface_t *source;
165   static double rx = 1.0, ry = 1.0;
166   if (data == NULL && surface == NULL && ctx == NULL)
167   {
168     data = malloc (WIDTH * HEIGHT * 4);
169     surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
170                                                    WIDTH, HEIGHT, WIDTH * 4);
171     ctx = cairo_create (surface);
172   }
173   cairo_scale (ctx, 1.0/rx, 1.0/ry);
174   rx = (double) WIDTH / (double) image->w;
175   ry = (double) HEIGHT / (double) image->h;
176   cairo_scale (ctx, rx, ry);
177   source = CairoFromSDL (image);
178   cairo_set_source_surface (ctx, source, 0, 0);
179   cairo_paint (ctx);
180   cairo_surface_destroy (source);
181   return CairoToSDL (surface);
182 }
183
184 SDL_Surface *
185 GetNextImage (SDL_Surface *image)
186 {
187   SDL_Surface *slice;
188   SDL_Rect center;
189   SDL_Surface *scale;
190   SDL_Surface *text;
191   SDL_Rect box;
192   SDL_Color Yellow = { 255, 255, 0, 0};
193   static double rx = RX, ry = RY, factor = 0.5;
194   if (rx < 0.25)
195   {
196     factor = 1.05;
197   }
198   if (rx > 2)
199   {
200     factor = 0.95238095238095233;
201   }
202   rx *= factor;
203   ry *= factor;
204   center = GetNextPoint ();
205   slice = SDL_CreateRGBSurface (SDL_SWSURFACE, WIDTH*rx, HEIGHT*ry,
206                                 32,
207                                 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
208   center.x -= (WIDTH/2) * rx;
209   center.y -= (HEIGHT/2) * ry;
210   center.w *= rx;
211   center.h *= ry;
212   SDL_BlitSurface (image, &center, slice, NULL);
213   SDL_UpdateRect (slice, 0, 0, 0, 0);
214   scale = CairoTarget (slice);
215   SDL_FreeSurface (slice);
216   if (stop)
217   {
218     text = TTF_RenderUTF8_Solid (font, names[cur], Yellow);
219     box.w = text->w + HBORDER;
220     box.h = text->h + VBORDER;
221     box.x = (WIDTH - text->w - HBORDER) / 2;
222     box.y = HEIGHT - (text->h + 32 + VBORDER/2);
223     SDL_FillRect (scale, &box, SDL_MapRGB (scale->format, 0, 0, 0));
224     box.x += HBORDER/2;
225     box.y += VBORDER/2;
226     box.w -= HBORDER;
227     box.h -= VBORDER;
228     SDL_BlitSurface (text, NULL, scale, &box);
229     SDL_FreeSurface (text);
230   }
231   SDL_UpdateRect (scale, 0, 0, 0, 0);
232   return scale;
233 }
234
235 int
236 main (int argc, char **argv)
237 {
238   SDL_Surface *screen;
239   SDL_Surface *image;
240   SDL_Surface *slice;
241   SDL_Event event;
242   Uint32 now, last;
243   int i;
244   ReadPoints ("pro-gnu");
245   SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER);
246   TTF_Init ();
247   font = TTF_OpenFont ("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 48);
248   screen = SDL_SetVideoMode (WIDTH, HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
249   image = IMG_Load ("/home/cascardo/fotos/debconf.jpg");
250   last = SDL_GetTicks ();
251   while (1)
252   {
253     if (SDL_PollEvent (&event))
254     {
255       if (event.type == SDL_KEYDOWN)
256         break;
257     }
258     now = SDL_GetTicks ();
259     /* skip */
260     while (!stop && now > last + FRAME_INTERVAL)
261     {
262       last += FRAME_INTERVAL;
263       GetNextPoint ();
264     }
265     slice = GetNextImage (image);
266     ShowPoint (screen, slice);
267     SDL_FreeSurface (slice);
268     if (stop)
269     {
270       stop = 0;
271       SDL_Delay (STOP_INTERVAL);
272       last = SDL_GetTicks ();
273     }
274     else
275     {
276       SDL_Delay (FRAME_INTERVAL - (now - last));
277     }
278   }
279   SDL_FreeSurface (image);
280   TTF_CloseFont (font);
281   TTF_Quit ();
282   SDL_Quit ();
283   free (points);
284   for (i = 0; i < psize; i++)
285     free (names[i]);
286   free (names);
287   return 0;
288 }