Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 1 | /* |
2 | SDL_anim: an animation library for SDL |
||
3 | Copyright (C) 2001, 2002 Michael Leonhard |
||
4 | |||
5 | This library is free software; you can redistribute it and/or |
||
6 | modify it under the terms of the GNU Library General Public |
||
7 | License as published by the Free Software Foundation; either |
||
8 | version 2 of the License, or (at your option) any later version. |
||
9 | |||
10 | This library is distributed in the hope that it will be useful, |
||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
13 | Library General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU Library General Public |
||
16 | License along with this library; if not, write to the Free |
||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
18 | |||
19 | Michael Leonhard |
||
20 | mike@tamale.net |
||
21 | */ |
||
22 | |||
23 | #include |
||
24 | #include |
||
25 | #include |
||
26 | #include |
||
27 | #include "SDL_anim.h" |
||
28 | |||
29 | /* deal with MSVC++ crappiness */ |
||
30 | #ifdef WIN32UNDEFINED |
||
31 | #define strcasecmp _strcmpi |
||
32 | #endif |
||
33 | |||
34 | void Anim_Free( SDL_Animation *anim ) { |
||
35 | SDL_FreeSurface( anim->surface ); |
||
36 | free( anim ); |
||
37 | } |
||
38 | |||
39 | int Anim_GetFrameNum( SDL_Animation *anim, Uint32 start, Uint32 now ) { |
||
40 | int mspf, ms, frame; |
||
41 | if( now < start ) return 0; |
||
42 | |||
43 | mspf = anim->duration / anim->frames; |
||
44 | ms = now - start; |
||
45 | if( mspf == 0 ) frame = 0; |
||
46 | else frame = ms / mspf; |
||
47 | |||
48 | return frame; |
||
49 | } |
||
50 | |||
51 | void Anim_GetFrameRect( SDL_Animation *anim, int frame, SDL_Rect *rect ) { |
||
52 | rect->x = anim->w * (frame % anim->frames); |
||
53 | rect->y = 0; |
||
54 | rect->w = anim->w; |
||
55 | rect->h = anim->h; |
||
56 | } |
||
57 | |||
58 | int Anim_BlitFrame( SDL_Animation *anim, Uint32 start, Uint32 now, SDL_Surface *dest, SDL_Rect *dr ) { |
||
59 | int frame; |
||
60 | frame = Anim_GetFrameNum( anim, start, now ); |
||
61 | return Anim_BlitFrameNum( anim, frame, dest, dr ); |
||
62 | } |
||
63 | |||
64 | int Anim_BlitFrameNum( SDL_Animation *anim, int frame, SDL_Surface *dest, SDL_Rect *dr ) { |
||
65 | SDL_Rect rect; |
||
66 | Anim_GetFrameRect( anim, frame, &rect ); |
||
67 | return SDL_BlitSurface( anim->surface, &rect, dest, dr ); |
||
68 | } |
||
69 | |||
70 | int Anim_DisplayFormat( SDL_Animation *anim ) { |
||
71 | struct SDL_Surface *newsurface; |
||
72 | if( SDL_WasInit( SDL_INIT_VIDEO ) == 0 ) return 0;/*"Video is not initialized.\n"*/ |
||
73 | newsurface = SDL_DisplayFormatAlpha( anim->surface ); |
||
74 | if( !newsurface ) return 0; |
||
75 | anim->surface = newsurface; |
||
76 | return 1; |
||
77 | } |
||
78 | |||
79 | int DoAnimFormat( char *text, int *duration, int *framewidth, int *numframes ) { |
||
80 | char *tok; |
||
81 | SDL_printf( "file is \"%s\"\n", text ); |
||
82 | |||
83 | /* SDL_anim */ |
||
84 | tok = strtok( text, " " ); |
||
85 | if( !tok ) return 0; |
||
86 | if( strcasecmp( tok, "SDL_anim" ) != 0 ) { |
||
87 | SDL_printf( "no SDL_anim\n" ); |
||
88 | return 0; |
||
89 | } |
||
90 | |||
91 | /* duration */ |
||
92 | tok = strtok( NULL, " " ); |
||
93 | if( !tok ) return 0; |
||
94 | *duration = atoi( tok ); |
||
95 | if( *duration < 1 ) { |
||
96 | SDL_printf( "no duration\n" ); |
||
97 | return 0; |
||
98 | } |
||
99 | |||
100 | /* framewidth */ |
||
101 | tok = strtok( NULL, " " ); |
||
102 | if( !tok ) return 0; |
||
103 | *framewidth = atoi( tok ); |
||
104 | if( *framewidth < 1 ) { |
||
105 | SDL_printf( "no framewidth\n" ); |
||
106 | return 0; |
||
107 | } |
||
108 | |||
109 | /* numframes */ |
||
110 | tok = strtok( NULL, " " ); |
||
111 | if( !tok ) return 0; |
||
112 | *numframes = atoi( tok ); |
||
113 | if( *numframes < 1 ) { |
||
114 | SDL_printf( "no numframes\n" ); |
||
115 | return 0; |
||
116 | } |
||
117 | |||
118 | return 1; |
||
119 | } |
||
120 | |||
121 | struct SDL_Animation *Anim_Load( const char *file ) { |
||
122 | int ckey = -1, i; |
||
123 | char buf[8]; |
||
124 | static FILE *fp; /* "static" prevents setjmp corruption */ |
||
125 | png_structp read_ptr; |
||
126 | png_infop read_info_ptr, end_info_ptr; |
||
127 | png_bytep *row_pointers; |
||
128 | png_textp text_ptr; |
||
129 | int num_text, t; |
||
130 | int interlace_type, compression_type, filter_type, bit_depth, color_type; |
||
131 | png_uint_32 width, height, row; |
||
132 | int duration, framewidth, numframes; |
||
133 | |||
134 | png_color_16p background; |
||
135 | double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; |
||
136 | double gamma; |
||
137 | int intent; |
||
138 | png_uint_16p hist; |
||
139 | png_uint_32 offset_x, offset_y; |
||
140 | int unit_type; |
||
141 | png_charp purpose, units; |
||
142 | png_charpp params; |
||
143 | png_int_32 X0, X1; |
||
144 | int type, nparams; |
||
145 | png_uint_32 res_x, res_y; |
||
146 | /* png_colorp palette; |
||
147 | int num_palette; |
||
148 | */ png_color_8p sig_bit; |
||
149 | png_bytep trans; |
||
150 | int num_trans; |
||
151 | png_color_16p trans_values; |
||
152 | |||
153 | Uint32 Rmask; |
||
154 | Uint32 Gmask; |
||
155 | Uint32 Bmask; |
||
156 | Uint32 Amask; |
||
157 | |||
158 | SDL_Animation *anim; |
||
159 | SDL_Surface *surface; |
||
160 | SDL_Palette *palette; |
||
161 | |||
162 | if( !file ) return NULL; |
||
163 | |||
164 | /* printf( "opening file \"%s\"\n", file ); |
||
165 | */ |
||
166 | /* open the file handle */ |
||
167 | fp = fopen( file, "rb" ); |
||
168 | if( fp == NULL ) { |
||
169 | SDL_printf( "fopen() failed\n" ); |
||
170 | return NULL; |
||
171 | } |
||
172 | |||
173 | /* check if it's PNG */ |
||
174 | if( fread( buf, 1, 8, fp ) != 8 ) { |
||
175 | SDL_printf( "fread() failed\n" ); |
||
176 | return NULL; |
||
177 | } |
||
178 | if( png_sig_cmp( buf, (png_size_t)0, 8 ) ) { |
||
179 | SDL_printf( "not a PNG file\n" ); |
||
180 | return NULL; |
||
181 | } |
||
182 | fseek( fp, 0, SEEK_SET ); |
||
183 | |||
184 | /* allocate read structure */ |
||
185 | read_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL ); |
||
186 | if( read_ptr == NULL ) { |
||
187 | SDL_printf( "png_create_read_struct() failed\n" ); |
||
188 | return NULL; |
||
189 | } |
||
190 | |||
191 | /* allocate read info structure */ |
||
192 | read_info_ptr = png_create_info_struct( read_ptr ); |
||
193 | if( read_info_ptr == NULL ) { |
||
194 | SDL_printf( "png_create_info_struct() failed\n" ); |
||
195 | return NULL; |
||
196 | } |
||
197 | end_info_ptr = png_create_info_struct( read_ptr ); |
||
198 | if( end_info_ptr == NULL ) { |
||
199 | SDL_printf( "png_create_info_struct() failed\n" ); |
||
200 | return NULL; |
||
201 | } |
||
202 | |||
203 | /* set error handler code */ |
||
204 | if( setjmp( read_ptr->jmpbuf ) ) { |
||
205 | SDL_printf( "libpng read error\n" ); |
||
206 | return NULL; |
||
207 | } |
||
208 | |||
209 | /* initialize stream */ |
||
210 | png_init_io( read_ptr, fp ); |
||
211 | png_set_read_status_fn( read_ptr, NULL ); |
||
212 | |||
213 | /* read png info struct */ |
||
214 | png_read_info( read_ptr, read_info_ptr ); |
||
215 | |||
216 | /* get the info */ |
||
217 | if( !png_get_IHDR( read_ptr, read_info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type ) ) { |
||
218 | SDL_printf( "png_get_IHDR() failed\n" ); |
||
219 | return NULL; |
||
220 | } |
||
221 | |||
222 | /* background color */ |
||
223 | png_get_bKGD( read_ptr, read_info_ptr, &background ); |
||
224 | |||
225 | png_get_cHRM( read_ptr, read_info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y ); |
||
226 | |||
227 | /* gamma */ |
||
228 | png_get_gAMA( read_ptr, read_info_ptr, &gamma ); |
||
229 | |||
230 | /* rendering intent */ |
||
231 | png_get_sRGB( read_ptr, read_info_ptr, &intent ); |
||
232 | |||
233 | /* Histogram */ |
||
234 | png_get_hIST( read_ptr, read_info_ptr, &hist ); |
||
235 | |||
236 | /* offsets */ |
||
237 | png_get_oFFs( read_ptr, read_info_ptr, &offset_x, &offset_y, &unit_type ); |
||
238 | |||
239 | png_get_pCAL( read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, ¶ms ); |
||
240 | |||
241 | /* pixel density */ |
||
242 | png_get_pHYs( read_ptr, read_info_ptr, &res_x, &res_y, &unit_type ); |
||
243 | |||
244 | /* png_get_PLTE( read_ptr, read_info_ptr, &palette, &num_palette ); |
||
245 | */ |
||
246 | /* significant bits */ |
||
247 | png_get_sBIT( read_ptr, read_info_ptr, &sig_bit ); |
||
248 | |||
249 | /* transparency */ |
||
250 | if( png_get_tRNS( read_ptr, read_info_ptr, &trans, &num_trans, &trans_values ) ) { |
||
251 | if( color_type == PNG_COLOR_TYPE_PALETTE ) { |
||
252 | if( num_trans == 1 ) ckey = trans[0]; |
||
253 | else png_set_expand( read_ptr ); |
||
254 | } |
||
255 | else ckey = 0; /* actual value will be set later */ |
||
256 | } |
||
257 | |||
258 | /* text chunks */ |
||
259 | num_text = 0; |
||
260 | if( !png_get_text( read_ptr, read_info_ptr, &text_ptr, &num_text ) ) { |
||
261 | SDL_printf( "file has no text chunks\n" ); |
||
262 | return NULL; |
||
263 | } |
||
264 | for( t = 0; t < num_text; t++ ) { |
||
265 | if( strcasecmp( text_ptr[t].key, "format" ) == 0 ) { |
||
266 | if( DoAnimFormat( text_ptr[t].text, &duration, &framewidth, &numframes ) ) break; |
||
267 | } |
||
268 | } |
||
269 | if( t == num_text ) { |
||
270 | SDL_printf( "file is not an SDL_anim PNG\n" ); |
||
271 | return NULL; |
||
272 | } |
||
273 | |||
274 | png_set_strip_16( read_ptr ); |
||
275 | png_set_packing( read_ptr ); |
||
276 | if(color_type == PNG_COLOR_TYPE_GRAY) |
||
277 | png_set_expand( read_ptr ); |
||
278 | |||
279 | /* Allocate the SDL surface to hold the image */ |
||
280 | Rmask = Gmask = Bmask = Amask = 0; |
||
281 | if( color_type != PNG_COLOR_TYPE_PALETTE ) { |
||
282 | if( SDL_BYTEORDER == SDL_LIL_ENDIAN ) { |
||
283 | Rmask = 0x000000FF; |
||
284 | Gmask = 0x0000FF00; |
||
285 | Bmask = 0x00FF0000; |
||
286 | Amask = (read_info_ptr->channels == 4)? 0xFF000000 : 0; |
||
287 | } |
||
288 | else { |
||
289 | int s = (read_info_ptr->channels == 4) ? 0 : 8; |
||
290 | Rmask = 0xFF000000 >> s; |
||
291 | Gmask = 0x00FF0000 >> s; |
||
292 | Bmask = 0x0000FF00 >> s; |
||
293 | Amask = 0x000000FF >> s; |
||
294 | } |
||
295 | } |
||
296 | |||
297 | surface = SDL_AllocSurface( SDL_SWSURFACE, width, height, bit_depth * read_info_ptr->channels, Rmask, Gmask, Bmask, Amask ); |
||
298 | if( surface == NULL ) { |
||
299 | Anim_SetError("Out of memory"); |
||
300 | return NULL; |
||
301 | } |
||
302 | |||
303 | if(ckey != -1) { |
||
304 | if( color_type != PNG_COLOR_TYPE_PALETTE ) ckey = SDL_MapRGB( surface->format, (Uint8)trans_values->red, (Uint8)trans_values->green, (Uint8)trans_values->blue ); |
||
305 | SDL_SetColorKey( surface, SDL_SRCCOLORKEY, ckey ); |
||
306 | } |
||
307 | |||
308 | /* allocate row pointers */ |
||
309 | row_pointers = (png_bytep *)malloc( sizeof( png_bytep ) * height ); |
||
310 | if( row_pointers == NULL ) { |
||
311 | SDL_printf( "malloc() failed\n" ); |
||
312 | return NULL; |
||
313 | } |
||
314 | for( row = 0; row < height; row++ ) { |
||
315 | row_pointers[row] = (Uint8 *)surface->pixels + row * surface->pitch; |
||
316 | } |
||
317 | |||
318 | png_read_image( read_ptr, row_pointers ); |
||
319 | |||
320 | /* end io */ |
||
321 | /* printf( "done\n" ); |
||
322 | */ png_read_end( read_ptr, end_info_ptr ); |
||
323 | |||
324 | /* cleanup */ |
||
325 | png_destroy_read_struct( &read_ptr, &read_info_ptr, &end_info_ptr); |
||
326 | fclose( fp ); |
||
327 | |||
328 | /* Load the palette, if any */ |
||
329 | palette = surface->format->palette; |
||
330 | if( palette ) { |
||
331 | if(color_type == PNG_COLOR_TYPE_GRAY) { |
||
332 | palette->ncolors = 256; |
||
333 | for( i = 0; i < 256; i++ ) { |
||
334 | palette->colors[i].r = i; |
||
335 | palette->colors[i].g = i; |
||
336 | palette->colors[i].b = i; |
||
337 | } |
||
338 | } |
||
339 | else if( read_info_ptr->num_palette > 0 ) { |
||
340 | palette->ncolors = read_info_ptr->num_palette; |
||
341 | for( i = 0; i < read_info_ptr->num_palette; ++i ) { |
||
342 | palette->colors[i].b = read_info_ptr->palette[i].blue; |
||
343 | palette->colors[i].g = read_info_ptr->palette[i].green; |
||
344 | palette->colors[i].r = read_info_ptr->palette[i].red; |
||
345 | } |
||
346 | } |
||
347 | } |
||
348 | |||
349 | anim = (struct SDL_Animation *)malloc( sizeof( struct SDL_Animation ) ); |
||
350 | if( !anim ) { |
||
351 | SDL_printf( "malloc() failed\n" ); |
||
352 | return NULL; |
||
353 | } |
||
354 | |||
355 | anim->surface = surface; |
||
356 | anim->w = framewidth; |
||
357 | anim->h = height; |
||
358 | anim->frames = numframes; |
||
359 | anim->duration = duration; |
||
360 | |||
361 | return anim; |
||
362 | }>>>>>>>> |