So far we have used some fixed palette values for the colors (see part four) - namely 0-15 to draw the 16 bars. These happen to be the default Linux framebuffer colors (slight variations between distributions to be expected). Since we are using palette indexes, we don't really know what are the actual colors output. The Linux framebuffer interface provides a function FBIOGETCMAP to read the color palette:
...would give us the red, green and blue components of the colors in the palette. So most likely r[0]=0, g[0]=0, b[0]=0 for the color index 0 i.e. black (#000000 in HTML) - r[1]=0, g[1]=0, b[1]=255 for color index 1 i.e. blue (#0000FF). Colors from index 16 onwards are most likely all black.
// Get palette information unsigned short r[256]; unsigned short g[256]; unsigned short b[256]; unsigned short a[256]; memset(r, 0, 256 * sizeof(unsigned short)); memset(g, 0, 256 * sizeof(unsigned short)); memset(b, 0, 256 * sizeof(unsigned short)); memset(a, 0, 256 * sizeof(unsigned short)); struct fb_cmap pal; pal.start = 0; pal.len = 0; pal.red = r; pal.green = g; pal.blue = b; pal.transp = a; if (ioctl(fbfd, FBIOGETCMAP, &pal)) { printf("Error reading palette.\n"); }
Unfortunately reading this information is not supported by the RPi framebuffer driver ...this surely is not how I wanted these posts to be Raspberry Pi specific :(
After a bit of trial and error (and 'stealing' the initial values from another Linux system using the above code), I managed to get pretty close to the RPi default colors. In this example we initialise some hard-coded values (note that I use the possibly more familiar range 0-255, matching many systems like the HTML color scheme) for the colors (the enum is not used here but might prove handy later on - think of put_pixel(x, y, RED)), set them to the system palette starting at index 16 (i.e. just after the default colors) and then draw the familiar color bars at the top half of the screen - and bars with same colors but using different palette indexes at the lower half for comparison:
...I only hope my monitor color tolerance is about ok and your eyes not much sharper than mine ;)
... // after includes // default framebuffer palette typedef enum { BLACK = 0, /* 0, 0, 0 */ BLUE = 1, /* 0, 0, 172 */ GREEN = 2, /* 0, 172, 0 */ CYAN = 3, /* 0, 172, 172 */ RED = 4, /* 172, 0, 0 */ PURPLE = 5, /* 172, 0, 172 */ ORANGE = 6, /* 172, 84, 0 */ LTGREY = 7, /* 172, 172, 172 */ GREY = 8, /* 84, 84, 84 */ LIGHT_BLUE = 9, /* 84, 84, 255 */ LIGHT_GREEN = 10, /* 84, 255, 84 */ LIGHT_CYAN = 11, /* 84, 255, 255 */ LIGHT_RED = 12, /* 255, 84, 84 */ LIGHT_PURPLE = 13, /* 255, 84, 255 */ YELLOW = 14, /* 255, 255, 84 */ WHITE = 15 /* 255, 255, 255 */ } COLOR_INDEX_T; static unsigned short def_r[] = { 0, 0, 0, 0, 172, 172, 172, 172, 84, 84, 84, 84, 255, 255, 255, 255}; static unsigned short def_g[] = { 0, 0, 172, 172, 0, 0, 84, 172, 84, 84, 255, 255, 84, 84, 255, 255}; static unsigned short def_b[] = { 0, 172, 0, 172, 0, 172, 0, 172, 84, 255, 84, 255, 84, 255, 84, 255}; ... void draw() { int x, y; for (y = 0; y < (vinfo.yres / 2); y++) { for (x = 0; x < vinfo.xres; x++) { // color based on the 16th of the screen width int c = 16 * x / vinfo.xres; // default colors at upper half put_pixel(x, y, c); // our own colors at lower half put_pixel(x, y + (vinfo.yres / 2), c + 16); } } } ... // in main after opening the fb device // Set palette unsigned short r[256]; unsigned short g[256]; unsigned short b[256]; memset(&r, 0, 256); // initialise with zeros memset(&g, 0, 256); memset(&b, 0, 256); int i; for(i = 0; i < 16; i++) { // copy the hard-coded values // note that Linux provides more precision (0-65535), // so we multiply ours (0-255) by 256 r[i] = def_r[i] << 8; g[i] = def_g[i] << 8; b[i] = def_b[i] << 8; } struct fb_cmap pal; pal.start = 16; // start our colors after the default 16 pal.len = 256; // kludge to force bcm fb drv to commit palette... pal.red = r; pal.green = g; pal.blue = b; pal.transp = 0; // we want all colors non-transparent == null if (ioctl(fbfd, FBIOPUTCMAP, &pal)) { printf("Error setting palette.\n"); } ...
Now you could go and fill the palette with any colors you can come up with and draw something interesting. If you use the first 16 color 'slots' in the palette for your own colors, remember to set the default colors at the end of your program:
...otherwise when returning to the console, you might not be able to read any of the text ;) In case this happens (or some other issue with the graphics garbles the screen), one way to fix thing is to type (possibly 'blindly') the commands:
...this (changes the color depth and resets back to the RPi default and) should clear refresh the screen.
// before closing the fbfd // reset palette palette.start = 0; palette.len = 256; palette.red = def_red; palette.green = def_green; palette.blue = def_blue; palette.transp = 0; if (ioctl(fbfd, FBIOPUTCMAP, &palette)) { printf("Error setting palette.\n"); }
fbset -depth 32 fbset -depth 16
[Continued in part six]
No comments:
Post a Comment
Note: only a member of this blog may post a comment.