Annotation of /trunk/linterm_tools/fw_builder/bootsplash/mng.c
Parent Directory | Revision Log
Revision 658 -
(hide annotations)
(download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 4 months ago) by niro
File MIME type: text/plain
File size: 9395 byte(s)
Mon Jan 14 16:57:24 2008 UTC (16 years, 4 months ago) by niro
File MIME type: text/plain
File size: 9395 byte(s)
initial import
1 | niro | 658 | /* |
2 | * fbmngplay - fb console MNG player. | ||
3 | * (c) 2001-2002 by Stefan Reinauer, <stepan@suse.de> | ||
4 | * | ||
5 | * This program is based on mngplay, part of libmng, written and (C) by | ||
6 | * Ralph Giles <giles@ashlu.bc.ca> | ||
7 | * | ||
8 | * This program my be redistributed under the terms of the | ||
9 | * GNU General Public Licence, version 2, or at your preference, | ||
10 | * any later version. | ||
11 | */ | ||
12 | |||
13 | #include <unistd.h> | ||
14 | #include <sys/time.h> | ||
15 | |||
16 | #include "fbmngplay.h" | ||
17 | #include "console.h" | ||
18 | #include "mng.h" | ||
19 | |||
20 | mngstuff *mng; | ||
21 | unsigned char *bufferstream; | ||
22 | unsigned long bufferpos = 0, buffersize = 0; | ||
23 | |||
24 | /* | ||
25 | * callbacks for the mng decoder | ||
26 | */ | ||
27 | |||
28 | /* memory allocation; data must be zeroed */ | ||
29 | mng_ptr mngalloc(mng_uint32 size) | ||
30 | { | ||
31 | return (mng_ptr) calloc(1, size); | ||
32 | } | ||
33 | |||
34 | /* memory deallocation */ | ||
35 | void mngfree(mng_ptr p, mng_uint32 size) | ||
36 | { | ||
37 | free(p); | ||
38 | return; | ||
39 | } | ||
40 | |||
41 | mng_bool mngopenstream(mng_handle mng) | ||
42 | { | ||
43 | mngstuff *mymng; | ||
44 | |||
45 | /* look up our stream struct */ | ||
46 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
47 | |||
48 | /* open the file */ | ||
49 | mymng->file = fopen(mymng->filename, "rb"); | ||
50 | if (mymng->file == NULL) { | ||
51 | fprintf(stderr, "unable to open '%s'\n", mymng->filename); | ||
52 | run = 0; | ||
53 | return MNG_FALSE; | ||
54 | } | ||
55 | |||
56 | if (buffered) { | ||
57 | unsigned long len; | ||
58 | fseek(mymng->file, 0, SEEK_END); | ||
59 | len = ftell(mymng->file); | ||
60 | rewind(mymng->file); | ||
61 | bufferstream = malloc(len); | ||
62 | if (!bufferstream) { | ||
63 | /* Not enough memory for buffers | ||
64 | * -> we go back to unbuffered mode | ||
65 | */ | ||
66 | printf("Reverted to non buffered mode.\n"); | ||
67 | buffered = 0; | ||
68 | return MNG_TRUE; | ||
69 | } | ||
70 | buffersize = len; | ||
71 | fread(bufferstream, 1, len, mymng->file); | ||
72 | bufferpos = 0; | ||
73 | fclose(mymng->file); | ||
74 | mymng->file = NULL; | ||
75 | } | ||
76 | |||
77 | return MNG_TRUE; | ||
78 | } | ||
79 | |||
80 | mng_bool mngclosestream(mng_handle mng) | ||
81 | { | ||
82 | mngstuff *mymng; | ||
83 | |||
84 | /* look up our stream struct */ | ||
85 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
86 | |||
87 | /* close the file */ | ||
88 | if (mymng->file) | ||
89 | fclose(mymng->file); | ||
90 | mymng->file = NULL; /* for safety */ | ||
91 | |||
92 | if (bufferstream) { | ||
93 | free(bufferstream); | ||
94 | bufferstream = 0; | ||
95 | buffersize = 0; | ||
96 | bufferpos = 0; | ||
97 | } | ||
98 | return MNG_TRUE; | ||
99 | } | ||
100 | |||
101 | /* feed data to the decoder */ | ||
102 | mng_bool mngreadstream(mng_handle mng, mng_ptr buffer, | ||
103 | mng_uint32 size, mng_uint32 * bytesread) | ||
104 | { | ||
105 | mngstuff *mymng; | ||
106 | |||
107 | /* look up our stream struct */ | ||
108 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
109 | if (!buffered) { | ||
110 | /* read the requested amount of data from the file */ | ||
111 | *bytesread = fread(buffer, 1, size, mymng->file); | ||
112 | } else { | ||
113 | *bytesread = (buffersize - bufferpos) < | ||
114 | size ? (buffersize - bufferpos) : size; | ||
115 | memcpy(buffer, bufferstream + bufferpos, *bytesread); | ||
116 | bufferpos += (*bytesread); | ||
117 | } | ||
118 | return MNG_TRUE; | ||
119 | } | ||
120 | |||
121 | mng_bool mnggetbackgroundbuffer(mng_handle mng) | ||
122 | { | ||
123 | unsigned char *background, *src; | ||
124 | mngstuff *mymng = mng_get_userdata(mng); | ||
125 | mng_uint32 width = mymng->width, height = mymng->height; | ||
126 | int bytes = (mymng->fbbpp >> 3); | ||
127 | |||
128 | if (mymng->background) | ||
129 | return MNG_TRUE; | ||
130 | |||
131 | /* If we're not on the right terminal, don't | ||
132 | * initialize background yet. | ||
133 | */ | ||
134 | if (sconly && current_console() != start_console) | ||
135 | return MNG_FALSE; | ||
136 | |||
137 | background = (unsigned char *) malloc(width * height * bytes); | ||
138 | if (background == NULL) { | ||
139 | fprintf(stderr, "could not allocate background buffer.\n"); | ||
140 | exit(0); | ||
141 | } | ||
142 | |||
143 | mymng->background = background; | ||
144 | src = | ||
145 | mymng->display + (mymng->fbwidth * mymng->fby + | ||
146 | mymng->fbx) * bytes; | ||
147 | |||
148 | while (height--) { | ||
149 | memcpy(background, src, width * bytes); | ||
150 | background += width * bytes; | ||
151 | src += mymng->fbrow; | ||
152 | } | ||
153 | |||
154 | return MNG_TRUE; | ||
155 | } | ||
156 | |||
157 | /* the header's been read. set up the display stuff */ | ||
158 | mng_bool mngprocessheader(mng_handle mng, | ||
159 | mng_uint32 width, mng_uint32 height) | ||
160 | { | ||
161 | mngstuff *mymng; | ||
162 | unsigned char *copybuffer; | ||
163 | |||
164 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
165 | mymng->width = width; | ||
166 | mymng->height = height; | ||
167 | |||
168 | copybuffer = (unsigned char *) malloc(width * height * 4); | ||
169 | if (copybuffer == NULL) { | ||
170 | fprintf(stderr, "could not allocate copy buffer.\n"); | ||
171 | exit(0); | ||
172 | } | ||
173 | mymng->copybuffer = copybuffer; | ||
174 | |||
175 | /* Try to get background buffer */ | ||
176 | mnggetbackgroundbuffer(mng); | ||
177 | |||
178 | /* tell the mng decoder about our bit-depth choice */ | ||
179 | /* FIXME: this works on intel. is it correct in general? */ | ||
180 | mng_set_canvasstyle(mng, MNG_CANVAS_BGRA8); | ||
181 | |||
182 | return MNG_TRUE; | ||
183 | } | ||
184 | |||
185 | /* return a row pointer for the decoder to fill */ | ||
186 | mng_ptr mnggetcanvasline(mng_handle mng, mng_uint32 line) | ||
187 | { | ||
188 | mngstuff *mymng; | ||
189 | mng_ptr row; | ||
190 | |||
191 | /* dereference our structure */ | ||
192 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
193 | |||
194 | /* we assume any necessary locking has happened | ||
195 | outside, in the frame level code */ | ||
196 | row = mymng->copybuffer + mymng->width * 4 * line; | ||
197 | |||
198 | return (row); | ||
199 | } | ||
200 | |||
201 | /* timer */ | ||
202 | mng_uint32 mnggetticks(mng_handle mng) | ||
203 | { | ||
204 | mng_uint32 ticks; | ||
205 | struct timeval tv; | ||
206 | struct timezone tz; | ||
207 | |||
208 | gettimeofday(&tv, &tz); | ||
209 | ticks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); | ||
210 | |||
211 | return (ticks); | ||
212 | } | ||
213 | |||
214 | static inline void copyline(unsigned char *dest, unsigned char *src, | ||
215 | unsigned char *background, mngstuff * mymng) | ||
216 | { | ||
217 | // BGRA8 | ||
218 | unsigned int i = mymng->width; | ||
219 | unsigned int fr, fg, fb, br, bg, bb, r, g, b, a; | ||
220 | unsigned short output, input; | ||
221 | |||
222 | while (i--) { | ||
223 | fb = *src++; | ||
224 | fg = *src++; | ||
225 | fr = *src++; | ||
226 | |||
227 | a = *src++; | ||
228 | a = a * mymng->alpha / 100; | ||
229 | switch (mymng->fbbpp) { | ||
230 | case 16: | ||
231 | input = *((unsigned short *) background)++; | ||
232 | |||
233 | br = (input >> mng->fbredo) << (8 - mng->fbredl); | ||
234 | bg = (input >> mng->fbgreeno) << (8 - | ||
235 | mng->fbgreenl); | ||
236 | bb = (input >> mng->fbblueo) << (8 - mng->fbbluel); | ||
237 | br &= 0xf8; | ||
238 | bg &= 0xfc; | ||
239 | bb &= 0xff; | ||
240 | #if 0 | ||
241 | br = (input >> 8) & 0xf8; | ||
242 | bg = (input >> 3) & 0xfc; | ||
243 | bb = input << 3 & 0xff; | ||
244 | #endif | ||
245 | break; | ||
246 | case 24: | ||
247 | bb = *background++; | ||
248 | bg = *background++; | ||
249 | br = *background++; | ||
250 | break; | ||
251 | case 32: | ||
252 | bb = *background++; | ||
253 | bg = *background++; | ||
254 | br = *background++; | ||
255 | background++; | ||
256 | break; | ||
257 | default: | ||
258 | br = 0; | ||
259 | bg = 0; | ||
260 | bb = 0; | ||
261 | printf("depth not supported.\n"); | ||
262 | run = 0; | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | r = ((fr * a) + (br * (0x100 - a))) >> 8; | ||
267 | g = ((fg * a) + (bg * (0x100 - a))) >> 8; | ||
268 | b = ((fb * a) + (bb * (0x100 - a))) >> 8; | ||
269 | |||
270 | switch (mymng->fbbpp) { | ||
271 | case 16: | ||
272 | // dumb 24->16 bit conversion. | ||
273 | r >>= (8 - mng->fbredl); | ||
274 | g >>= (8 - mng->fbgreenl); | ||
275 | b >>= (8 - mng->fbbluel); | ||
276 | |||
277 | output = | ||
278 | (r << mng->fbredo) | (g << mng-> | ||
279 | fbgreeno) | (b << mng-> | ||
280 | fbblueo); | ||
281 | |||
282 | *((unsigned short *) dest)++ = output; | ||
283 | break; | ||
284 | case 24: | ||
285 | *dest++ = b; | ||
286 | *dest++ = g; | ||
287 | *dest++ = r; | ||
288 | break; | ||
289 | case 32: | ||
290 | *dest++ = b; | ||
291 | *dest++ = g; | ||
292 | *dest++ = r; | ||
293 | dest++; | ||
294 | break; | ||
295 | default: | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | |||
301 | mng_bool mngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, | ||
302 | mng_uint32 w, mng_uint32 h) | ||
303 | { | ||
304 | mngstuff *mymng = mng_get_userdata(mng); | ||
305 | unsigned char *background; | ||
306 | unsigned char *dest, *src; | ||
307 | int bytes = (mymng->fbbpp >> 3); | ||
308 | |||
309 | if (sconly && current_console() != start_console) | ||
310 | return MNG_TRUE; | ||
311 | |||
312 | /* When we read the header, we might still | ||
313 | * have been on a different console | ||
314 | */ | ||
315 | |||
316 | if (!(mymng->background)) | ||
317 | mnggetbackgroundbuffer(mng); | ||
318 | |||
319 | background = mymng->background; | ||
320 | |||
321 | dest = | ||
322 | mymng->display + (mymng->fby * mymng->fbwidth + | ||
323 | mymng->fbx) * bytes; | ||
324 | src = mymng->copybuffer; | ||
325 | |||
326 | /* refresh the screen with the new frame */ | ||
327 | while (h-- > 0) { | ||
328 | copyline(dest, src, background, mymng); | ||
329 | |||
330 | dest += mymng->fbrow; | ||
331 | background += mymng->width * bytes; | ||
332 | /* 4 bytes per pixel due to RGBA */ | ||
333 | src += 4 * mymng->width; | ||
334 | } | ||
335 | |||
336 | /* remove traces in alpha transparent pictures. */ | ||
337 | memset(mymng->copybuffer, 0, 4 * mymng->width * mymng->height); | ||
338 | |||
339 | return MNG_TRUE; | ||
340 | } | ||
341 | |||
342 | /* interframe delay callback */ | ||
343 | mng_bool mngsettimer(mng_handle mng, mng_uint32 msecs) | ||
344 | { | ||
345 | mngstuff *mymng; | ||
346 | |||
347 | /* look up our stream struct */ | ||
348 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
349 | |||
350 | /* set the timer for when the decoder wants to be woken */ | ||
351 | mymng->delay = msecs; | ||
352 | |||
353 | return MNG_TRUE; | ||
354 | } | ||
355 | |||
356 | mng_bool mngerror(mng_handle mng, mng_int32 code, mng_int8 severity, | ||
357 | mng_chunkid chunktype, mng_uint32 chunkseq, | ||
358 | mng_int32 extra1, mng_int32 extra2, mng_pchar text) | ||
359 | { | ||
360 | mngstuff *mymng; | ||
361 | char chunk[5]; | ||
362 | |||
363 | /* dereference our data so we can get the filename */ | ||
364 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
365 | /* pull out the chuck type as a string */ | ||
366 | // FIXME: does this assume unsigned char? | ||
367 | chunk[0] = (char) ((chunktype >> 24) & 0xFF); | ||
368 | chunk[1] = (char) ((chunktype >> 16) & 0xFF); | ||
369 | chunk[2] = (char) ((chunktype >> 8) & 0xFF); | ||
370 | chunk[3] = (char) ((chunktype) & 0xFF); | ||
371 | chunk[4] = '\0'; | ||
372 | |||
373 | /* output the error */ | ||
374 | fprintf(stderr, "error playing '%s' chunk %s (%d):\n", | ||
375 | mymng->filename, chunk, chunkseq); | ||
376 | fprintf(stderr, "%s\n", text); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | int mngquit(mng_handle mng) | ||
382 | { | ||
383 | mngstuff *mymng; | ||
384 | |||
385 | /* dereference our data so we can free it */ | ||
386 | mymng = (mngstuff *) mng_get_userdata(mng); | ||
387 | |||
388 | /* cleanup. this will call mymngclosestream */ | ||
389 | mng_cleanup(&mng); | ||
390 | |||
391 | /* free our data */ | ||
392 | free(mymng); | ||
393 | |||
394 | exit(0); | ||
395 | } | ||
396 | |||
397 | void cleanup(void) | ||
398 | { | ||
399 | mngquit(mng->mng); | ||
400 | exit(0); | ||
401 | } | ||
402 | |||
403 | void restore_area(void) | ||
404 | { | ||
405 | int height, width; | ||
406 | unsigned char *dest, *background; | ||
407 | |||
408 | if (sconly && current_console() != start_console) | ||
409 | return; | ||
410 | |||
411 | /* when we didn't manage to get a background until | ||
412 | * now, we don't have anything to restore anyways. | ||
413 | */ | ||
414 | |||
415 | if (!(mng->background)) | ||
416 | return; | ||
417 | |||
418 | background = mng->background; | ||
419 | height = mng->height; | ||
420 | width = mng->width; | ||
421 | dest = mng->display + ((mng->fbwidth * mng->fby + mng->fbx) * | ||
422 | (mng->fbbpp >> 3)); | ||
423 | |||
424 | while (height--) { | ||
425 | memcpy(dest, background, width * (mng->fbbpp >> 3)); | ||
426 | background += width * (mng->fbbpp >> 3); | ||
427 | dest += mng->fbrow; | ||
428 | } | ||
429 | } |