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