From 181cec4348da40331b3e8ab365732c025ec149b2 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Wed, 27 Apr 2011 19:24:15 +0200 Subject: Import upstream version 0.11.0~svn1143 --- drv_generic_graphic.c | 723 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 723 insertions(+) create mode 100644 drv_generic_graphic.c (limited to 'drv_generic_graphic.c') diff --git a/drv_generic_graphic.c b/drv_generic_graphic.c new file mode 100644 index 0000000..cdc0129 --- /dev/null +++ b/drv_generic_graphic.c @@ -0,0 +1,723 @@ +/* $Id: drv_generic_graphic.c 1003 2009-03-26 08:11:33Z michux $ + * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_generic_graphic.c $ + * + * generic driver helper for graphic displays + * + * Copyright (C) 1999, 2000 Michael Reinelt + * Copyright (C) 2004 The LCD4Linux Team + * + * This file is part of LCD4Linux. + * + * LCD4Linux is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LCD4Linux is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * + * exported functions: + * + * int drv_generic_graphic_init (char *section, char *driver); + * initializes the generic graphic driver + * + * int drv_generic_graphic_draw (WIDGET *W); + * renders Text widget into framebuffer + * calls drv_generic_graphic_real_blit() + * + * int drv_generic_graphic_icon_draw (WIDGET *W); + * renders Icon widget into framebuffer + * calls drv_generic_graphic_real_blit() + * + * int drv_generic_graphic_bar_draw (WIDGET *W); + * renders Bar widget into framebuffer + * calls drv_generic_graphic_real_blit() + * + * int drv_generic_graphic_quit (void); + * closes generic graphic driver + * + */ + + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "cfg.h" +#include "plugin.h" +#include "layout.h" +#include "widget.h" +#include "property.h" +#include "widget_text.h" +#include "widget_icon.h" +#include "widget_bar.h" +#include "widget_image.h" +#include "rgb.h" +#include "drv.h" +#include "drv_generic.h" +#include "drv_generic_graphic.h" +#include "font_6x8.h" +#include "font_6x8_bold.h" + +#ifdef WITH_DMALLOC +#include +#endif + +/* pixel colors */ +RGBA FG_COL = {.R = 0x00,.G = 0x00,.B = 0x00,.A = 0xff }; +RGBA BG_COL = {.R = 0xff,.G = 0xff,.B = 0xff,.A = 0xff }; +RGBA BL_COL = {.R = 0xff,.G = 0xff,.B = 0xff,.A = 0x00 }; +RGBA NO_COL = {.R = 0x00,.G = 0x00,.B = 0x00,.A = 0x00 }; + +static char *Section = NULL; +static char *Driver = NULL; + +/* framebuffer */ +static RGBA *drv_generic_graphic_FB[LAYERS] = { NULL, }; + +/* inverted colors */ +static int INVERTED = 0; + +/* must be implemented by the real driver */ +void (*drv_generic_graphic_real_blit) () = NULL; + + +/****************************************/ +/*** generic Framebuffer stuff ***/ +/****************************************/ + +static void drv_generic_graphic_resizeFB(int rows, int cols) +{ + RGBA *newFB; + int i, l, row, col; + + /* Layout FB is large enough */ + if (rows <= LROWS && cols <= LCOLS) + return; + + /* get maximum values */ + if (rows < LROWS) + rows = LROWS; + if (cols < LCOLS) + cols = LCOLS; + + for (l = 0; l < LAYERS; l++) { + + /* allocate and initialize new Layout FB */ + newFB = malloc(cols * rows * sizeof(*newFB)); + for (i = 0; i < rows * cols; i++) + newFB[i] = NO_COL; + + /* transfer contents */ + if (drv_generic_graphic_FB[l] != NULL) { + for (row = 0; row < LROWS; row++) { + for (col = 0; col < LCOLS; col++) { + newFB[row * cols + col] = drv_generic_graphic_FB[l][row * LCOLS + col]; + } + } + free(drv_generic_graphic_FB[l]); + } + drv_generic_graphic_FB[l] = newFB; + } + + LCOLS = cols; + LROWS = rows; + +} + +static void drv_generic_graphic_window(int pos, int size, int max, int *wpos, int *wsize) +{ + int p1 = pos; + int p2 = pos + size; + + *wpos = 0; + *wsize = 0; + + if (p1 > max || p2 < 0 || size < 1) + return; + + if (p1 < 0) + p1 = 0; + + if (p2 > max) + p2 = max; + + *wpos = p1; + *wsize = p2 - p1; +} + +static void drv_generic_graphic_blit(const int row, const int col, const int height, const int width) +{ + if (drv_generic_graphic_real_blit) { + int r, c, h, w; + drv_generic_graphic_window(row, height, DROWS, &r, &h); + drv_generic_graphic_window(col, width, DCOLS, &c, &w); + if (h > 0 && w > 0) { + drv_generic_graphic_real_blit(r, c, h, w); + } + } +} + +static RGBA drv_generic_graphic_blend(const int row, const int col) +{ + int l, o; + RGBA p; + RGBA ret; + + ret.R = BL_COL.R; + ret.G = BL_COL.G; + ret.B = BL_COL.B; + ret.A = 0x00; + + /* find first opaque layer */ + /* layers below are fully covered */ + o = LAYERS - 1; + for (l = 0; l < LAYERS; l++) { + p = drv_generic_graphic_FB[l][row * LCOLS + col]; + if (p.A == 255) { + o = l; + break; + } + } + + for (l = o; l >= 0; l--) { + p = drv_generic_graphic_FB[l][row * LCOLS + col]; + switch (p.A) { + case 0: + break; + case 255: + ret.R = p.R; + ret.G = p.G; + ret.B = p.B; + ret.A = 0xff; + break; + default: + ret.R = (p.R * p.A + ret.R * (255 - p.A)) / 255; + ret.G = (p.G * p.A + ret.G * (255 - p.A)) / 255; + ret.B = (p.B * p.A + ret.B * (255 - p.A)) / 255; + ret.A = 0xff; + } + } + if (INVERTED) { + ret.R = 255 - ret.R; + ret.G = 255 - ret.G; + ret.B = 255 - ret.B; + } + + return ret; +} + + +/****************************************/ +/*** generic text handling ***/ +/****************************************/ + +static void drv_generic_graphic_render(const int layer, const int row, const int col, const RGBA fg, const RGBA bg, + const char *style, const char *txt) +{ + int c, r, x, y, len; + + /* sanity checks */ + if (layer < 0 || layer >= LAYERS) { + error("%s: layer %d out of bounds (0..%d)", Driver, layer, LAYERS - 1); + return; + } + + len = strlen(txt); + + /* maybe grow layout framebuffer */ + drv_generic_graphic_resizeFB(row + YRES, col + XRES * len); + + r = row; + c = col; + + /* render text into layout FB */ + while (*txt != '\0') { + unsigned char *chr; + + if (strstr(style, "bold") != NULL) { + chr = Font_6x8_bold[(int) *(unsigned char *) txt]; + } else { + chr = Font_6x8[(int) *(unsigned char *) txt]; + } + + for (y = 0; y < YRES; y++) { + int mask = 1 << XRES; + for (x = 0; x < XRES; x++) { + mask >>= 1; + if (chr[y] & mask) + drv_generic_graphic_FB[layer][(r + y) * LCOLS + c + x] = fg; + else + drv_generic_graphic_FB[layer][(r + y) * LCOLS + c + x] = bg; + } + } + c += XRES; + txt++; + } + + /* flush area */ + drv_generic_graphic_blit(row, col, YRES, XRES * len); + +} + + +/* say hello to the user */ +int drv_generic_graphic_greet(const char *msg1, const char *msg2) +{ + char *line1[] = { "* LCD4Linux " VERSION " *", + "LCD4Linux " VERSION, + "* LCD4Linux *", + "LCD4Linux", + "L4Linux", + NULL + }; + + char *line2[] = { "http://lcd4linux.bulix.org", + "lcd4linux.bulix.org", + NULL + }; + + int i; + int flag = 0; + + unsigned int cols = DCOLS / XRES; + unsigned int rows = DROWS / YRES; + + for (i = 0; line1[i]; i++) { + if (strlen(line1[i]) <= cols) { + drv_generic_graphic_render(0, YRES * 0, XRES * ((cols - strlen(line1[i])) / 2), FG_COL, BG_COL, "norm", + line1[i]); + flag = 1; + break; + } + } + + if (rows >= 2) { + for (i = 0; line2[i]; i++) { + if (strlen(line2[i]) <= cols) { + drv_generic_graphic_render(0, YRES * 1, XRES * ((cols - strlen(line2[i])) / 2), FG_COL, BG_COL, "norm", + line2[i]); + flag = 1; + break; + } + } + } + + if (msg1 && rows >= 3) { + unsigned int len = strlen(msg1); + if (len <= cols) { + drv_generic_graphic_render(0, YRES * 2, XRES * ((cols - len) / 2), FG_COL, BG_COL, "norm", msg1); + flag = 1; + } + } + + if (msg2 && rows >= 4) { + unsigned int len = strlen(msg2); + if (len <= cols) { + drv_generic_graphic_render(0, YRES * 3, XRES * ((cols - len) / 2), FG_COL, BG_COL, "norm", msg2); + flag = 1; + } + } + + return flag; +} + + +int drv_generic_graphic_draw(WIDGET * W) +{ + WIDGET_TEXT *Text = W->data; + RGBA fg, bg; + + fg = W->fg_valid ? W->fg_color : FG_COL; + bg = W->bg_valid ? W->bg_color : BG_COL; + + drv_generic_graphic_render(W->layer, YRES * W->row, XRES * W->col, fg, bg, P2S(&Text->style), Text->buffer); + + return 0; +} + + +/****************************************/ +/*** generic icon handling ***/ +/****************************************/ + +int drv_generic_graphic_icon_draw(WIDGET * W) +{ + WIDGET_ICON *Icon = W->data; + RGBA fg, bg; + unsigned char *bitmap = Icon->bitmap + YRES * Icon->curmap; + int layer, row, col; + int x, y; + int visible; + + layer = W->layer; + row = YRES * W->row; + col = XRES * W->col; + + fg = W->fg_valid ? W->fg_color : FG_COL; + bg = W->bg_valid ? W->bg_color : BG_COL; + + /* sanity check */ + if (layer < 0 || layer >= LAYERS) { + error("%s: layer %d out of bounds (0..%d)", Driver, layer, LAYERS - 1); + return -1; + } + + /* maybe grow layout framebuffer */ + drv_generic_graphic_resizeFB(row + YRES, col + XRES); + + /* Icon visible? */ + visible = P2N(&Icon->visible) > 0; + + /* render icon */ + for (y = 0; y < YRES; y++) { + int mask = 1 << XRES; + for (x = 0; x < XRES; x++) { + int i = (row + y) * LCOLS + col + x; + mask >>= 1; + if (visible) { + if (bitmap[y] & mask) + drv_generic_graphic_FB[layer][i] = fg; + else + drv_generic_graphic_FB[layer][i] = bg; + } else { + drv_generic_graphic_FB[layer][i] = BG_COL; + } + } + } + + /* flush area */ + drv_generic_graphic_blit(row, col, YRES, XRES); + + return 0; + +} + + +/****************************************/ +/*** generic bar handling ***/ +/****************************************/ + +int drv_generic_graphic_bar_draw(WIDGET * W) +{ + WIDGET_BAR *Bar = W->data; + RGBA fg, bg, bar[2]; + int layer, row, col, len, res, rev, max, val1, val2; + int x, y; + DIRECTION dir; + STYLE style; + + layer = W->layer; + row = YRES * W->row; + col = XRES * W->col; + dir = Bar->direction; + style = Bar->style; + len = Bar->length; + + fg = W->fg_valid ? W->fg_color : FG_COL; + bg = W->bg_valid ? W->bg_color : BG_COL; + + bar[0] = Bar->color_valid[0] ? Bar->color[0] : fg; + bar[1] = Bar->color_valid[1] ? Bar->color[1] : fg; + + /* sanity check */ + if (layer < 0 || layer >= LAYERS) { + error("%s: layer %d out of bounds (0..%d)", Driver, layer, LAYERS - 1); + return -1; + } + + /* maybe grow layout framebuffer */ + if (dir & (DIR_EAST | DIR_WEST)) { + drv_generic_graphic_resizeFB(row + YRES, col + XRES * len); + } else { + drv_generic_graphic_resizeFB(row + YRES * len, col + XRES); + } + + res = dir & (DIR_EAST | DIR_WEST) ? XRES : YRES; + max = len * res; + val1 = Bar->val1 * (double) (max); + val2 = Bar->val2 * (double) (max); + + if (val1 < 1) + val1 = 1; + else if (val1 > max) + val1 = max; + + if (val2 < 1) + val2 = 1; + else if (val2 > max) + val2 = max; + + rev = 0; + + switch (dir) { + case DIR_WEST: + val1 = max - val1; + val2 = max - val2; + rev = 1; + + case DIR_EAST: + for (y = 0; y < YRES; y++) { + int val = y < YRES / 2 ? val1 : val2; + RGBA bc = y < YRES / 2 ? bar[0] : bar[1]; + + for (x = 0; x < max; x++) { + if (x < val) + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col + x] = rev ? bg : bc; + else + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col + x] = rev ? bc : bg; + + if (style) { + drv_generic_graphic_FB[layer][(row + 0) * LCOLS + col + x] = fg; + drv_generic_graphic_FB[layer][(row + YRES - 1) * LCOLS + col + x] = fg; + } + } + if (style) { + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col] = fg; + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col + max - 1] = fg; + } + } + break; + + case DIR_NORTH: + val1 = max - val1; + val2 = max - val2; + rev = 1; + + case DIR_SOUTH: + for (x = 0; x < XRES; x++) { + int val = x < XRES / 2 ? val1 : val2; + RGBA bc = x < XRES / 2 ? bar[0] : bar[1]; + for (y = 0; y < max; y++) { + if (y < val) + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col + x] = rev ? bg : bc; + else + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col + x] = rev ? bc : bg; + if (style) { + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col + 0] = fg; + drv_generic_graphic_FB[layer][(row + y) * LCOLS + col + XRES - 1] = fg; + } + } + if (style) { + drv_generic_graphic_FB[layer][(row + 0) * LCOLS + col + x] = fg; + drv_generic_graphic_FB[layer][(row + max - 1) * LCOLS + col + x] = fg; + } + } + break; + } + + /* flush area */ + if (dir & (DIR_EAST | DIR_WEST)) { + drv_generic_graphic_blit(row, col, YRES, XRES * len); + } else { + drv_generic_graphic_blit(row, col, YRES * len, XRES); + } + + return 0; +} + + +/****************************************/ +/*** generic image handling ***/ +/****************************************/ + +int drv_generic_graphic_image_draw(WIDGET * W) +{ + WIDGET_IMAGE *Image = W->data; + int layer, row, col, width, height; + int x, y; + int visible; + + layer = W->layer; + row = W->row; + col = W->col; + width = Image->width; + height = Image->height; + + /* sanity check */ + if (layer < 0 || layer >= LAYERS) { + error("%s: layer %d out of bounds (0..%d)", Driver, layer, LAYERS - 1); + return -1; + } + + /* if no size or no image at all, do nothing */ + if (width <= 0 || height <= 0 || Image->bitmap == NULL) { + return 0; + } + + /* maybe grow layout framebuffer */ + drv_generic_graphic_resizeFB(row + height, col + width); + + /* render image */ + visible = P2N(&Image->visible); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + int i = (row + y) * LCOLS + col + x; + if (visible) { + drv_generic_graphic_FB[layer][i] = Image->bitmap[y * width + x]; + } else { + drv_generic_graphic_FB[layer][i] = BG_COL; + } + } + } + + /* flush area */ + drv_generic_graphic_blit(row, col, height, width); + + return 0; + +} + + +/****************************************/ +/*** generic init/quit ***/ +/****************************************/ + +int drv_generic_graphic_init(const char *section, const char *driver) +{ + int i, l; + char *color; + WIDGET_CLASS wc; + + Section = (char *) section; + Driver = (char *) driver; + + /* init layout framebuffer */ + LROWS = 0; + LCOLS = 0; + + for (l = 0; l < LAYERS; l++) + drv_generic_graphic_FB[l] = NULL; + + drv_generic_graphic_resizeFB(DROWS, DCOLS); + + /* sanity check */ + for (l = 0; l < LAYERS; l++) { + if (drv_generic_graphic_FB[l] == NULL) { + error("%s: framebuffer could not be allocated: malloc() failed", Driver); + return -1; + } + } + + /* init generic driver & register plugins */ + drv_generic_init(); + + /* set default colors */ + color = cfg_get(Section, "foreground", "000000ff"); + if (color2RGBA(color, &FG_COL) < 0) { + error("%s: ignoring illegal color '%s'", Driver, color); + } + if (color) + free(color); + + color = cfg_get(Section, "background", "ffffff00"); + if (color2RGBA(color, &BG_COL) < 0) { + error("%s: ignoring illegal color '%s'", Driver, color); + } + if (color) + free(color); + + color = cfg_get(Section, "basecolor", "ffffff"); + if (color2RGBA(color, &BL_COL) < 0) { + error("%s: ignoring illegal color '%s'", Driver, color); + } + if (color) + free(color); + + /* inverted display? */ + cfg_number(section, "inverted", 0, 0, 1, &INVERTED); + + /* register text widget */ + wc = Widget_Text; + wc.draw = drv_generic_graphic_draw; + widget_register(&wc); + + /* register icon widget */ + wc = Widget_Icon; + wc.draw = drv_generic_graphic_icon_draw; + widget_register(&wc); + + /* register bar widget */ + wc = Widget_Bar; + wc.draw = drv_generic_graphic_bar_draw; + widget_register(&wc); + + /* register image widget */ +#ifdef WITH_IMAGE + wc = Widget_Image; + wc.draw = drv_generic_graphic_image_draw; + widget_register(&wc); +#endif + + /* clear framebuffer but do not blit to display */ + for (l = 0; l < LAYERS; l++) + for (i = 0; i < LCOLS * LROWS; i++) + drv_generic_graphic_FB[l][i] = NO_COL; + + return 0; +} + + +int drv_generic_graphic_clear(void) +{ + int i, l; + + for (l = 0; l < LAYERS; l++) + for (i = 0; i < LCOLS * LROWS; i++) + drv_generic_graphic_FB[l][i] = NO_COL; + + drv_generic_graphic_blit(0, 0, LROWS, LCOLS); + + return 0; +} + + +RGBA drv_generic_graphic_rgb(const int row, const int col) +{ + return drv_generic_graphic_blend(row, col); +} + + +unsigned char drv_generic_graphic_gray(const int row, const int col) +{ + RGBA p = drv_generic_graphic_blend(row, col); + return (77 * p.R + 150 * p.G + 28 * p.B) / 255; +} + + +unsigned char drv_generic_graphic_black(const int row, const int col) +{ + return drv_generic_graphic_gray(row, col) < 127; +} + + +int drv_generic_graphic_quit(void) +{ + int l; + + for (l = 0; l < LAYERS; l++) { + if (drv_generic_graphic_FB[l]) { + free(drv_generic_graphic_FB[l]); + drv_generic_graphic_FB[l] = NULL; + } + } + widget_unregister(); + return (0); +} -- cgit v1.2.3