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