[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    Re: fbsplash enhancement - text rendering, animations...
From:       Denys Vlasenko <vda.linux () googlemail ! com>
Date:       2009-09-24 0:03:50
Message-ID: 200909240203.50418.vda.linux () googlemail ! com
[Download RAW message or body]

On Thursday 03 September 2009 20:47, Michele Sanges wrote:
> George,
> 
> as you have seen, months ago I repeatedly sent to the list my text 
> rendering patch, but nobody has taken it in consideration.

I looked at it. I started working on making it clean enough
for inclusion, but the work stalled at a certain point.
The attached patch is where I stopped.

> Anyway, by means the file fbsplash.cfg file it's possible to specify the 
> position, the color and the size of the text displayed, but I agree with 
> you that hardcoded fonts allow very restrictive usages.

Position and color in a config file is too restrictive too.
it's not unexpected that people would ant to output text
in different spots...

The command can optionally include it too, before actual
test to display.

> For this reason  
> I hoped in a feedback from the list, but unfortunately is not arrived.

I do not want to sound negative, but I do not know how to say it
without doing so. Your code needs much work before it looks
more or less ok. That, plus my laziness in attempts to reach
that stage, made this patch to fall through the cracks.

I apologize. I had to talk to you more and sooner.

--
vda

["fbsplash3.patch" (text/x-diff)]

diff -d -urpN busybox.2/include/usage.h busybox.3/include/usage.h
--- busybox.2/include/usage.h	2009-02-15 12:35:26.000000000 +0100
+++ busybox.3/include/usage.h	2009-02-15 16:58:15.000000000 +0100
@@ -144,7 +144,7 @@
        "bar"

 #define fbsplash_trivial_usage \
-       "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]"
+       "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD] [-m FONTMAPFILE]"
 #define fbsplash_full_usage "\n\n" \
        "Options:\n" \
      "\n	-s	Image" \
@@ -153,8 +153,10 @@
      "\n	-i	Config file (var=value):" \
      "\n			BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \
      "\n			BAR_R,BAR_G,BAR_B" \
+     "\n			TEXT_LEFT,TEXT_TOP,TEXT_R,TEXT_G,TEXT_B,TEXT_SIZE" \
      "\n	-f	Control pipe (else exit after drawing image)" \
-     "\n			commands: 'NN' (% for progress bar) or 'exit'" \
+     "\n	-m	Font map file" \
+     "\n			commands: 'NN' (% for progress bar), 'write:string to print' or 'exit'"

 #define brctl_trivial_usage \
        "COMMAND [BRIDGE [INTERFACE]]"
diff -d -urpN busybox.2/miscutils/Config.in busybox.3/miscutils/Config.in
--- busybox.2/miscutils/Config.in	2009-02-15 12:35:26.000000000 +0100
+++ busybox.3/miscutils/Config.in	2009-02-15 23:44:26.000000000 +0100
@@ -257,6 +257,24 @@ config IONICE
 	  Set/set program io scheduling class and priority
 	  Requires kernel >= 2.6.13

+config FBSPLASH_TEXT_RENDERING
+	bool "Text rendering"
+	default n
+	depends on FBSPLASH
+	help
+	  This option adds the ability to print text messages on the
+	  image displayed by the fbsplash applet.
+	  - command for fifo:
+	    "write:string to print" - print the string after the word "write:"
+
+config FBSPLASH_DYNAMIC_FONT
+	bool "Font loading"
+	default n
+	depends on FBSPLASH_TEXT_RENDERING
+	help
+	  The font map is dynamically loaded from a file.
+	  Adds about 700 byte.
+
 config INOTIFYD
 	bool "inotifyd"
 	default n
diff -d -urpN busybox.2/miscutils/fbsplash.c busybox.3/miscutils/fbsplash.c
--- busybox.2/miscutils/fbsplash.c	2009-02-15 18:28:58.000000000 +0100
+++ busybox.3/miscutils/fbsplash.c	2009-02-16 00:17:57.000000000 +0100
@@ -13,11 +13,13 @@
  *      -s path_to_image_file (can be "-" for stdin)
  *      -i path_to_cfg_file
  *      -f path_to_fifo (can be "-" for stdin)
+ *      -m font map file
  * - if you want to run it only in presence of a kernel parameter
  *   (for example fbsplash=on), use:
  *   grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params]
  * - commands for fifo:
  *   "NN" (ASCII decimal number) - percentage to show on progress bar.
+ *   "write:string to print" - print the string after the word "write:"
  *   "exit" (or just close fifo) - well you guessed it.
  */

@@ -29,16 +31,125 @@

 #define BYTES_PER_PIXEL 2

-typedef unsigned short DATA;
+typedef uint16_t DATA;
+
+#if ENABLE_FBSPLASH_TEXT_RENDERING
+
+#define NUM_CHARS (127 - 32)
+#define SCANLINES 12
+
+#if !ENABLE_FBSPLASH_DYNAMIC_FONT
+static const char fontmap[][SCANLINES] = {
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space (32)
+{0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x80,0x00,0x00,0x00,0x00}, // ! (33)
+{0x00,0xA0,0xA0,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // " (34)
+{0x00,0x24,0x24,0x7E,0x28,0xFC,0x48,0x48,0x00,0x00,0x00,0x00}, // # (35)
+{0x00,0x20,0x78,0xA0,0x60,0x30,0x28,0xF0,0x20,0x20,0x00,0x00}, // $ (36)
+{0x00,0x64,0x98,0x98,0x7E,0x19,0x19,0x26,0x00,0x00,0x00,0x00}, // % (37)
+{0x00,0x60,0x90,0x90,0x68,0x90,0x98,0x64,0x00,0x00,0x00,0x00}, // & (38)
+{0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ' (39)
+{0x00,0x20,0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x40,0x20,0x00}, // ( (40)
+{0x00,0x80,0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x40,0x80,0x00}, // ) (41)
+{0x00,0x20,0xA8,0x70,0xA8,0x20,0x00,0x00,0x00,0x00,0x00,0x00}, // * (42)
+{0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00,0x00,0x00,0x00}, // + (43)
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80,0x00}, // , (44)
+{0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00}, // - (45)
+{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00}, // . (46)
+{0x00,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x80,0x80,0x00,0x00}, // / (47)
+{0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x60,0x00,0x00,0x00,0x00}, // 0 (48)
+{0x00,0x40,0xC0,0x40,0x40,0x40,0x40,0xE0,0x00,0x00,0x00,0x00}, // 1 (49)
+{0x00,0xE0,0x10,0x10,0x20,0x40,0x80,0xF0,0x00,0x00,0x00,0x00}, // 2 (50)
+{0x00,0xE0,0x10,0x10,0x60,0x10,0x10,0xE0,0x00,0x00,0x00,0x00}, // 3 (51)
+{0x00,0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00,0x00,0x00,0x00}, // 4 (52)
+{0x00,0xF0,0x80,0x80,0xE0,0x10,0x10,0xE0,0x00,0x00,0x00,0x00}, // 5 (53)
+{0x00,0x60,0x80,0x80,0xE0,0x90,0x90,0x60,0x00,0x00,0x00,0x00}, // 6 (54)
+{0x00,0xF0,0x10,0x20,0x20,0x40,0x40,0x80,0x00,0x00,0x00,0x00}, // 7 (55)
+{0x00,0x60,0x90,0x90,0x60,0x90,0x90,0x60,0x00,0x00,0x00,0x00}, // 8 (56)
+{0x00,0x60,0x90,0x90,0x70,0x10,0x10,0x60,0x00,0x00,0x00,0x00}, // 9 (57)
+{0x00,0x00,0x00,0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x00}, // : (58)
+{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x40,0x40,0x80}, // ; (59)
+{0x00,0x00,0x00,0x08,0x70,0x80,0x70,0x08,0x00,0x00,0x00,0x00}, // < (60)
+{0x00,0x00,0x00,0x00,0xFC,0x00,0xFC,0x00,0x00,0x00,0x00,0x00}, // = (61)
+{0x00,0x00,0x00,0x80,0x70,0x08,0x70,0x80,0x00,0x00,0x00,0x00}, // > (62)
+{0x00,0xE0,0x10,0x10,0x20,0x40,0x00,0x40,0x00,0x00,0x00,0x00}, // ? (63)
+{0x00,0x38,0x44,0x9A,0xAA,0xAA,0x9C,0x40,0x38,0x00,0x00,0x00}, // @ (64)
+{0x00,0x30,0x30,0x48,0x48,0xFC,0x84,0x84,0x00,0x00,0x00,0x00}, // A (65)
+{0x00,0xE0,0x90,0x90,0xF0,0x88,0x88,0xF0,0x00,0x00,0x00,0x00}, // B (66)
+{0x00,0x38,0x44,0x80,0x80,0x80,0x44,0x38,0x00,0x00,0x00,0x00}, // C (67)
+{0x00,0xF0,0x88,0x84,0x84,0x84,0x88,0xF0,0x00,0x00,0x00,0x00}, // D (68)
+{0x00,0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,0x00,0x00,0x00}, // E (69)
+{0x00,0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00,0x00,0x00,0x00}, // F (70)
+{0x00,0x38,0x44,0x80,0x9C,0x84,0x44,0x3C,0x00,0x00,0x00,0x00}, // G (71)
+{0x00,0x84,0x84,0x84,0xFC,0x84,0x84,0x84,0x00,0x00,0x00,0x00}, // H (72)
+{0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0xE0,0x00,0x00,0x00,0x00}, // I (73)
+{0x00,0x60,0x20,0x20,0x20,0x20,0x20,0xC0,0x00,0x00,0x00,0x00}, // J (74)
+{0x00,0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00,0x00,0x00,0x00}, // K (75)
+{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xF0,0x00,0x00,0x00,0x00}, // L (76)
+{0x00,0xC6,0xC6,0xAA,0xAA,0x92,0x92,0x82,0x00,0x00,0x00,0x00}, // M (77)
+{0x00,0x84,0xC4,0xA4,0x94,0x8C,0x84,0x84,0x00,0x00,0x00,0x00}, // N (78)
+{0x00,0x38,0x44,0x82,0x82,0x82,0x44,0x38,0x00,0x00,0x00,0x00}, // O (79)
+{0x00,0xF0,0x88,0x88,0x88,0xF0,0x80,0x80,0x00,0x00,0x00,0x00}, // P (80)
+{0x00,0x38,0x44,0x82,0x82,0x82,0x44,0x38,0x08,0x06,0x00,0x00}, // Q (81)
+{0x00,0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00,0x00,0x00,0x00}, // R (82)
+{0x00,0x78,0x80,0x80,0x70,0x08,0x08,0xF0,0x00,0x00,0x00,0x00}, // S (83)
+{0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x00}, // T (84)
+{0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00,0x00,0x00}, // U (85)
+{0x00,0x84,0x84,0x84,0x48,0x48,0x30,0x30,0x00,0x00,0x00,0x00}, // V (86)
+{0x00,0x92,0x92,0xAA,0xAA,0xAA,0x44,0x44,0x00,0x00,0x00,0x00}, // W (87)
+{0x00,0x90,0x90,0x60,0x60,0x60,0x90,0x90,0x00,0x00,0x00,0x00}, // X (88)
+{0x00,0x88,0x50,0x50,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x00}, // Y (89)
+{0x00,0xF0,0x10,0x20,0x40,0x40,0x80,0xF0,0x00,0x00,0x00,0x00}, // Z (90)
+{0x00,0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x00}, // [ (91)
+{0x00,0x80,0x80,0x40,0x40,0x40,0x40,0x40,0x20,0x20,0x00,0x00}, // \ (92)
+{0x00,0xC0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xC0,0x00}, // ] (93)
+{0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^ (94)
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00}, // _ (95)
+{0x00,0x80,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ` (96)
+{0x00,0x00,0x00,0x60,0x10,0x70,0x90,0x70,0x00,0x00,0x00,0x00}, // a (97)
+{0x80,0x80,0x80,0xE0,0x90,0x90,0x90,0xE0,0x00,0x00,0x00,0x00}, // b (98)
+{0x00,0x00,0x00,0x60,0x80,0x80,0x80,0x60,0x00,0x00,0x00,0x00}, // c (99)
+{0x10,0x10,0x10,0x70,0x90,0x90,0x90,0x70,0x00,0x00,0x00,0x00}, // d (100)
+{0x00,0x00,0x00,0x60,0x90,0xF0,0x80,0x70,0x00,0x00,0x00,0x00}, // e (101)
+{0x60,0x80,0x80,0xE0,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00}, // f (102)
+{0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x70,0x10,0x60,0x00,0x00}, // g (103)
+{0x80,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0x00}, // h (104)
+{0x00,0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00}, // i (105)
+{0x00,0x40,0x00,0xC0,0x40,0x40,0x40,0x40,0x40,0x80,0x00,0x00}, // j (106)
+{0x80,0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00,0x00,0x00,0x00}, // k (107)
+{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00}, // l (108)
+{0x00,0x00,0x00,0xEC,0x92,0x92,0x92,0x92,0x00,0x00,0x00,0x00}, // m (109)
+{0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0x00}, // n (110)
+{0x00,0x00,0x00,0x60,0x90,0x90,0x90,0x60,0x00,0x00,0x00,0x00}, // o (111)
+{0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0xE0,0x80,0x80,0x00,0x00}, // p (112)
+{0x00,0x00,0x00,0x70,0x90,0x90,0x90,0x70,0x10,0x10,0x00,0x00}, // q (113)
+{0x00,0x00,0x00,0xA0,0xC0,0x80,0x80,0x80,0x00,0x00,0x00,0x00}, // r (114)
+{0x00,0x00,0x00,0xE0,0x80,0x40,0x20,0xE0,0x00,0x00,0x00,0x00}, // s (115)
+{0x00,0x00,0x80,0xC0,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0x00}, // t (116)
+{0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x70,0x00,0x00,0x00,0x00}, // u (117)
+{0x00,0x00,0x00,0x88,0x50,0x50,0x50,0x20,0x00,0x00,0x00,0x00}, // v (118)
+{0x00,0x00,0x00,0x92,0x92,0xAA,0x6C,0x44,0x00,0x00,0x00,0x00}, // w (119)
+{0x00,0x00,0x00,0xA0,0x40,0x40,0x40,0xA0,0x00,0x00,0x00,0x00}, // x (120)
+{0x00,0x00,0x00,0x88,0x50,0x50,0x50,0x20,0x20,0x40,0x00,0x00}, // y (121)
+{0x00,0x00,0x00,0xE0,0x20,0x40,0x80,0xE0,0x00,0x00,0x00,0x00}, // z (122)
+{0x00,0x20,0x40,0x40,0x40,0x40,0x80,0x40,0x40,0x40,0x20,0x00}, // { (123)
+{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00}, // | (124)
+{0x00,0x80,0x40,0x40,0x40,0x40,0x20,0x40,0x40,0x40,0x80,0x00}, // } (125)
+{0x00,0x60,0x90,0x90,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00}  // ~ (126)
+};
+#endif
+#endif

 struct globals {
 #if DEBUG
-	bool bdebug_messages;	// enable/disable logging
-	FILE *logfile_fd;	// log file
+	FILE *logfile_fp;
 #endif
-	unsigned char *addr;	// pointer to framebuffer memory
-	unsigned ns[7];		// n-parameters
+#if ENABLE_FBSPLASH_DYNAMIC_FONT
+	char (*fontmap)[SCANLINES];
+#endif
+	unsigned char *addr; // pointer to framebuffer memory
+	unsigned textpix;
 	const char *image_filename;
+	unsigned ns[13]; // n-parameters
 	struct fb_var_screeninfo scr_var;
 	struct fb_fix_screeninfo scr_fix;
 };
@@ -47,6 +158,10 @@ struct globals {
 	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 } while (0)

+#if ENABLE_FBSPLASH_DYNAMIC_FONT
+# define fontmap	(G.fontmap)
+#endif
+
 #define nbar_width	ns[0]	// progress bar width
 #define nbar_height	ns[1]	// progress bar height
 #define nbar_posx	ns[2]	// progress bar horizontal position
@@ -54,25 +169,51 @@ struct globals {
 #define nbar_colr	ns[4]	// progress bar color red component
 #define nbar_colg	ns[5]	// progress bar color green component
 #define nbar_colb	ns[6]	// progress bar color blue component
+#define text_posx	ns[7]	// text horizontal position
+#define text_posy	ns[8]	// text vertical position
+#define text_colr	ns[9]	// text color red component
+#define text_colg	ns[10]	// text color green component
+#define text_colb	ns[11]	// text color blue component
+#define text_scale	ns[12]
+#define bdebug_messages	ns[13]
+
+static const char const param_names[] ALIGN1 +	"BAR_WIDTH\0" "BAR_HEIGHT\0"
+	"BAR_LEFT\0" "BAR_TOP\0"
+	"BAR_R\0" "BAR_G\0" "BAR_B\0"
+	"TEXT_LEFT\0" "TEXT_TOP\0"
+	"TEXT_R\0" "TEXT_G\0" "TEXT_B\0"
+	"TEXT_SIZE\0"
+#if DEBUG
+	"DEBUG\0"
+#endif
+	;

 #if DEBUG
-#define DEBUG_MESSAGE(strMessage, args...) \
+# define DEBUG_MESSAGE(strMessage, args...) \
 	if (G.bdebug_messages) { \
-		fprintf(G.logfile_fd, "[%s][%s] - %s\n", \
+		fprintf(G.logfile_fp, "[%s][%s] - %s\n", \
 		__FILE__, __FUNCTION__, strMessage);	\
 	}
 #else
-#define DEBUG_MESSAGE(...) ((void)0)
+# define DEBUG_MESSAGE(...) ((void)0)
 #endif


-/**
- *	Open and initialize the framebuffer device
- * \param *strfb_device pointer to framebuffer device
+static unsigned _24to16(unsigned r, unsigned g, unsigned b)
+{
+	return ((r << 8) & 0xf800)
+	     | ((g << 3) & 0x07e0)
+	     | ((b >> 3));
+}
+
+
+/*
+ * Open and initialize the framebuffer device
  */
-static void fb_open(const char *strfb_device)
+static void fb_open(const char *fb_device)
 {
-	int fbfd = xopen(strfb_device, O_RDWR);
+	int fbfd = xopen(fb_device, O_RDWR);

 	// framebuffer properties
 	xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var);
@@ -84,7 +225,7 @@ static void fb_open(const char *strfb_de
 	// map the device in memory
 	G.addr = mmap(NULL,
 			G.scr_var.xres * G.scr_var.yres
-			* BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/ ,
+			* BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/,
 			PROT_WRITE, MAP_SHARED, fbfd, 0);
 	if (G.addr == MAP_FAILED)
 		bb_perror_msg_and_die("mmap");
@@ -92,26 +233,22 @@ static void fb_open(const char *strfb_de
 }


-/**
- *	Draw hollow rectangle on framebuffer
+/*
+ * Draw hollow rectangle
  */
 static void fb_drawrectangle(void)
 {
 	int cnt;
-	DATA thispix;
 	DATA *ptr1, *ptr2;
-	unsigned char nred = G.nbar_colr/2;
-	unsigned char ngreen =  G.nbar_colg/2;
-	unsigned char nblue = G.nbar_colb/2;
+	DATA *ptr1save;
+	DATA thispix;

-	nred   >>= 3;  // 5-bit red
-	ngreen >>= 2;  // 6-bit green
-	nblue  >>= 3;  // 5-bit blue
-	thispix = nblue + (ngreen << 5) + (nred << (5+6));
+	thispix = _24to16(G.nbar_colr/2, G.nbar_colg/2, G.nbar_colb/2);

 	// horizontal lines
 	ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * \
                BYTES_PER_PIXEL);
-	ptr2 = (DATA*)(G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + \
G.nbar_posx) * BYTES_PER_PIXEL); +	ptr1save = ptr1;
+	ptr2 = ptr1 + (G.nbar_height - 1) * G.scr_var.xres;
 	cnt = G.nbar_width - 1;
 	do {
 		*ptr1++ = thispix;
@@ -119,8 +256,8 @@ static void fb_drawrectangle(void)
 	} while (--cnt >= 0);

 	// vertical lines
-	ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * \
                BYTES_PER_PIXEL);
-	ptr2 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width \
- 1) * BYTES_PER_PIXEL); +	ptr2 = ptr1 - 1;
+	ptr1 = ptr1save;
 	cnt = G.nbar_height - 1;
 	do {
 		*ptr1 = thispix; ptr1 += G.scr_var.xres;
@@ -129,24 +266,17 @@ static void fb_drawrectangle(void)
 }


-/**
- *	Draw filled rectangle on framebuffer
- * \param nx1pos,ny1pos upper left position
- * \param nx2pos,ny2pos down right position
- * \param nred,ngreen,nblue rgb color
+/*
+ * Draw filled rectangle
+ * nx1pos,ny1pos upper left position
+ * nx2pos,ny2pos down right position
+ * thispix       pixel value
  */
-static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
-	unsigned char nred, unsigned char ngreen, unsigned char nblue)
+static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, \
unsigned thispix)  {
 	int cnt1, cnt2, nypos;
-	DATA thispix;
 	DATA *ptr;

-	nred   >>= 3;  // 5-bit red
-	ngreen >>= 2;  // 6-bit green
-	nblue  >>= 3;  // 5-bit blue
-	thispix = nblue + (ngreen << 5) + (nred << (5+6));
-
 	cnt1 = ny2pos - ny1pos;
 	nypos = ny1pos;
 	do {
@@ -161,9 +291,8 @@ static void fb_drawfullrectangle(int nx1
 }


-/**
- *	Draw a progress bar on framebuffer
- * \param percent percentage of loading
+/*
+ * Draw a progress bar on framebuffer
  */
 static void fb_drawprogressbar(unsigned percent)
 {
@@ -189,7 +318,7 @@ static void fb_drawprogressbar(unsigned
 	fb_drawfullrectangle(
 			left_x,	top_y,
 					left_x + width, top_y + height,
-			G.nbar_colr, G.nbar_colg, G.nbar_colb);
+			_24to16(G.nbar_colr, G.nbar_colg, G.nbar_colb));

 	if (percent > 0) {
 		// actual progress bar
@@ -203,7 +332,7 @@ static void fb_drawprogressbar(unsigned
 			unsigned gray_level = 100 + i*100/height;
 			fb_drawfullrectangle(
 					left_x, top_y, left_x + width, top_y,
-					gray_level, gray_level, gray_level);
+					_24to16(gray_level, gray_level, gray_level));
 			top_y++;
 			i--;
 		}
@@ -211,59 +340,78 @@ static void fb_drawprogressbar(unsigned
 }


-/**
- *	Draw image from PPM file
+/*
+ * Draw a PPM image
+ *
+ * h_pos  horizontal position from which draw the image.
+ * v_pos  vertical position from which draw the image.
+ * h_dim  horizontal dimension of the image section to draw.
+ * v_dim  vertical dimension of the image section to draw.
+ * With X_dim = -1, corresponding dimension is to the end of screen.
  */
-static void fb_drawimage(void)
+static void fb_drawimage(int h_pos, int v_pos, int h_dim, int v_dim)
 {
-	char head[256];
-	char s[80];
 	FILE *theme_file;
 	unsigned char *pixline;
-	unsigned i, j, width, height, line_size;
+	unsigned h_size, v_size, line_size;

-	memset(head, 0, sizeof(head));
 	theme_file = xfopen_stdin(G.image_filename);

-	// parse ppm header
+	// Read & parse ppm header. Example:
+	// P6
+	// # CREATOR: The GIMP's PNM Filter Version 1.0
+	// 640 480
+	// 255
+	// [binary data starts on this line]
 	while (1) {
+		unsigned max_color_val;
+		char head[256];
+		char s[80];
+
 		if (fgets(s, sizeof(s), theme_file) == NULL)
 			bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
-
 		if (s[0] == '#')
 			continue;
-
 		if (strlen(head) + strlen(s) >= sizeof(head))
 			bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
-
 		strcat(head, s);
-		if (head[0] != 'P' || head[1] != '6')
-			bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
-
-		// width, height, max_color_val
-		if (sscanf(head, "P6 %u %u %u", &width, &height, &i) == 3)
+//		if (head[0] != 'P' || head[1] != '6')
+//			bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
+		// Try to parse ("is it complete now?").
+		// NB: spaces in format may match '\n' too.
+		if (sscanf(head, "P6 %u %u %u", &h_size, &v_size, &max_color_val) == 3) {
+			if (max_color_val > 255) // we don't support 16bit color components
+				bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
 			break;
-// TODO: i must be <= 255!
+		}
 	}

-	line_size = width*3;
-	if (width > G.scr_var.xres)
-		width = G.scr_var.xres;
-	if (height > G.scr_var.yres)
-		height = G.scr_var.yres;
-
+	line_size = h_size * 3;
 	pixline = xmalloc(line_size);
-	for (j = 0; j < height; j++) {
-		unsigned char *pixel = pixline;
-		DATA *src = (DATA *)(G.addr + j * G.scr_fix.line_length);
+	// _Advance_ (not _set_, we need to account for the header)
+	// file position to v_pos's line.
+	fseek(theme_file, line_size * v_pos, SEEK_CUR);
+
+	// Starting from here, h_size/v_size mean "last h/v coord *on screen*"
+	if (v_dim != -1)
+//fixme: v_size must never grow here
+		v_size = v_pos + v_dim;
+	if (v_size > G.scr_var.yres)
+		v_size = G.scr_var.yres;
+	if (h_dim != -1)
+		h_size = h_pos + h_dim;
+	if (h_size > G.scr_var.xres)
+		h_size = G.scr_var.xres;
+
+	for (; v_pos < v_size; v_pos++) {
+		unsigned char *pixel = pixline + 3 * h_pos;
+		DATA *src = (DATA *)(G.addr + (v_pos * G.scr_var.xres + h_pos) * BYTES_PER_PIXEL);

 		if (fread(pixline, 1, line_size, theme_file) != line_size)
 			bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
-		for (i = 0; i < width; i++) {
+		for (; h_pos < h_size; h_pos++) {
 			unsigned thispix;
-			thispix = (((unsigned)pixel[0] << 8) & 0xf800)
-				| (((unsigned)pixel[1] << 3) & 0x07e0)
-				| (((unsigned)pixel[2] >> 3));
+			thispix = _24to16(pixel[0], pixel[1], pixel[2]);
 			*src++ = thispix;
 			pixel += 3;
 		}
@@ -273,20 +421,79 @@ static void fb_drawimage(void)
 }


-/**
- *	Parse configuration file
- * \param *cfg_filename name of the configuration file
+#if ENABLE_FBSPLASH_TEXT_RENDERING
+/*
+ * Draw single character
+ *
+ * h_pos  horizontal position
+ * v_pos  vertical position
+ * ch     character to draw
  */
-static void init(const char *cfg_filename)
+static void fb_drawchar(int h_pos, int v_pos, unsigned ch)
 {
-	static const char const param_names[] ALIGN1 -		"BAR_WIDTH\0" "BAR_HEIGHT\0"
-		"BAR_LEFT\0" "BAR_TOP\0"
-		"BAR_R\0" "BAR_G\0" "BAR_B\0"
-#if DEBUG
-		"DEBUG\0"
+	int line_num;
+	DATA *line_ptr;
+
+	ch -= 32;
+	if (ch >= NUM_CHARS)
+		return;
+
+	line_ptr = (DATA*)(G.addr + (v_pos * G.scr_var.xres + h_pos) * BYTES_PER_PIXEL);
+
+	for (line_num = 0; line_num < SCANLINES; line_num++) {
+		int m = G.text_scale;
+		while (--m >= 0) {
+			// Draw one horz line of the character
+			DATA *ptr = line_ptr;
+			uint8_t pixel_bit;
+			for (pixel_bit = 0x80; pixel_bit; pixel_bit >>= 1) {
+				if (fontmap[ch][line_num] & pixel_bit) {
+					int n = G.text_scale;
+					while (--n >= 0)
+						*ptr++ = G.textpix;
+				} else {
+					ptr += G.text_scale;
+				}
+			}
+			line_ptr += G.scr_var.xres;
+		}
+	}
+}
+
+
+/*
+ * Draw a string
+ */
+static void fb_drawstring(char *string)
+{
+	static int old_string_size = -1; // in pixel
+	int n;
+
+	// redraws the portion of image interested to the old write operation
+	if (old_string_size != -1) {
+		fb_drawimage(G.text_posx, G.text_posy,
+				old_string_size, SCANLINES * G.text_scale);
+	}
+
+	// new write operation
+	n = 0;
+	while (*string) {
+		fb_drawchar(G.text_posx + n,
+				G.text_posy,
+				*string);
+		n += 8 * G.text_scale;
+		string++;
+	}
+	old_string_size = n;
+}
 #endif
-		;
+
+
+/*
+ * Parse configuration file
+ */
+static void init(const char *cfg_filename)
+{
 	char *token[2];
 	parser_t *parser = config_open2(cfg_filename, xfopen_stdin);
 	while (config_read(parser, token, 2, 2, "#=",
@@ -294,25 +501,29 @@ static void init(const char *cfg_filenam
 		unsigned val = xatoi_u(token[1]);
 		int i = index_in_strings(param_names, token[0]);
 		if (i < 0)
-			bb_error_msg_and_die("syntax error: '%s'", token[0]);
-		if (i >= 0 && i < 7)
-			G.ns[i] = val;
-#if DEBUG
-		if (i == 7) {
-			G.bdebug_messages = val;
-			if (G.bdebug_messages)
-				G.logfile_fd = xfopen_for_write("/tmp/fbsplash.log");
-		}
-#endif
+			bb_error_msg_and_die("syntax error: %s", token[0]);
+		G.ns[i] = val;
 	}
 	config_close(parser);
+
+#if DEBUG
+	if (G.bdebug_messages)
+		G.logfile_fp = xfopen_for_write("/tmp/fbsplash.log");
+#endif
+	G.textpix = _24to16(G.text_colr, G.text_colg, G.text_colb);
 }


 int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int fbsplash_main(int argc UNUSED_PARAM, char **argv)
 {
+#if ENABLE_FBSPLASH_DYNAMIC_FONT
+	const char *fontmap_filename = NULL;
+#else
+# define fontmap_filename 1
+#endif
 	const char *fb_device, *cfg_filename, *fifo_filename;
+
 	FILE *fp = fp; // for compiler
 	char *num_buf;
 	unsigned num;
@@ -324,9 +535,21 @@ int fbsplash_main(int argc UNUSED_PARAM,
 	fb_device = "/dev/fb0";
 	cfg_filename = NULL;
 	fifo_filename = NULL;
+
+#if ENABLE_FBSPLASH_DYNAMIC_FONT
+	bCursorOff = 1 & getopt32(argv, "cs:d:i:f:m:",
+			&G.image_filename, &fb_device, &cfg_filename, &fifo_filename, &fontmap_filename);
+
+	if (fontmap_filename) {
+		int fontmap_fd = xopen(fontmap_filename, O_RDONLY);
+		fontmap = xmalloc(sizeof(fontmap[0]) * NUM_CHARS);
+		xread(fontmap_fd, fontmap, sizeof(fontmap[0]) * NUM_CHARS);
+		close(fontmap_fd);
+	}
+#else
 	bCursorOff = 1 & getopt32(argv, "cs:d:i:f:",
 			&G.image_filename, &fb_device, &cfg_filename, &fifo_filename);
-
+#endif
 	// parse configuration file
 	if (cfg_filename)
 		init(cfg_filename);
@@ -342,7 +565,7 @@ int fbsplash_main(int argc UNUSED_PARAM,
 		full_write(STDOUT_FILENO, "\x1b" "[?25l", 6);
 	}

-	fb_drawimage();
+	fb_drawimage(0, 0, -1, -1);

 	if (!fifo_filename)
 		return EXIT_SUCCESS;
@@ -373,6 +596,14 @@ int fbsplash_main(int argc UNUSED_PARAM,
 			DEBUG_MESSAGE("exit");
 			break;
 		}
+#if ENABLE_FBSPLASH_TEXT_RENDERING
+		else if (strncmp(num_buf, "write:", 6) == 0) {
+			if (fontmap_filename) {
+				fb_drawstring(num_buf + 6);
+				continue;
+			}
+		}
+#endif
 		num = atoi(num_buf);
 		if (isdigit(num_buf[0]) && (num <= 100)) {
 #if DEBUG
diff -d -urpN busybox.2/miscutils/fbsplash.cfg busybox.3/miscutils/fbsplash.cfg
--- busybox.2/miscutils/fbsplash.cfg	2009-02-15 12:35:26.000000000 +0100
+++ busybox.3/miscutils/fbsplash.cfg	2009-02-15 16:58:15.000000000 +0100
@@ -7,3 +7,13 @@ BAR_HEIGHT 
 BAR_R€
 BAR_G€
 BAR_B0
+# the below settings are active only if you enable the option \
FBSPLASH_TEXT_RENDERING +# text position
+TEXT_LEFT0
+TEXT_TOP50
+# text color
+TEXT_R€
+TEXT_G€
+TEXT_B0
+# text size (1 to 4)
+TEXT_SIZE=2



_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic