Hi,
Since I'm playing around with DirectColor visuals, I've thought of
adding a SetColorAdjustment hook to the primary layer using the gamma
ramp. Brightness and contrast adjustments are doable by programming the
gamma ramp. Saturation adjustment is not as correct, since its
implementation is best done on a per-pixel basis.
The attached function is not thoroughly tested, but seems to work during
my debugging sessions. Also, I'm not sure if the algorithm is correct.
It requires an fbdev driver that correctly supports DirectColor visuals
(check by running XFBDev and launching the xgamma utility).
What is hue anyway? Can this be emulated?
Tony
static DFBResult
primarySetColorAdjustment( DisplayLayer *layer,
void *driver_data,
void *layer_data,
DFBColorAdjustment *adj )
{
CoreSurface *surface = dfb_layer_surface( layer );
CorePalette *palette = surface->palette;
struct fb_cmap cmap;
signed short r, g, b, a;
signed short contrast = adj->contrast >> 8;
signed short brightness = (adj->brightness >> 8) - 128;
signed short saturation = adj->saturation >> 8;
int i;
if (dfb_fbdev->shared->fix.visual != FB_VISUAL_DIRECTCOLOR &&
palette == NULL)
return DFB_UNIMPLEMENTED;
/* Use gamma ramp to set color attributes */
cmap.start = 0;
cmap.len = surface->palette->num_entries;
cmap.red = (__u16*)alloca( 2 * cmap.len );
cmap.green = (__u16*)alloca( 2 * cmap.len );
cmap.blue = (__u16*)alloca( 2 * cmap.len );
cmap.transp = (__u16*)alloca( 2 * cmap.len );
for (i = 0; i < cmap.len; i++) {
/*
* Brightness Adjustment: Increase/Decrease each color channels
* by a constant amount as specified by value of brightness.
*/
r = (signed short) palette->entries[i].r + brightness;
g = (signed short) palette->entries[i].g + brightness;
b = (signed short) palette->entries[i].b + brightness;
a = (signed short) palette->entries[i].a;
r = (r > 255) ? 255 : r;
g = (g > 255) ? 255 : g;
b = (b > 255) ? 255 : b;
r = (r < 0) ? 0 : r;
g = (g < 0) ? 0 : g;
b = (b < 0) ? 0 : b;
/*
* Contrast Adjustment: We increase/decrease the "separation"
* between colors in proportion to the value specified by the
* contrast control. Decreasing the contrast has a side effect
* of decreasing the brightness.
*/
/* Increase contrast */
if (contrast > 128) {
contrast -= 128;
r = ((r + contrast/2)/contrast) * contrast;
g = ((g + contrast/2)/contrast) * contrast;
b = ((b + contrast/2)/contrast) * contrast;
}
/* Decrease contrast */
else if (contrast < 127) {
float c = (float)contrast/128.0;
r = (signed short)((float)r * c);
g = (signed short)((float)g * c);
b = (signed short)((float)b * c);
}
/*
* Saturation Adjustment: This is the crudest implementation. The
* best way to implement saturation is on-the-fly, on a per-pixel
* basis. We can approximate this by just squaring each color
* component, then scale back using the saturation value. Result
* may not be as expected. The implementation has the side effect
* of altering the contrast too.
*/
if (saturation != 0 && saturation != 128) {
saturation = 255 - saturation;
r = (signed short)((float)(r * r)/(float)saturation);
g = (signed short)((float)(g * g)/(float)saturation);
b = (signed short)((float)(b * b)/(float)saturation);
}
r = (r > 255) ? 255 : r;
g = (g > 255) ? 255 : g;
b = (b > 255) ? 255 : b;
r = (r < 0) ? 0 : r;
g = (g < 0) ? 0 : g;
b = (b < 0) ? 0 : b;
r |= r << 8;
g |= g << 8;
b |= b << 8;
a |= a << 8;
cmap.red[i] = (unsigned short) r;
cmap.green[i] = (unsigned short) g;
cmap.blue[i] = (unsigned short) b;
cmap.transp[i] = (unsigned short) a;
}
if (ioctl( dfb_fbdev->fd, FBIOPUTCMAP, &cmap ) < 0) {
PERRORMSG( "DirectFB/core/fbdev: "
"Could not set the palette!\n" );
return errno2dfb(errno);
}
return DFB_OK;
}