Magellan Linux

Contents of /trunk/busybox/patches/busybox-1.19.0-fbsplash-tykef-1.0.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1517 - (show annotations) (download)
Mon Sep 5 21:30:02 2011 UTC (12 years, 8 months 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