Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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