Contents of /trunk/busybox/patches/busybox-1.19.0-fbsplash-tykef-1.0.patch
Parent Directory | Revision Log
Revision 1517 -
(show annotations)
(download)
Mon Sep 5 21:30:02 2011 UTC (13 years ago) by niro
File size: 48293 byte(s)
Mon Sep 5 21:30:02 2011 UTC (13 years ago) by niro
File size: 48293 byte(s)
-fixed missing function
1 | diff -Naur busybox-1.19.0/miscutils/Config.src busybox-1.19.0-magellan/miscutils/Config.src |
2 | --- busybox-1.19.0/miscutils/Config.src 2011-08-11 02:23:58.000000000 +0200 |
3 | +++ busybox-1.19.0-magellan/miscutils/Config.src 2011-09-05 21:00:28.000000000 +0200 |
4 | @@ -276,7 +276,8 @@ |
5 | select PLATFORM_LINUX |
6 | help |
7 | Shows splash image and progress bar on framebuffer device. |
8 | - Can be used during boot phase of an embedded device. ~2kb. |
9 | + Can be used during boot phase of an embedded device. |
10 | + Code size is 2..7kb depends on enabled features. |
11 | Usage: |
12 | - use kernel option 'vga=xxx' or otherwise enable fb device. |
13 | - put somewhere fbsplash.cfg file and an image in .ppm format. |
14 | @@ -292,6 +293,44 @@ |
15 | "NN" (ASCII decimal number) - percentage to show on progress bar |
16 | "exit" - well you guessed it |
17 | |
18 | +config FEATURE_FBSPLASH_8BPP |
19 | + bool "support 8bit depth with color mapping" |
20 | + depends on FBSPLASH |
21 | + help |
22 | + support for low color framebuffer that's need color mapping ~350 b |
23 | + |
24 | +config FEATURE_FBSPLASH_SPRITES |
25 | + bool "Render icons and animations" |
26 | + default n |
27 | + depends on FBSPLASH |
28 | + help |
29 | + This option adds the ability to display icons on the |
30 | + image displayed by the fbsplash applet. ~1.5kb. |
31 | + - command for fifo: |
32 | + "load:x:y:filename" - load images from file |
33 | + each sprite is one square area when image is wider than higher |
34 | + before load new sprite set, old area is cleared. |
35 | + "sprite:n" - show one sprite - sprite 0 is background. |
36 | + "anime:n:m:t" - anime from sprite n up/down to sprite m |
37 | + time between sprites is in t * 100 msec. |
38 | + |
39 | +config FEATURE_FBSPLASH_TEXT |
40 | + bool "text rendering" |
41 | + default n |
42 | + depends on FBSPLASH |
43 | + help |
44 | + This option adds the ability to print text messages on the |
45 | + image displayed by the fbsplash applet. ~2kb. |
46 | + - command for fifo: |
47 | + "write:string to print" - print the string after the word "write:" |
48 | + |
49 | +config FEATURE_FBSPLASH_FONTLOAD |
50 | + bool "font loading" |
51 | + depends on FEATURE_FBSPLASH_TEXT |
52 | + help |
53 | + The font is loaded from a standard console font file. |
54 | + Supported are psf v1.x and psf v2.0 files including mapping ~1kb. |
55 | + |
56 | config FLASHCP |
57 | bool "flashcp" |
58 | default n # doesn't build on Ubuntu 8.04 |
59 | diff -Naur busybox-1.19.0/miscutils/fbsplash.c busybox-1.19.0-magellan/miscutils/fbsplash.c |
60 | --- busybox-1.19.0/miscutils/fbsplash.c 2011-08-11 02:23:58.000000000 +0200 |
61 | +++ busybox-1.19.0-magellan/miscutils/fbsplash.c 2011-09-06 01:04:13.000000000 +0200 |
62 | @@ -1,6 +1,7 @@ |
63 | /* vi: set sw=4 ts=4: */ |
64 | /* |
65 | * Copyright (C) 2008 Michele Sanges <michele.sanges@gmail.com> |
66 | + * Copyright (C) 2009 Jiri Gabriel <george.gabriel@seznam.cz> |
67 | * |
68 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
69 | * |
70 | @@ -10,19 +11,51 @@ |
71 | * - run applet: $ setsid fbsplash [params] & |
72 | * -c: hide cursor |
73 | * -d /dev/fbN: framebuffer device (if not /dev/fb0) |
74 | - * -s path_to_image_file (can be "-" for stdin) |
75 | + * -s path_to_image_file - ppm or ppm.gz or ppm.bz2 |
76 | * -i path_to_cfg_file |
77 | * -f path_to_fifo (can be "-" for stdin) |
78 | + * -m font map file - standard psf file (v1 and v2) can be with unumap |
79 | * - if you want to run it only in presence of a kernel parameter |
80 | * (for example fbsplash=on), use: |
81 | * grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params] |
82 | * - commands for fifo: |
83 | * "NN" (ASCII decimal number) - percentage to show on progress bar. |
84 | - * "exit" (or just close fifo) - well you guessed it. |
85 | + * if number is smaller than zero progress bar is filled from left. |
86 | + * "write:string to print" - print the string after the word "write:" |
87 | + * "exit" - well you guessed it. |
88 | + */ |
89 | + |
90 | +/* |
91 | + * enhancements: |
92 | + * - framebuffer can be in depth 8,15,16,24,32 PSEUDOCOLR,TRUECOLOR |
93 | + * not only 16 |
94 | + * - image file cannot be stdin |
95 | + * - bugfix: if virtual size is bigger than visual resolution |
96 | + * - progress bar can be dscending for shutdown (-1..-100) |
97 | + * - progress bar is from background picture + color in cfg - only colorize. |
98 | + * - bouncing bar - command "bounce" and at start. |
99 | + * - smaller image is shown centered on screen cfg positions recalc on demand. |
100 | + * - without text rendering and sprites grow size is only 800b. |
101 | + * text rendering: |
102 | + * - font is standard psf console font |
103 | + * - if font not specified or not compiled in fontload function |
104 | + * font is used from kernel using KDFONTOP / GIO_FONTX / GIO_FONT |
105 | + * - colorize text render by \033[30m .. \033[37m,\033[1;30 .. \033[1;37m |
106 | + * sprites: |
107 | + * - animated sprites load by fifo command "load:x:y:filename". |
108 | + * File is ppm format may be gzipped/bzipped or raw. |
109 | + * Frame/Icon is always square. Width of each Frame is image height. |
110 | + * Frame number 0 is always created for save background. |
111 | + * Transparent color is in ppm file is stored as #FF00FF - purple. |
112 | + * Show frame by pipe command "sprite:n" where n is frame number. |
113 | + * Run animated sequence by "anime:n:m:t" where |
114 | + * n is first frame m is last frame, t is time between displaying |
115 | + * frames in 0.1sec. n can be bigger than m for reverse order in anime. |
116 | */ |
117 | |
118 | //usage:#define fbsplash_trivial_usage |
119 | //usage: "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" |
120 | +//usage: IF_FEATURE_FBSPLASH_FONTLOAD("[-m FONTMAPFILE]") |
121 | //usage:#define fbsplash_full_usage "\n\n" |
122 | //usage: " -s Image" |
123 | //usage: "\n -c Hide cursor" |
124 | @@ -30,31 +63,155 @@ |
125 | //usage: "\n -i Config file (var=value):" |
126 | //usage: "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" |
127 | //usage: "\n BAR_R,BAR_G,BAR_B" |
128 | +//usage: "\n TEXT_LEFT,TEXT_TOP,TEXT_R,TEXT_G,TEXT_B,TEXT_SIZE" |
129 | //usage: "\n -f Control pipe (else exit after drawing image)" |
130 | //usage: "\n commands: 'NN' (% for progress bar) or 'exit'" |
131 | +//usage: IF_FEATURE_FBSPLASH_FONTLOAD( |
132 | +//usage: "\n -m Font map file" |
133 | +//usage: "\n commands: 'NN' (% for progress bar), 'write:string to print' or 'exit'" |
134 | +//usage: ) |
135 | |
136 | #include "libbb.h" |
137 | +#if BB_BIG_ENDIAN |
138 | +#warning "fbsplash work only on little endian architecures. Sorry" |
139 | +int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
140 | +int fbsplash_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { |
141 | + bb_error_msg_and_die("fbsplash not work on big endian architectures."); |
142 | + return 1; |
143 | +} |
144 | + |
145 | +#else |
146 | #include <linux/fb.h> |
147 | |
148 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
149 | +#include <linux/kd.h> |
150 | + |
151 | +/* if you have fonts with sequences can turn this to 1 i not find any font with this feature |
152 | + ~510 bytes of code */ |
153 | +#define ENABLE_FEATURE_FBSPLASH_PSFSEQS 0 |
154 | + |
155 | +/* if you not use text colors and need optimize size - disable text colors |
156 | + ~250 bytes of code */ |
157 | +#define ENABLE_FEATURE_FBSPLASH_TEXT_COLORS 1 |
158 | + |
159 | +#if !defined(GIO_UNIMAP) |
160 | +struct unipair { |
161 | + unsigned short unicode; |
162 | + unsigned short fontpos; |
163 | +} __atribute__ ((packed)); |
164 | + |
165 | +struct unimapdesc { |
166 | + unsigned short entry_ct; |
167 | + struct unipair *entries; |
168 | +} __atribute__ ((packed)); |
169 | +#endif |
170 | + |
171 | +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD |
172 | + |
173 | +enum { // uint16 |
174 | + PSF1_MAGIC = 0x0436, |
175 | + PSF1_SEPARATOR = 0xFFFF, |
176 | + PSF1_STARTSEQ = 0xFFFE |
177 | +}; |
178 | + |
179 | +enum { // uint32 |
180 | + PSF2_MAGIC = 0x864ab572, |
181 | + PSF2_HAS_UNICODE_TABLE = 0x01, /* bits used in flags */ |
182 | + PSF2_MAXVERSION = 0 /* max version recognized so far */ |
183 | +}; |
184 | + |
185 | +enum { // uint8 |
186 | + PSF1_MODE512 = 0x01, |
187 | + PSF1_MODEHASTAB = 0x02, |
188 | + PSF1_MODEHASSEQ = 0x04, |
189 | + PSF1_MAXMODE = 0x05, |
190 | + PSF2_STARTSEQ = 0xFE, |
191 | + PSF2_SEPARATOR = 0xFF |
192 | +}; |
193 | + |
194 | +struct psf1_header { |
195 | + uint16_t magic; /* Magic number */ |
196 | + uint8_t mode; /* PSF font mode */ |
197 | + uint8_t charsize; /* Character size */ |
198 | +} __attribute__ ((packed)); |
199 | + |
200 | +struct psf2_header { |
201 | + uint32_t magic; |
202 | + uint32_t version; |
203 | + uint32_t headersize; /* offset of bitmaps in file */ |
204 | + uint32_t flags; |
205 | + uint32_t length; /* number of glyphs */ |
206 | + uint32_t charsize; /* number of bytes for each character */ |
207 | + uint32_t height, width; /* max dimensions of glyphs */ |
208 | + /* charsize = height * ((width + 7) / 8) */ |
209 | +} __attribute__ ((packed)); |
210 | + |
211 | +#endif // FONTLOAD |
212 | +struct fbfont { |
213 | + uint8_t *mem1; |
214 | + uint8_t *glyphs; |
215 | + struct unimapdesc ud; |
216 | + int height; |
217 | + int width; |
218 | + int glyphcount; |
219 | + int charsize; |
220 | + int rowbytes; |
221 | +}; |
222 | + |
223 | +#endif |
224 | + |
225 | /* If you want logging messages on /tmp/fbsplash.log... */ |
226 | #define DEBUG 0 |
227 | |
228 | +typedef uint32_t RGB; |
229 | + |
230 | +struct sprite { |
231 | + int w,h,bw; // width height in pixels, width in bytes |
232 | + uint8_t pixbuf[0]; |
233 | +}; |
234 | + |
235 | +struct ppmfile { |
236 | + int fd; |
237 | + int sizx,sizy; |
238 | + int bufhead,buftail; |
239 | + uint8_t buf[0]; // buf for entire pixels row |
240 | +}; |
241 | + |
242 | struct globals { |
243 | #if DEBUG |
244 | bool bdebug_messages; // enable/disable logging |
245 | FILE *logfile_fd; // log file |
246 | #endif |
247 | - unsigned char *addr; // pointer to framebuffer memory |
248 | - unsigned ns[7]; // n-parameters |
249 | + unsigned char *addr; // pointer to visible framebuffer memory |
250 | + unsigned char *mapaddr; // pointer to framebuffer memory |
251 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
252 | + #define FBCFGVALS 13 |
253 | +#else |
254 | + #define FBCFGVALS 7 |
255 | +#endif |
256 | + unsigned ns[FBCFGVALS]; // n-parameters |
257 | const char *image_filename; |
258 | struct fb_var_screeninfo scr_var; |
259 | struct fb_fix_screeninfo scr_fix; |
260 | - unsigned bytes_per_pixel; |
261 | + int bytes_per_pixel,x0,y0; // offset for centering |
262 | + struct sprite *spb1,*spb2; |
263 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
264 | + struct fbfont *font; |
265 | + struct sprite *spt; |
266 | + uint8_t *unknown_glyph; |
267 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
268 | + uint8_t combglyph[4*32]; /* max width=32 max height=32 */ |
269 | +#endif |
270 | +#endif |
271 | }; |
272 | + |
273 | #define G (*ptr_to_globals) |
274 | #define INIT_G() do { \ |
275 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
276 | } while (0) |
277 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
278 | + #define GF (*(ptr_to_globals->font)) |
279 | +#endif |
280 | |
281 | #define nbar_width ns[0] // progress bar width |
282 | #define nbar_height ns[1] // progress bar height |
283 | @@ -63,6 +220,75 @@ |
284 | #define nbar_colr ns[4] // progress bar color red component |
285 | #define nbar_colg ns[5] // progress bar color green component |
286 | #define nbar_colb ns[6] // progress bar color blue component |
287 | +#define text_posx ns[7] // text horizontal position |
288 | +#define text_posy ns[8] // text vertical position |
289 | +#define text_colr ns[9] // text color red component |
290 | +#define text_colg ns[10] // text color green component |
291 | +#define text_colb ns[11] // text color blue component |
292 | +#define text_size ns[12] // text size (1 to 4) |
293 | + |
294 | +/** |
295 | + * A function to compute pixel value |
296 | + */ |
297 | +static RGB FAST_FUNC makecol(uint16_t r, uint16_t g, uint16_t b) { |
298 | + if (r > 255) r = 255; |
299 | + if (g > 255) g = 255; |
300 | + if (b > 255) b = 255; |
301 | +#if ENABLE_FEATURE_FBSPLASH_8BPP |
302 | + if (G.bytes_per_pixel == 1) { |
303 | + // mymap is 6*8*5 = 240 values on offset 16 |
304 | + // (r/42.6666) + (g/32) + (b/51.2) |
305 | + return 16 + (((r << 8) + r) / 13107) * 40 + |
306 | + (((g << 8) + g) / 9362) * 5 + |
307 | + (((b << 8) + b) / 16383); |
308 | + } |
309 | +#endif |
310 | + return ((r >> (8 - G.scr_var.red.length )) << G.scr_var.red.offset) | |
311 | + ((g >> (8 - G.scr_var.green.length)) << G.scr_var.green.offset) | |
312 | + ((b >> (8 - G.scr_var.blue.length )) << G.scr_var.blue.offset); |
313 | +} |
314 | + |
315 | +/* |
316 | + * A function to put the pixel row |
317 | + */ |
318 | +static void fb_putpixrow(int x, int y, int w, uint8_t *rgb) { |
319 | + uint8_t *a; |
320 | + int realw; |
321 | + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres) return; |
322 | + a = G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x; |
323 | + realw = ((x + w) < G.scr_var.xres ? w : G.scr_var.xres - x) * G.bytes_per_pixel; |
324 | + memcpy(a,rgb,realw); |
325 | + return; |
326 | +} |
327 | + |
328 | +/* |
329 | + * A function to put the sprite to position or fill sprite from videoram |
330 | + */ |
331 | +static void fb_sprite(int x, int y, int x0, int width, struct sprite *s, int direction) { |
332 | + uint8_t *a,*p; |
333 | + int realw,iy; |
334 | + |
335 | + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres || |
336 | + x0 >= s->w || x0 < 0 || width > (s->w - x0)) { |
337 | + return; |
338 | + } |
339 | + realw = ((x + width) < G.scr_var.xres ? width : (G.scr_var.xres - x)) * G.bytes_per_pixel; |
340 | + a = G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x; |
341 | + p = &(s->pixbuf[x0 * G.bytes_per_pixel]); |
342 | + for (iy = 0; iy < s->h; iy++) { |
343 | + if ((iy + y) > G.scr_var.yres) break; |
344 | + if (direction == 1) { |
345 | + memcpy(p,a,realw); |
346 | + } else { |
347 | + memcpy(a,p,realw); |
348 | + } |
349 | + a += G.scr_fix.line_length; |
350 | + p += s->bw; |
351 | + } |
352 | + return; |
353 | +} |
354 | +#define fb_putsprite(x,y,s) fb_sprite(x,y,0,s->w,s,0) |
355 | +#define fb_getsprite(x,y,s) fb_sprite(x,y,0,s->w,s,1) |
356 | |
357 | #if DEBUG |
358 | #define DEBUG_MESSAGE(strMessage, args...) \ |
359 | @@ -87,19 +313,60 @@ |
360 | xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var); |
361 | xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix); |
362 | |
363 | - if (G.scr_var.bits_per_pixel < 16 || G.scr_var.bits_per_pixel > 32) |
364 | - bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel); |
365 | - G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3; |
366 | +#if ENABLE_FEATURE_FBSPLASH_8BPP |
367 | + if ((G.scr_var.bits_per_pixel < 8) || |
368 | + (G.scr_fix.type != FB_TYPE_PACKED_PIXELS)) { |
369 | + bb_error_msg_and_die("only 8,15,16,24 and 32 bpp is supported"); |
370 | + } |
371 | +#else |
372 | + if ((G.scr_var.bits_per_pixel < 15) || |
373 | + (G.scr_fix.type != FB_TYPE_PACKED_PIXELS)) { |
374 | + bb_error_msg_and_die("only 15,16,24 and 32 bpp is supported"); |
375 | + } |
376 | +#endif |
377 | + switch (G.scr_fix.visual) { |
378 | +#if ENABLE_FEATURE_FBSPLASH_8BPP |
379 | + case FB_VISUAL_PSEUDOCOLOR: do { |
380 | + uint8_t *cmem; |
381 | + struct fb_cmap *cmap; |
382 | + int r,g,b,i; |
383 | + cmem = xzalloc(sizeof(struct fb_cmap) + sizeof(uint16_t) * 3 * 256); |
384 | + cmap = (struct fb_cmap *)cmem; |
385 | + cmap->len = 256; |
386 | + cmap->red = (uint16_t *)&(cmem[sizeof(struct fb_cmap)]); |
387 | + cmap->green = &(cmap->red[256]); |
388 | + cmap->blue = &(cmap->green[256]); |
389 | + xioctl(fbfd, FBIOGETCMAP, cmem); // read original palette |
390 | + // fill cmap with my 6x8x5 pallette |
391 | + for (r = 0,i = 16; r < 6; r++) { |
392 | + for (g = 0; g < 8; g++) { |
393 | + for (b = 0; b < 5; b++, i++) { |
394 | + cmap->red[i] = r * 13107; |
395 | + cmap->green[i] = g * 9362; |
396 | + cmap->blue[i] = b * 16383; |
397 | + } |
398 | + } |
399 | + } |
400 | + xioctl(fbfd, FBIOPUTCMAP, cmem); |
401 | + free(cmem); |
402 | + } while(0); |
403 | +#endif |
404 | + case FB_VISUAL_TRUECOLOR: |
405 | + break; |
406 | + default: |
407 | + bb_error_msg_and_die("only TrueColor modes is supported"); |
408 | + } |
409 | + |
410 | + G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) / 8; |
411 | |
412 | // map the device in memory |
413 | - G.addr = mmap(NULL, |
414 | - G.scr_var.xres * G.scr_var.yres * G.bytes_per_pixel, |
415 | + G.mapaddr = mmap(NULL, |
416 | + G.scr_var.yres_virtual * G.scr_fix.line_length , |
417 | PROT_WRITE, MAP_SHARED, fbfd, 0); |
418 | - if (G.addr == MAP_FAILED) |
419 | + if (G.mapaddr == MAP_FAILED) |
420 | bb_perror_msg_and_die("mmap"); |
421 | - |
422 | // point to the start of the visible screen |
423 | - G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * G.bytes_per_pixel; |
424 | + G.addr = G.mapaddr + G.scr_var.yoffset * G.scr_fix.line_length; |
425 | close(fbfd); |
426 | } |
427 | |
428 | @@ -140,142 +407,60 @@ |
429 | |
430 | |
431 | /** |
432 | - * Draw hollow rectangle on framebuffer |
433 | - */ |
434 | -static void fb_drawrectangle(void) |
435 | -{ |
436 | - int cnt; |
437 | - unsigned thispix; |
438 | - unsigned char *ptr1, *ptr2; |
439 | - unsigned char nred = G.nbar_colr/2; |
440 | - unsigned char ngreen = G.nbar_colg/2; |
441 | - unsigned char nblue = G.nbar_colb/2; |
442 | - |
443 | - thispix = fb_pixel_value(nred, ngreen, nblue); |
444 | - |
445 | - // horizontal lines |
446 | - ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; |
447 | - ptr2 = G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; |
448 | - cnt = G.nbar_width - 1; |
449 | - do { |
450 | - fb_write_pixel(ptr1, thispix); |
451 | - fb_write_pixel(ptr2, thispix); |
452 | - ptr1 += G.bytes_per_pixel; |
453 | - ptr2 += G.bytes_per_pixel; |
454 | - } while (--cnt >= 0); |
455 | - |
456 | - // vertical lines |
457 | - ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; |
458 | - ptr2 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel; |
459 | - cnt = G.nbar_height - 1; |
460 | - do { |
461 | - fb_write_pixel(ptr1, thispix); |
462 | - fb_write_pixel(ptr2, thispix); |
463 | - ptr1 += G.scr_var.xres * G.bytes_per_pixel; |
464 | - ptr2 += G.scr_var.xres * G.bytes_per_pixel; |
465 | - } while (--cnt >= 0); |
466 | -} |
467 | - |
468 | - |
469 | -/** |
470 | - * Draw filled rectangle on framebuffer |
471 | - * \param nx1pos,ny1pos upper left position |
472 | - * \param nx2pos,ny2pos down right position |
473 | - * \param nred,ngreen,nblue rgb color |
474 | - */ |
475 | -static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, |
476 | - unsigned char nred, unsigned char ngreen, unsigned char nblue) |
477 | -{ |
478 | - int cnt1, cnt2, nypos; |
479 | - unsigned thispix; |
480 | - unsigned char *ptr; |
481 | - |
482 | - thispix = fb_pixel_value(nred, ngreen, nblue); |
483 | - |
484 | - cnt1 = ny2pos - ny1pos; |
485 | - nypos = ny1pos; |
486 | - do { |
487 | - ptr = G.addr + (nypos * G.scr_var.xres + nx1pos) * G.bytes_per_pixel; |
488 | - cnt2 = nx2pos - nx1pos; |
489 | - do { |
490 | - fb_write_pixel(ptr, thispix); |
491 | - ptr += G.bytes_per_pixel; |
492 | - } while (--cnt2 >= 0); |
493 | - |
494 | - nypos++; |
495 | - } while (--cnt1 >= 0); |
496 | -} |
497 | - |
498 | - |
499 | -/** |
500 | * Draw a progress bar on framebuffer |
501 | - * \param percent percentage of loading |
502 | + * \param frompct percentage on which bar starting |
503 | + * \param topct percentage where bar end |
504 | */ |
505 | -static void fb_drawprogressbar(unsigned percent) |
506 | +static void fb_drawnbar(int frompct, int topct) |
507 | { |
508 | - int i, left_x, top_y, width, height; |
509 | + int w0,w1,w2; |
510 | |
511 | - // outer box |
512 | - left_x = G.nbar_posx; |
513 | - top_y = G.nbar_posy; |
514 | - width = G.nbar_width - 1; |
515 | - height = G.nbar_height - 1; |
516 | - if ((height | width) < 0) |
517 | + if (G.spb1 == NULL || G.spb2 == NULL) |
518 | return; |
519 | - // NB: "width" of 1 actually makes rect with width of 2! |
520 | - fb_drawrectangle(); |
521 | - |
522 | - // inner "empty" rectangle |
523 | - left_x++; |
524 | - top_y++; |
525 | - width -= 2; |
526 | - height -= 2; |
527 | - if ((height | width) < 0) |
528 | + if (frompct < 0 || frompct > 100 || |
529 | + topct < 0 || topct > 100 || |
530 | + frompct > topct) { |
531 | return; |
532 | - fb_drawfullrectangle( |
533 | - left_x, top_y, |
534 | - left_x + width, top_y + height, |
535 | - G.nbar_colr, G.nbar_colg, G.nbar_colb); |
536 | - |
537 | - if (percent > 0) { |
538 | - // actual progress bar |
539 | - width = width * percent / 100; |
540 | - i = height; |
541 | - if (height == 0) |
542 | - height++; // divide by 0 is bad |
543 | - while (i >= 0) { |
544 | - // draw one-line thick "rectangle" |
545 | - // top line will have gray lvl 200, bottom one 100 |
546 | - unsigned gray_level = 100 + i*100/height; |
547 | - fb_drawfullrectangle( |
548 | - left_x, top_y, left_x + width, top_y, |
549 | - gray_level, gray_level, gray_level); |
550 | - top_y++; |
551 | - i--; |
552 | - } |
553 | } |
554 | + |
555 | + w0 = G.spb1->w * frompct / 100; |
556 | + w0 = (w0 > G.spb1->w ? G.spb1->w : w0); |
557 | + w2 = G.spb1->w * (100 - topct) / 100; |
558 | + w2 = ((w0 + w2) > G.spb1->w ? G.spb1->w - w0 : w2); |
559 | + w1 = G.spb1->w - w0 - w2; |
560 | + if (w0 > 0) |
561 | + fb_sprite(G.nbar_posx, G.nbar_posy, 0, w0, G.spb1, 0); // left "empty" area |
562 | + if (w1 > 0) |
563 | + fb_sprite(G.nbar_posx + w0, G.nbar_posy, w0, w1, G.spb2, 0); // filled area |
564 | + if (w2 > 0) |
565 | + fb_sprite(G.nbar_posx + w0 + w1, G.nbar_posy, w0 + w1, w2, G.spb1, 0); // right "empty" area |
566 | } |
567 | |
568 | +static struct sprite *fb_newsprite(int pw, int ph, int scrx, int scry) { |
569 | + struct sprite *s; |
570 | + s=xmalloc(sizeof(struct sprite) + |
571 | + ph * pw * G.bytes_per_pixel); |
572 | + s->w = pw; |
573 | + s->h = ph; |
574 | + s->bw = pw * G.bytes_per_pixel; |
575 | + if (scrx >= 0) fb_getsprite(scrx, scry, s); // read |
576 | + return s; |
577 | +} |
578 | |
579 | /** |
580 | - * Draw image from PPM file |
581 | + * Open PPM file - must be binary, color maxval 255 |
582 | */ |
583 | -static void fb_drawimage(void) |
584 | -{ |
585 | - FILE *theme_file; |
586 | - char *read_ptr; |
587 | - unsigned char *pixline; |
588 | - unsigned i, j, width, height, line_size; |
589 | - |
590 | - if (LONE_DASH(G.image_filename)) { |
591 | - theme_file = stdin; |
592 | - } else { |
593 | - int fd = open_zipped(G.image_filename); |
594 | - if (fd < 0) |
595 | - bb_simple_perror_msg_and_die(G.image_filename); |
596 | - theme_file = xfdopen_for_read(fd); |
597 | - } |
598 | - |
599 | +static struct ppmfile *ppm_open(const char *filename) { |
600 | + int i,k,l,val; |
601 | + struct ppmfile *p; |
602 | + uint8_t *s; |
603 | + char *e; |
604 | + |
605 | + i = open_zipped(filename); |
606 | + if (i == -1) return NULL; |
607 | + p = (struct ppmfile *) xmalloc(sizeof(struct ppmfile) + 600); |
608 | + // initial buf 600 bytes header cannot be larger |
609 | + p->fd = i; |
610 | /* Parse ppm header: |
611 | * - Magic: two characters "P6". |
612 | * - Whitespace (blanks, TABs, CRs, LFs). |
613 | @@ -289,55 +474,723 @@ |
614 | * - A raster of Width * Height pixels in triplets of rgb |
615 | * in pure binary by 1 or 2 bytes. (we support only 1 byte) |
616 | */ |
617 | -#define concat_buf bb_common_bufsiz1 |
618 | - read_ptr = concat_buf; |
619 | - while (1) { |
620 | - int w, h, max_color_val; |
621 | - int rem = concat_buf + sizeof(concat_buf) - read_ptr; |
622 | - if (rem < 2 |
623 | - || fgets(read_ptr, rem, theme_file) == NULL |
624 | - ) { |
625 | - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); |
626 | - } |
627 | - read_ptr = strchrnul(read_ptr, '#'); |
628 | - *read_ptr = '\0'; /* ignore #comments */ |
629 | - if (sscanf(concat_buf, "P6 %u %u %u", &w, &h, &max_color_val) == 3 |
630 | - && max_color_val <= 255 |
631 | - ) { |
632 | - width = w; /* w is on stack, width may be in register */ |
633 | - height = h; |
634 | - break; |
635 | + l=read(p->fd,&(p->buf[0]),600); |
636 | + if ((l < 0) || (p->buf[0] != 'P') || (p->buf[1] != '6')) { |
637 | + goto ppmopen_end; |
638 | + } |
639 | + for (s = &(p->buf[2]), i = 0, k = 0; s < &(p->buf[l]) && (k < 3); ) { |
640 | + switch (i) { |
641 | + case 0: |
642 | + if (*s <= ' ') { |
643 | + s++; // skip whitespaces |
644 | + } else { |
645 | + i++; // next state |
646 | + } |
647 | + break; |
648 | + case 1: // num or rmks |
649 | + if (*s == '#') { |
650 | + i = 2; |
651 | + } else { |
652 | + val=bb_strtoi((char *)s,&e,10); |
653 | + if (s == (uint8_t *)e) goto ppmopen_end; // no number - error |
654 | + s=(uint8_t *)e; |
655 | + i=0; // skip whitespaces |
656 | + switch (++k) { |
657 | + case 1: p->sizx = val; break; |
658 | + case 2: p->sizy = val; break; |
659 | + case 3: |
660 | + if (val > 255) |
661 | + goto ppmopen_end; // only 1 byte per color |
662 | + s++; |
663 | + p->bufhead = s - &(p->buf[0]); |
664 | + p->buftail = l; |
665 | + break; |
666 | + } |
667 | + } |
668 | + break; |
669 | + case 2: // skip to eol |
670 | + if (*s == 10) i=0; |
671 | + s++; |
672 | + break; |
673 | + } |
674 | + } |
675 | + if (p->sizx < 1 || p->sizy < 1) goto ppmopen_end; |
676 | + if (p->sizx > 200) { |
677 | + // buf is only 600 bytes = 200 pix prealocated - need more. |
678 | + p = xrealloc(p,sizeof(struct ppmfile) + 3 * p->sizx); |
679 | + } |
680 | + return p; |
681 | + |
682 | +ppmopen_end: |
683 | + close(p->fd); |
684 | + free(p); |
685 | + return NULL; |
686 | +} |
687 | + |
688 | +/** |
689 | + * Read pixelline from ppm to internal buffer and return pointer |
690 | + */ |
691 | +static uint8_t *ppm_readline(struct ppmfile *p) { |
692 | + int i; |
693 | + if (p==NULL) return NULL; |
694 | + if (p->bufhead < p->buftail) { |
695 | + // pack buffer |
696 | + for (i = 0; p->bufhead < p->buftail; i++) { |
697 | + p->buf[i]=p->buf[p->bufhead++]; |
698 | } |
699 | + p->buftail = i; |
700 | + } else { |
701 | + p->buftail = 0; |
702 | + } |
703 | + while (p->buftail < (p->sizx * 3)) { |
704 | + i=read(p->fd, &(p->buf[p->buftail]), (p->sizx * 3) - p->buftail); |
705 | + if (i < 0) return NULL; |
706 | + p->buftail += i; |
707 | } |
708 | + p->bufhead = p->sizx * 3; |
709 | + return &(p->buf[0]); |
710 | +} |
711 | |
712 | - line_size = width*3; |
713 | - pixline = xmalloc(line_size); |
714 | +/** |
715 | + * Close ppmfile |
716 | + */ |
717 | +static void ppm_close(struct ppmfile *p) { |
718 | + if (p == NULL) return; |
719 | + close(p->fd); |
720 | + free(p); |
721 | +} |
722 | + |
723 | +/** |
724 | + * Draws a PPM image. |
725 | + */ |
726 | +static void fb_drawimage(void) |
727 | +{ |
728 | + struct ppmfile *ppm; |
729 | + unsigned char *pixel; |
730 | + unsigned char *rgbline,*rgbpix,*sprpix; |
731 | + RGB thispix; |
732 | + unsigned i, j, width, height; |
733 | + |
734 | + ppm = ppm_open(G.image_filename); |
735 | + if (ppm == NULL) |
736 | + bb_error_msg_and_die("PPM file %s cannot be opened",G.image_filename); |
737 | + width = ppm->sizx; |
738 | + height = ppm->sizy; |
739 | + if (width > G.scr_var.xres || height > G.scr_var.yres) |
740 | + bb_error_msg_and_die("PPM %dx%d does not match screen %dx%d", |
741 | + width, height, G.scr_var.xres, G.scr_var.yres); |
742 | + if (width > G.scr_var.xres) |
743 | + width = G.scr_var.xres; |
744 | + if (height > G.scr_var.yres) |
745 | + height = G.scr_var.yres; |
746 | + |
747 | + G.x0 = (width == G.scr_var.xres ? 0 : (G.scr_var.xres - width) / 2); |
748 | + G.y0 = (height == G.scr_var.yres ? 0 : (G.scr_var.yres - height) / 2); |
749 | + rgbline = xmalloc((width * G.bytes_per_pixel) + sizeof(RGB)); |
750 | |
751 | - if (width > G.scr_var.xres) |
752 | - width = G.scr_var.xres; |
753 | - if (height > G.scr_var.yres) |
754 | - height = G.scr_var.yres; |
755 | for (j = 0; j < height; j++) { |
756 | - unsigned char *pixel; |
757 | - unsigned char *src; |
758 | + pixel = ppm_readline(ppm); |
759 | + rgbpix = rgbline; |
760 | + if (pixel == NULL) |
761 | + bb_error_msg_and_die("bad PPM file '%s' line %d", G.image_filename,j); |
762 | + if (G.spb2 != NULL && j >= G.nbar_posy && j < (G.nbar_posy + G.spb2->h)) { |
763 | + sprpix = &(G.spb2->pixbuf[(j - G.nbar_posy) * G.spb2->bw]); |
764 | + } else { |
765 | + sprpix = NULL; |
766 | + } |
767 | |
768 | - if (fread(pixline, 1, line_size, theme_file) != line_size) |
769 | - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); |
770 | - pixel = pixline; |
771 | - src = G.addr + j * G.scr_fix.line_length; |
772 | for (i = 0; i < width; i++) { |
773 | - unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]); |
774 | - fb_write_pixel(src, thispix); |
775 | - src += G.bytes_per_pixel; |
776 | + thispix = makecol(pixel[0],pixel[1],pixel[2]); |
777 | + *((RGB*)rgbpix) = thispix; |
778 | + if ((sprpix != NULL) && (i >= G.nbar_posx)) { |
779 | + if (G.nbar_colr >= 256) { // Multiple not add |
780 | + thispix = makecol((G.nbar_colr & 255) * pixel[0], (G.nbar_colg & 255) * pixel[1], (G.nbar_colb & 255) * pixel[2]); |
781 | + } else { |
782 | + thispix = makecol(G.nbar_colr + pixel[0], G.nbar_colg + pixel[1], G.nbar_colb + pixel[2]); |
783 | + } |
784 | + memcpy(sprpix,&thispix,G.bytes_per_pixel); |
785 | + if (i >= (G.nbar_posx + G.spb2->w - 1)) { |
786 | + sprpix = NULL; |
787 | + } else { |
788 | + sprpix += G.bytes_per_pixel; |
789 | + } |
790 | + } |
791 | + pixel += 3; |
792 | + rgbpix += G.bytes_per_pixel; |
793 | + } |
794 | + fb_putpixrow(G.x0,j + G.y0,width,rgbline); |
795 | + } |
796 | + free(rgbline); |
797 | + ppm_close(ppm); |
798 | + // recalc cfg if centered image |
799 | + G.nbar_posx += G.x0; |
800 | + G.nbar_posy += G.y0; |
801 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
802 | + G.text_posx += G.x0; |
803 | + G.text_posy += G.y0; |
804 | +#endif |
805 | +} |
806 | + |
807 | +#if ENABLE_FEATURE_FBSPLASH_SPRITES |
808 | +/** |
809 | + * Read rectangle sprites from ppm file |
810 | + * \return pointer to array of sprites |
811 | + * \return number of sprites loaded |
812 | + */ |
813 | +static struct sprite *fb_loadsprites(char *filename, int sx, int sy) { |
814 | + struct ppmfile *ppm; |
815 | + uint8_t *pixel, *rgbpix; |
816 | + struct sprite *s=NULL; |
817 | + int y,i; |
818 | + RGB thispix; |
819 | + |
820 | + if ((ppm = ppm_open(filename)) == NULL) goto readsprites_out; |
821 | + s = fb_newsprite(ppm->sizx + ppm->sizy, ppm->sizy, -1, -1); |
822 | + fb_sprite(sx + G.x0, sy + G.y0, 0, s->h, s, 1); // load square 0 - background |
823 | + rgbpix = &(s->pixbuf[0]); |
824 | + for (y = 0; y < ppm->sizy; y++) { |
825 | + // skip square 0 |
826 | + rgbpix += s->h * G.bytes_per_pixel; |
827 | + // read from file |
828 | + pixel = ppm_readline(ppm); |
829 | + for (i = 0; (pixel != NULL) && (i < ppm->sizx); i++) { |
830 | + if (pixel[0]==0xFF && pixel[1]==0 && pixel[2]==0xFF) { |
831 | + // transparent color => get pixel from square 0 |
832 | + memcpy(&thispix, |
833 | + &(s->pixbuf[y * s->bw + (i % s->h) * G.bytes_per_pixel]), |
834 | + G.bytes_per_pixel); |
835 | + } else { |
836 | + thispix = makecol(pixel[0],pixel[1],pixel[2]); |
837 | + } |
838 | + memcpy(rgbpix,&thispix,G.bytes_per_pixel); |
839 | pixel += 3; |
840 | + rgbpix += G.bytes_per_pixel; |
841 | + } |
842 | + } |
843 | + ppm_close(ppm); |
844 | + return s; |
845 | +readsprites_out: |
846 | + if (s != NULL) free(s); |
847 | + return NULL; |
848 | +} |
849 | + |
850 | +#define fb_putanim(x,y,n,s) fb_sprite(x + G.x0,y + G.y0,s->h * n,s->h,s,0) |
851 | +#endif |
852 | + |
853 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
854 | + |
855 | +/* |
856 | + * A function to put the pixel |
857 | + */ |
858 | +static void fb_putpixel(int x, int y, RGB rgb) { |
859 | + uint8_t *a; |
860 | + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres) return; |
861 | + a=G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x; |
862 | + memcpy(a,&rgb,G.bytes_per_pixel); |
863 | + |
864 | + return; |
865 | +} |
866 | + |
867 | +/** |
868 | + * UTF-8 - get one charcter and advance to next |
869 | + * ??? this function may be in libbb ??? |
870 | + * \return UCS4 value |
871 | + */ |
872 | +static uint32_t ucs4value(uint8_t **s) { |
873 | + uint8_t *c; |
874 | + uint32_t ucs,w; |
875 | + int count; |
876 | + |
877 | + if (s==NULL || *s==NULL || **s==0) return 0; |
878 | + c = *s; |
879 | + ucs = *c++; |
880 | + if (ucs >= 0xC0) { /* 0x80..0xBF is error in utf8 but i use as-is */ |
881 | + for (w = ucs & 0x7F, count = 0;(w & 0x40) == 0x40; count++) { |
882 | + w <<= 1; |
883 | + } |
884 | + ucs=ucs & (0x7E >> count); |
885 | + for(; count > 0; count--) { |
886 | + if ((*c & 0xC0) != 0x80) { /* error in utf8 */ |
887 | + ucs=0; |
888 | + break; |
889 | + } |
890 | + ucs = (ucs << 6) + (*c++ & 0x3F); |
891 | + } |
892 | + } |
893 | + *s=c; |
894 | + return ucs; |
895 | +} |
896 | + |
897 | +/** |
898 | + * Find in GF.ud.entries desired UTF-8 char and advance to next char |
899 | + * can combine glyphs in own memory |
900 | + * \param s pointer to utf8 char pointer |
901 | + * \return pinter to glyph |
902 | + */ |
903 | +static uint8_t *getglyph(uint8_t **s) { |
904 | + uint32_t ucs; |
905 | + uint8_t *c,*g; |
906 | + int utflen,i; |
907 | + |
908 | + if (s == NULL || *s == NULL || **s == 0) |
909 | + return G.unknown_glyph; /* end of string - no advance */ |
910 | + c = *s; |
911 | + ucs = ucs4value(&c); |
912 | + utflen = c - *s; |
913 | + g = G.unknown_glyph; |
914 | + if (GF.ud.entries == NULL) { |
915 | + if (ucs < GF.glyphcount) { |
916 | + g = GF.glyphs + GF.charsize * ucs; |
917 | + } |
918 | + } else if (ucs <= 0xFFFF) { // only ucs2 |
919 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
920 | + int j,compose; |
921 | + memset(G.combglyph,0,sizeof(G.combglyph)); |
922 | + for (i = 0, compose=0; i < GF.ud.entry_ct; i++) { |
923 | + if (GF.ud.entries[i].unicode == ucs) { |
924 | + g=GF.glyphs + |
925 | + GF.ud.entries[i].fontpos * GF.charsize; |
926 | + for (j = 0; j < GF.charsize; j++) { |
927 | + G.combglyph[j] |= g[j]; |
928 | + } |
929 | + compose++; |
930 | + } |
931 | + } |
932 | + if (compose > 1) { // found more than one |
933 | + g = &(G.combglyph[0]); |
934 | + } |
935 | +#else |
936 | + // no sequences - first found win |
937 | + for (i = 0; i < GF.ud.entry_ct ; i++) { |
938 | + if (GF.ud.entries[i].unicode == ucs) { |
939 | + g = GF.glyphs + GF.ud.entries[i].fontpos * GF.charsize; |
940 | + break; |
941 | + } |
942 | } |
943 | +#endif |
944 | + } |
945 | + *s=c; |
946 | + return g; |
947 | +} |
948 | + |
949 | +/** |
950 | + * Draws a single character on framebuffer. |
951 | + * \param nXPos horizontal position from which draw the character. |
952 | + * \param nYPos vertical position from which draw the character. |
953 | + * \param nCharSize character scale factor [1..4]. |
954 | + * \param pointer to *nChar character to draw - auto advance by utf8. |
955 | + * \param RGB color |
956 | + */ |
957 | +static void fb_drawchar(int nXPos, int nYPos, int nCharSize, |
958 | + uint8_t **nChar, RGB thispix) |
959 | +{ |
960 | + int x,y,px; |
961 | + uint8_t *glyph; |
962 | + |
963 | + if (G.font==NULL || GF.height==0 || GF.glyphs==NULL) return; |
964 | + if (G.unknown_glyph == NULL) { |
965 | + uint8_t *unknown; |
966 | + const uint8_t unconst[]="?"; |
967 | + unknown=(uint8_t *)unconst; |
968 | + G.unknown_glyph = getglyph(&unknown); |
969 | + } |
970 | + |
971 | + glyph=getglyph(nChar); |
972 | + if (glyph==NULL) return; |
973 | + glyph-=GF.rowbytes; |
974 | + for (y = 0; y < (GF.height * nCharSize); y++) { |
975 | + if ((y % nCharSize) == 0) glyph+=GF.rowbytes; |
976 | + for (x = 0,px = -1; x < (GF.width * nCharSize); x++) { |
977 | + if ((x % nCharSize) == 0) px++; |
978 | + if ((glyph[px / 8] & (0x80 >> (px % 8))) != 0) { |
979 | + fb_putpixel(nXPos + x, nYPos + y,thispix); |
980 | + } |
981 | + } |
982 | } |
983 | - free(pixline); |
984 | - fclose(theme_file); |
985 | } |
986 | |
987 | |
988 | /** |
989 | + * Draws a string on framebuffer. |
990 | + * \param *strString pointer to the string. |
991 | + */ |
992 | +static void fb_drawstring(char *strString) |
993 | +{ |
994 | + RGB thispix; |
995 | + int nCharSize; |
996 | + int x; |
997 | + uint8_t *c; |
998 | + |
999 | + // size check |
1000 | + nCharSize = G.text_size; |
1001 | + if (nCharSize < 1) |
1002 | + nCharSize = 1; |
1003 | + else if (nCharSize > 4) |
1004 | + nCharSize = 4; |
1005 | + |
1006 | + if (G.font==NULL || GF.height==0 || GF.glyphs==NULL) return; |
1007 | + |
1008 | + // redraws the portion of image interested to the old write operation |
1009 | + fb_putsprite(G.text_posx, G.text_posy, G.spt); |
1010 | + |
1011 | + // new write operation |
1012 | + thispix=makecol(G.text_colr,G.text_colg,G.text_colb); |
1013 | + for (x = G.text_posx, c = (uint8_t *)strString; *c != 0;) { |
1014 | +#if ENABLE_FEATURE_FBSPLASH_TEXT_COLORS |
1015 | + if (*c==0x1b && c[1]=='[') { |
1016 | + long newcol=0,first; |
1017 | + char *e; |
1018 | + e=(char *)&(c[1]); |
1019 | + do { |
1020 | + first=newcol; |
1021 | + ++e; |
1022 | + newcol = strtol(e,&e,10); |
1023 | + } while (*e == ';'); |
1024 | + if (*e == 'm' && ((newcol == 0) || (newcol >= 30 && newcol <= 37))) { |
1025 | + if (newcol >= 30 && newcol <= 37) { |
1026 | + if (newcol == 0 && first == 1) { |
1027 | + thispix=makecol(0x33,0x33,0x33); |
1028 | + } else { |
1029 | + newcol -= 30; |
1030 | + first = (first == 1 ? 0xFF : 0xCC); |
1031 | + thispix=makecol((newcol & 1) ? first : 0, |
1032 | + (newcol & 2) ? first : 0, |
1033 | + (newcol & 4) ? first : 0); |
1034 | + } |
1035 | + } else { |
1036 | + thispix=makecol(G.text_colr,G.text_colg,G.text_colb); |
1037 | + } |
1038 | + c=(uint8_t *)(++e); |
1039 | + continue; |
1040 | + } |
1041 | + } |
1042 | +#endif |
1043 | + fb_drawchar(x, G.text_posy, nCharSize, &c, thispix); |
1044 | + x += GF.width * nCharSize; |
1045 | + if (x >= G.scr_var.xres) break; // too long string |
1046 | + } |
1047 | +} |
1048 | + |
1049 | +/** |
1050 | + * Free readed font structure with all allocated memory |
1051 | + */ |
1052 | +static void fb_freefont(void) { |
1053 | + if (G.font != NULL) { |
1054 | + if (GF.mem1 != NULL) free(GF.mem1); |
1055 | + if (GF.ud.entries != NULL) free(GF.ud.entries); |
1056 | + free(G.font); |
1057 | + G.font=NULL; |
1058 | + } |
1059 | +} |
1060 | + |
1061 | +/** |
1062 | + * Read font and mapping from console using ioctl GIO_FONT and GIO_UNIMAP |
1063 | + */ |
1064 | +static void fb_readvgafont(void) { |
1065 | + int fd,i; |
1066 | +#if (defined(KDFONTOP) && defined(KD_FONT_OP_GET)) || defined(GIO_FONTX) |
1067 | +#if defined(KDFONTOP) && defined(KD_FONT_OP_GET) |
1068 | + struct console_font_op fo; |
1069 | + fd = open(CURRENT_TTY,O_NONBLOCK); |
1070 | + if (fd == -1) return; |
1071 | + |
1072 | + fo.data = NULL; |
1073 | + fo.charcount = 0; |
1074 | + fo.height = 32; fo.width = 32; // max usable font size |
1075 | + fo.flags = 0; |
1076 | + fo.op = KD_FONT_OP_GET; |
1077 | + if (ioctl(fd, KDFONTOP, &fo) == 0) { |
1078 | + i = (fo.width + 7) / 8; |
1079 | + fo.data = xmalloc(fo.charcount * 32 * i); |
1080 | + if (ioctl(fd, KDFONTOP, &fo) == -1) { |
1081 | + free(fo.data); |
1082 | + goto fb_vgafontout; |
1083 | + } |
1084 | + } |
1085 | + if (G.font != NULL) fb_freefont(); |
1086 | + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont)); |
1087 | + GF.height = fo.height; |
1088 | + GF.glyphcount = fo.charcount; |
1089 | + GF.width = fo.width; |
1090 | + GF.rowbytes = (fo.width + 7) / 8; |
1091 | + GF.charsize = GF.height * GF.rowbytes; |
1092 | + GF.mem1 = (uint8_t *) xmalloc(GF.height * GF.glyphcount * GF.rowbytes); |
1093 | + GF.glyphs = GF.mem1; |
1094 | + for (i = 0; i < GF.glyphcount; i++) { |
1095 | + memcpy(&(GF.glyphs[i * GF.height * GF.rowbytes]), |
1096 | + &(fo.data[i * 32 * GF.rowbytes]), |
1097 | + GF.height * GF.rowbytes); |
1098 | + } |
1099 | + if (fo.data) free(fo.data); |
1100 | +#else // KDFONTOP / GIO_FONTX |
1101 | + struct consolefontdesc cfd; |
1102 | + int j; |
1103 | + fd = open(CURRENT_TTY,O_NONBLOCK); |
1104 | + if (fd == -1) return; |
1105 | + |
1106 | + cfd.chardata = NULL; |
1107 | + cfd.charcount = 0; |
1108 | + cfd.charheight = 0; |
1109 | + if (ioctl(fd, GIO_FONTX, &cfd) == 0) { |
1110 | + cfd.chardata = xmalloc(cfd.charcount * 32); |
1111 | + if (ioctl(fd, GIO_FONTX, &cfd) == -1) { |
1112 | + free(cfd.chardata); |
1113 | + goto fb_vgafontout; |
1114 | + } |
1115 | + } else { |
1116 | + cfd.charcount=256; |
1117 | + cfd.chardata = xmalloc(256 * 32); |
1118 | + if (ioctl(fd, GIO_FONT, cfd.chardata) != 0) { |
1119 | + free(cfd.chardata); |
1120 | + goto fb_vgafontout; |
1121 | + } |
1122 | + // compute real height |
1123 | + cfd.charheight=0; |
1124 | + for (j = 31; (j > 0) && (cfd.charheight == 0); j--) { |
1125 | + for (i = 0; (i < 256) && (cfd.charheight == 0); i++) { |
1126 | + if (cfd.chardata[i*32+j] != 0) |
1127 | + cfd.charheight=j; |
1128 | + } |
1129 | + } |
1130 | + } |
1131 | + if (cfd.charheight != 0) { |
1132 | + if (G.font != NULL) fb_freefont(); |
1133 | + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont)); |
1134 | + GF.charsize = cfd.charheight; |
1135 | + GF.height = GF.charsize; |
1136 | + GF.glyphcount = cfd.charcount; |
1137 | + GF.width = 8; |
1138 | + GF.rowbytes = 1; |
1139 | + GF.mem1 = (uint8_t *) xmalloc(GF.height * GF.glyphcount); |
1140 | + GF.glyphs = GF.mem1; |
1141 | + // pack font |
1142 | + for (i = 0; i < GF.glyphcount; i++) { |
1143 | + memcpy(&(GF.glyphs[i * GF.height]), |
1144 | + &(cfd.chardata[i * 32]), |
1145 | + GF.height); |
1146 | + } |
1147 | + } |
1148 | + free(cfd.chardata); |
1149 | +#endif // FONTOP / FONTX |
1150 | +#if defined(GIO_UNIMAP) |
1151 | + GF.ud.entry_ct = 0; |
1152 | + ioctl(fd, GIO_UNIMAP, &(GF.ud)); |
1153 | + if (errno != ENOMEM) { |
1154 | + goto fb_vgafontout; |
1155 | + } |
1156 | + if (GF.ud.entry_ct > 0) { |
1157 | + GF.ud.entries = xmalloc(GF.ud.entry_ct * sizeof(struct unipair)); |
1158 | + if (ioctl(fd, GIO_UNIMAP, &(GF.ud)) == -1) { |
1159 | + // error no unimap |
1160 | + free(GF.ud.entries); |
1161 | + GF.ud.entry_ct = 0; |
1162 | + } |
1163 | + } |
1164 | +#endif // GIO_UNIMAP |
1165 | +fb_vgafontout: |
1166 | + close(fd); |
1167 | +#endif // GIO_FONTX or KDFONTOP available |
1168 | + return; |
1169 | +} |
1170 | + |
1171 | +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD |
1172 | + |
1173 | +static uint16_t nextuni(int ver, uint8_t *map, int *pos) { |
1174 | + uint16_t rv; |
1175 | + int i; |
1176 | + i=*pos; |
1177 | + if (ver==1) { |
1178 | + rv = map[i + 1]; |
1179 | + rv = (rv << 8) + map[i]; |
1180 | + i += 2; |
1181 | + } else { // ver 2 |
1182 | + if (map[i] == 0xFF) rv = 0xFFFF; |
1183 | + else if (map[i] == 0xFE) rv = 0xFFFE; |
1184 | + else if (map[i] < 0xC0) rv = map[i]; |
1185 | + else if (map[i] < 0xE0) { |
1186 | + rv = map[i] & 0x1F; |
1187 | + if ((map[i + 1] & 0xC0) == 0x80) |
1188 | + rv = (rv << 6) + (map[++i] & 0x3F); |
1189 | + } else if (map[i] < 0xF0) { |
1190 | + rv = map[i] & 0x0F; |
1191 | + if ((map[i + 1] & 0xC0) == 0x80) |
1192 | + rv = (rv << 6) + (map[++i] & 0x3F); |
1193 | + if ((map[i + 1] & 0xC0) == 0x80) |
1194 | + rv = (rv << 6) + (map[++i] & 0x3F); |
1195 | + } else rv = map[i]; |
1196 | + i++; |
1197 | + } |
1198 | + *pos=i; |
1199 | + return rv; |
1200 | +} |
1201 | + |
1202 | +/** |
1203 | + * Convert unimap from psf v1 and psf v2 to unimapdesc |
1204 | + */ |
1205 | +static void convertmap(int ver, uint8_t *map, int mapsize, struct unimapdesc *ud) { |
1206 | + int i,j,k,glyph,glycodes; |
1207 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
1208 | + int l, seqlen=0, *seq=NULL; |
1209 | +#endif |
1210 | + uint16_t e; |
1211 | + ud->entry_ct=0; |
1212 | + for (i = 0, glycodes=0; i < mapsize; ) { |
1213 | + e = nextuni(ver, map, &i); |
1214 | + if (e == PSF1_STARTSEQ) { |
1215 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
1216 | + seqlen++; |
1217 | +#endif |
1218 | + e = nextuni(ver, map, &i); |
1219 | + while ((e != PSF1_SEPARATOR) && (i < mapsize)) { |
1220 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
1221 | + ud->entry_ct += glycodes; |
1222 | +#endif |
1223 | + e = nextuni(ver, map, &i); |
1224 | + } |
1225 | + glycodes=0; |
1226 | + } else if (e == PSF1_SEPARATOR) { |
1227 | + ud->entry_ct += glycodes; |
1228 | + glycodes=0; |
1229 | + } else { |
1230 | + glycodes++; |
1231 | + } |
1232 | + } |
1233 | + ud->entries = (struct unipair *) |
1234 | + xmalloc(sizeof(struct unimapdesc) * ud->entry_ct); |
1235 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
1236 | + if (seqlen > 0) { |
1237 | + seq = xzalloc(sizeof(int) * (seqlen + 1)); |
1238 | + } |
1239 | +#endif |
1240 | + for (i = 0, glyph = 0, j = 0, k = 0; i < mapsize; ) { |
1241 | + e = nextuni(ver, map, &i); |
1242 | + if (e == PSF1_STARTSEQ) { |
1243 | + e = nextuni(ver, map, &i); |
1244 | + k++; // this is seqence - position saved |
1245 | + // remove sequence - this is not glyph |
1246 | + while (ud->entries[j-1].fontpos == glyph && j > 0) { |
1247 | + j--; |
1248 | + } |
1249 | + // skip chars in seq |
1250 | + while ((e != PSF1_SEPARATOR) && (i < mapsize)) { |
1251 | + e = nextuni(ver, map, &i); |
1252 | + } |
1253 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
1254 | + if (k < seqlen) seq[k] = i; |
1255 | +#endif |
1256 | + } else if (e == PSF1_SEPARATOR) { |
1257 | + glyph++; |
1258 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
1259 | + // next may be sequence |
1260 | + if (k < seqlen) seq[k] = i; |
1261 | +#endif |
1262 | + } else if (j < ud->entry_ct) { |
1263 | + ud->entries[j].unicode=e; |
1264 | + ud->entries[j++].fontpos=glyph; |
1265 | + } |
1266 | + } |
1267 | +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS |
1268 | + i = 0; |
1269 | + while (i < seqlen) { |
1270 | + k = seq[i]; |
1271 | + do { |
1272 | + e = nextuni(ver, map, &k); |
1273 | + } while (e != PSF1_STARTSEQ && e != PSF1_SEPARATOR && k < mapsize); |
1274 | + if (e == PSF1_STARTSEQ) { |
1275 | + e = nextuni(ver, map, &k); |
1276 | + while ((e != PSF1_SEPARATOR) && (k < mapsize)) { |
1277 | + // find glyph in table |
1278 | + glyph = 0; |
1279 | + while ((glyph < j) && (ud->entries[glyph].unicode != e)) { |
1280 | + glyph++; |
1281 | + } |
1282 | + // write glyph to table for all chars |
1283 | + if (glyph < j) { // found |
1284 | + l = seq[i]; // code pointer |
1285 | + e = nextuni(ver, map, &l); |
1286 | + while(e != PSF1_STARTSEQ && l < mapsize) { |
1287 | + ud->entries[j].unicode=e; |
1288 | + ud->entries[j++].fontpos=ud->entries[glyph].fontpos; |
1289 | + e = nextuni(ver, map, &l); |
1290 | + } |
1291 | + } |
1292 | + e = nextuni(ver, map, &k); |
1293 | + } |
1294 | + } |
1295 | + i++; |
1296 | + } |
1297 | + if (seqlen > 0) { |
1298 | + // remove unfound glyphs if any |
1299 | + ud->entry_ct = j; |
1300 | + free(seq); |
1301 | + } |
1302 | +#endif |
1303 | +} |
1304 | + |
1305 | +/** |
1306 | + * Read PSF v1 and PSF v2 fonts to own font structure |
1307 | + */ |
1308 | +static void fb_readpsf(const char *filename) { |
1309 | + unsigned int len; |
1310 | + int maplen; |
1311 | + uint8_t *buf; |
1312 | + struct psf1_header *psf1; |
1313 | + struct psf2_header *psf2; |
1314 | + |
1315 | + if (G.font != NULL) fb_freefont(); |
1316 | + len = 48*1024; // can't be larger |
1317 | + buf = xmalloc_open_zipped_read_close(filename, &len); |
1318 | + if (buf == NULL) { |
1319 | + bb_simple_perror_msg_and_die(filename); |
1320 | + } |
1321 | + if (len < 1024) { |
1322 | + goto badfmt; |
1323 | + } |
1324 | + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont)); |
1325 | + GF.mem1 = buf; |
1326 | + psf1 = (struct psf1_header *)buf; |
1327 | + psf2 = (struct psf2_header *)buf; |
1328 | + if ((psf1->magic == PSF1_MAGIC) && (psf1->mode <= PSF1_MAXMODE)) { |
1329 | + GF.glyphs = &(buf[sizeof(struct psf1_header)]); |
1330 | + GF.charsize = psf1->charsize; |
1331 | + GF.height = GF.charsize; |
1332 | + GF.glyphcount = ((psf1->mode & PSF1_MODE512) ? 512 : 256); |
1333 | + GF.width = 8; |
1334 | + maplen = len - sizeof(struct psf1_header) - |
1335 | + (GF.charsize * GF.glyphcount); |
1336 | + if ((maplen > 0) && ((psf1->mode & PSF1_MODEHASTAB) != 0)) { |
1337 | + convertmap(1,&(buf[len - maplen]),maplen,&(GF.ud)); |
1338 | + } else { |
1339 | + if (maplen < 0) goto badfmt; |
1340 | + } |
1341 | + } else if ((psf2->magic == PSF2_MAGIC) && |
1342 | + (psf2->version <= PSF2_MAXVERSION)) { |
1343 | + GF.glyphs=&(buf[psf2->headersize]); |
1344 | + GF.height = psf2->height; |
1345 | + GF.width = psf2->width; |
1346 | + GF.glyphcount = psf2->length; |
1347 | + GF.charsize = psf2->charsize; |
1348 | + maplen = len - psf2->headersize - |
1349 | + (GF.charsize * GF.glyphcount); |
1350 | + if ((maplen > 0) && ((psf2->flags & PSF2_HAS_UNICODE_TABLE) != 0)) { |
1351 | + convertmap(2,&(buf[len - maplen]),maplen,&(GF.ud)); |
1352 | + } else { |
1353 | + if (maplen < 0) goto badfmt; |
1354 | + } |
1355 | + } else { |
1356 | + goto badfmt; |
1357 | + } |
1358 | + GF.rowbytes = GF.charsize / GF.height; |
1359 | + |
1360 | + return; |
1361 | +badfmt: |
1362 | + if (G.font) fb_freefont(); |
1363 | + bb_error_msg_and_die("Cannot read file %s - unrecognized format\n",filename); |
1364 | +} |
1365 | +#endif // FONTLOAD |
1366 | +#endif // TEXT |
1367 | + |
1368 | +/** |
1369 | * Parse configuration file |
1370 | * \param *cfg_filename name of the configuration file |
1371 | */ |
1372 | @@ -347,6 +1200,9 @@ |
1373 | "BAR_WIDTH\0" "BAR_HEIGHT\0" |
1374 | "BAR_LEFT\0" "BAR_TOP\0" |
1375 | "BAR_R\0" "BAR_G\0" "BAR_B\0" |
1376 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
1377 | + "TEXT_LEFT\0" "TEXT_TOP\0" "TEXT_R\0" "TEXT_G\0" "TEXT_B\0" "TEXT_SIZE\0" |
1378 | +#endif |
1379 | #if DEBUG |
1380 | "DEBUG\0" |
1381 | #endif |
1382 | @@ -354,15 +1210,15 @@ |
1383 | char *token[2]; |
1384 | parser_t *parser = config_open2(cfg_filename, xfopen_stdin); |
1385 | while (config_read(parser, token, 2, 2, "#=", |
1386 | - (PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) { |
1387 | + (PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) { |
1388 | unsigned val = xatoi_positive(token[1]); |
1389 | int i = index_in_strings(param_names, token[0]); |
1390 | if (i < 0) |
1391 | bb_error_msg_and_die("syntax error: %s", token[0]); |
1392 | - if (i >= 0 && i < 7) |
1393 | + if (i >= 0 && i < FBCFGVALS) |
1394 | G.ns[i] = val; |
1395 | #if DEBUG |
1396 | - if (i == 7) { |
1397 | + if (i == FBCFGVALS) { |
1398 | G.bdebug_messages = val; |
1399 | if (G.bdebug_messages) |
1400 | G.logfile_fd = xfopen_for_write("/tmp/fbsplash.log"); |
1401 | @@ -376,11 +1232,24 @@ |
1402 | int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1403 | int fbsplash_main(int argc UNUSED_PARAM, char **argv) |
1404 | { |
1405 | +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD |
1406 | + const char *fontmap_filename = NULL; |
1407 | +#endif |
1408 | const char *fb_device, *cfg_filename, *fifo_filename; |
1409 | - FILE *fp = fp; // for compiler |
1410 | - char *num_buf; |
1411 | - unsigned num; |
1412 | + char num_buf[512]; |
1413 | + int num; |
1414 | bool bCursorOff; |
1415 | + struct timeval tim; |
1416 | + fd_set rdfds; |
1417 | + FILE *fp=fp; |
1418 | + int bounce_x=0; |
1419 | +#if ENABLE_FEATURE_FBSPLASH_SPRITES |
1420 | + int anim_x,anim_y, /* position of sprite or animation */ |
1421 | + anim_n,anim_m, /* min sprite, max sprite for animation */ |
1422 | + anim_p=0, /* actual sprite */ |
1423 | + anim_t=0,anim_now=0; /* time between steps */ |
1424 | + struct sprite *spa=NULL; |
1425 | +#endif |
1426 | |
1427 | INIT_G(); |
1428 | |
1429 | @@ -388,9 +1257,19 @@ |
1430 | fb_device = "/dev/fb0"; |
1431 | cfg_filename = NULL; |
1432 | fifo_filename = NULL; |
1433 | + |
1434 | +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD |
1435 | + bCursorOff = 1 & getopt32(argv, "cs:d:i:f:m:", |
1436 | + &G.image_filename, &fb_device, &cfg_filename, &fifo_filename, &fontmap_filename); |
1437 | + |
1438 | + if (fontmap_filename) fb_readpsf(fontmap_filename); |
1439 | +#else |
1440 | bCursorOff = 1 & getopt32(argv, "cs:d:i:f:", |
1441 | &G.image_filename, &fb_device, &cfg_filename, &fifo_filename); |
1442 | - |
1443 | +#endif |
1444 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
1445 | + if (G.font==NULL) fb_readvgafont(); |
1446 | +#endif |
1447 | // parse configuration file |
1448 | if (cfg_filename) |
1449 | init(cfg_filename); |
1450 | @@ -406,8 +1285,20 @@ |
1451 | full_write(STDOUT_FILENO, "\033[?25l", 6); |
1452 | } |
1453 | |
1454 | + if (fifo_filename != NULL) { |
1455 | + G.spb2 = fb_newsprite(G.nbar_width, G.nbar_height, -1, -1); |
1456 | + } |
1457 | + |
1458 | fb_drawimage(); |
1459 | |
1460 | + G.spb1 = fb_newsprite(G.nbar_width, G.nbar_height, G.nbar_posx, G.nbar_posy); |
1461 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
1462 | + if (G.font != NULL) |
1463 | + G.spt = fb_newsprite(G.scr_var.xres - G.text_posx, |
1464 | + GF.height * G.text_size, |
1465 | + G.text_posx, G.text_posy); |
1466 | +#endif |
1467 | + |
1468 | if (!fifo_filename) |
1469 | return EXIT_SUCCESS; |
1470 | |
1471 | @@ -424,31 +1315,137 @@ |
1472 | // when last writer closes input end. |
1473 | // The simplest way is to open fifo for writing too |
1474 | // and become an additional writer :) |
1475 | - open(fifo_filename, O_WRONLY); // errors are ignored |
1476 | + open(fifo_filename, O_WRONLY | O_NDELAY); // errors are ignored |
1477 | } |
1478 | |
1479 | - fb_drawprogressbar(0); |
1480 | // Block on read, waiting for some input. |
1481 | // Use of <stdio.h> style I/O allows to correctly |
1482 | // handle a case when we have many buffered lines |
1483 | // already in the pipe |
1484 | - while ((num_buf = xmalloc_fgetline(fp)) != NULL) { |
1485 | - if (strncmp(num_buf, "exit", 4) == 0) { |
1486 | - DEBUG_MESSAGE("exit"); |
1487 | - break; |
1488 | - } |
1489 | - num = atoi(num_buf); |
1490 | - if (isdigit(num_buf[0]) && (num <= 100)) { |
1491 | + // select and fgets work just in time only in nobuf mode |
1492 | + setvbuf(fp, NULL, _IONBF, 0); |
1493 | + tim.tv_sec = 0; |
1494 | + tim.tv_usec = 100000; |
1495 | + while (1) { |
1496 | + FD_ZERO(&rdfds); |
1497 | + FD_SET(fileno(fp),&rdfds); |
1498 | + if ((num=select(fileno(fp) + 1,&rdfds,NULL,NULL,&tim))==-1) |
1499 | + break; // select error |
1500 | + if (num != 0 && fgets(num_buf,sizeof(num_buf) - 1,fp) != NULL) { |
1501 | + num_buf[sizeof(num_buf) - 1]=0; |
1502 | + num=strlen(num_buf) - 1; |
1503 | + if (num >= 0 && num_buf[num]==10) num_buf[num]=0; |
1504 | + if (strncmp(num_buf, "exit", 4) == 0) { |
1505 | + DEBUG_MESSAGE("exit"); |
1506 | + break; |
1507 | + } else if (strncmp(num_buf, "bounce", 6) == 0) { |
1508 | + bounce_x = 0; |
1509 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
1510 | + } else if (strncmp(num_buf, "write:", 6) == 0) { |
1511 | + if (G.font!=NULL) fb_drawstring(num_buf + 6); |
1512 | + DEBUG_MESSAGE(num_buf); |
1513 | +#endif |
1514 | +#if ENABLE_FEATURE_FBSPLASH_SPRITES |
1515 | + } else if (strncmp(num_buf, "load:", 5) == 0) { |
1516 | + if (spa) { |
1517 | + fb_putanim(anim_x,anim_y,0,spa); // hide old |
1518 | + free(spa); |
1519 | + spa=NULL; |
1520 | + } |
1521 | + if (sscanf(&(num_buf[5]),"%d:%d:", |
1522 | + &anim_x,&anim_y) == 2) { |
1523 | + // skip x:y |
1524 | + for (num=5;num_buf[num] != ':';) num++; |
1525 | + for (num++;num_buf[num] != ':';) num++; |
1526 | + spa=fb_loadsprites(&(num_buf[num + 1]),anim_x,anim_y); |
1527 | + anim_t = anim_now = 0; // stop animation |
1528 | + } |
1529 | + } else if (strncmp(num_buf, "sprite:", 7) == 0) { |
1530 | + if (spa != NULL) { |
1531 | + // "sprite:n" |
1532 | + anim_t = anim_now = 0; // stop animation |
1533 | + anim_p = atoi(&(num_buf[7])); |
1534 | + if (anim_p >= 0) { |
1535 | + fb_putanim(anim_x,anim_y,anim_p,spa); |
1536 | + } |
1537 | + } |
1538 | + } else if (strncmp(num_buf, "anime:", 6) == 0) { |
1539 | + if (spa != NULL) { |
1540 | + // "anime:n:m:t" |
1541 | + if ((sscanf(&(num_buf[6]),"%d:%d:%d", |
1542 | + &anim_n,&anim_m,&anim_t) == 3) && |
1543 | + (anim_n >= 0) && (anim_m >= 0)) { |
1544 | + anim_p = anim_n; // first frame |
1545 | + fb_putanim(anim_x,anim_y,anim_p,spa); |
1546 | + anim_now = anim_t; // next sprite after time t |
1547 | + } else { |
1548 | + anim_now = anim_t = 0; // stop animation |
1549 | + } |
1550 | + } |
1551 | +#endif |
1552 | + } else { |
1553 | + num = atoi(num_buf); |
1554 | + if ((isdigit(num_buf[0]) || (num_buf[0]=='-')) && |
1555 | + (num >= -100 && num <= 100)) { |
1556 | #if DEBUG |
1557 | - DEBUG_MESSAGE(itoa(num)); |
1558 | + char strVal[10]; |
1559 | + sprintf(strVal, "%d", num); |
1560 | + DEBUG_MESSAGE(strVal); |
1561 | +#endif |
1562 | + if (num < 0) { |
1563 | + fb_drawnbar(-1 * num,100); |
1564 | + } else { |
1565 | + fb_drawnbar(0,num); |
1566 | + } |
1567 | + bounce_x = -1; // stop bounce |
1568 | + } |
1569 | + } |
1570 | + } else { |
1571 | + if (fp == stdin && feof(fp)) break; // stdin closed END |
1572 | + } |
1573 | + if (tim.tv_usec == 0) { // timeout - anime |
1574 | + tim.tv_usec = 100000; |
1575 | + if (bounce_x >= 0) { |
1576 | + bounce_x += 5; |
1577 | + if (bounce_x > 160) bounce_x = 0; |
1578 | + if (bounce_x > 80) |
1579 | + fb_drawnbar(160 - bounce_x,180 - bounce_x); |
1580 | + else |
1581 | + fb_drawnbar(bounce_x, bounce_x + 20); |
1582 | + } |
1583 | +#if ENABLE_FEATURE_FBSPLASH_SPRITES |
1584 | + if (spa != NULL && anim_t != 0) { |
1585 | + --anim_now; |
1586 | + if (anim_now <= 0) { |
1587 | + anim_now = anim_t; // wait |
1588 | + if (anim_n < anim_m) { |
1589 | + anim_p++; |
1590 | + if (anim_p > anim_m) anim_p = anim_n; |
1591 | + } else { |
1592 | + anim_p--; |
1593 | + if (anim_p < anim_m) anim_p = anim_n; |
1594 | + } |
1595 | + fb_putanim(anim_x,anim_y,anim_p,spa); |
1596 | + } |
1597 | + } |
1598 | #endif |
1599 | - fb_drawprogressbar(num); |
1600 | } |
1601 | - free(num_buf); |
1602 | } |
1603 | - |
1604 | + if (G.spb1 != NULL) free(G.spb1); |
1605 | + G.spb1 = NULL; |
1606 | + if (G.spb2 != NULL) free(G.spb2); |
1607 | + G.spb2 = NULL; |
1608 | +#if ENABLE_FEATURE_FBSPLASH_TEXT |
1609 | + if (G.font != NULL) fb_freefont(); |
1610 | + if (G.spt != NULL) free(G.spt); |
1611 | + G.spt = NULL; |
1612 | +#endif |
1613 | +#if ENABLE_FEATURE_FBSPLASH_SPRITES |
1614 | + if (spa != NULL) free(spa); |
1615 | +#endif |
1616 | if (bCursorOff) // restore cursor |
1617 | full_write(STDOUT_FILENO, "\033[?25h", 6); |
1618 | |
1619 | return EXIT_SUCCESS; |
1620 | } |
1621 | +#endif |
1622 | diff -Naur busybox-1.19.0/miscutils/fbsplash.cfg busybox-1.19.0-magellan/miscutils/fbsplash.cfg |
1623 | --- busybox-1.19.0/miscutils/fbsplash.cfg 2011-08-11 02:23:58.000000000 +0200 |
1624 | +++ busybox-1.19.0-magellan/miscutils/fbsplash.cfg 2011-09-05 21:00:28.000000000 +0200 |
1625 | @@ -7,3 +7,13 @@ |
1626 | BAR_R=80 |
1627 | BAR_G=80 |
1628 | BAR_B=130 |
1629 | +# the below settings are active only if you enable the option FBSPLASH_TEXT_RENDERING |
1630 | +# text position |
1631 | +#TEXT_LEFT=100 |
1632 | +#TEXT_TOP=350 |
1633 | +## text color |
1634 | +#TEXT_R=80 |
1635 | +#TEXT_G=80 |
1636 | +#TEXT_B=130 |
1637 | +## text size (1 to 4) |
1638 | +#TEXT_SIZE=2 |