/* * Image.c -- Image support routines. * * Authors : Patrick LECOANET * Creation date : Wed Dec 8 11:04:44 1999 */ /* * Copyright (c) 1999 CENA, Patrick Lecoanet -- * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This code 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this code; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include "Types.h" #include "Image.h" #include "WidgetInfo.h" #include "Geo.h" static const char rcsid[] = "$Id$"; static const char compile_id[] = "$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; /* * Key used to index the bitmap_masks hash table. */ typedef struct { Display *dpy; Pixmap bitmap; } BitmapKey; typedef struct _ImagePixmap { Display *dpy; Pixmap pixmap; Pixmap mask_pmap; struct _ImagePixmap *next; } ImagePixmap; static Tcl_HashTable image_bits; static Tcl_HashTable bitmap_masks; static Tcl_HashTable font_bitmaps; /* ********************************************************************************** * * GetImageBits -- * ********************************************************************************** */ ImageBits * GetImageBits(ZnWindow win, char *image_name, ZnImage image) { static int inited = 0; Tcl_HashEntry *entry; XImage *im1, *im2, *mask; Pixmap pmap; Display *dpy = Tk_Display(win); int depth = Tk_Depth(win); int x, y, new, width, height; unsigned char *line; XGCValues values; GC gc; ImageBits *im_bits; ZnBool full_mask=True; if (!inited) { Tcl_InitHashTable(&image_bits, TCL_STRING_KEYS); inited = 1; } entry = Tcl_FindHashEntry(&image_bits, image_name); if (entry != NULL) { im_bits = (ImageBits *) Tcl_GetHashValue(entry); } else { Tk_SizeOfImage(image, &width, &height); im_bits = (ImageBits *) ZnMalloc(sizeof(ImageBits)); #ifdef SHM im_bits->pixbuf = NULL; #endif im_bits->pixmaps = NULL; im_bits->b_bits = NULL; pmap = XCreatePixmap(dpy, ZnWindowId(win), width, height, depth); values.foreground = 0; gc = XCreateGC(dpy, pmap, GCForeground, &values); XFillRectangle(dpy, pmap, gc, 0, 0, width, height); Tk_RedrawImage(image, 0, 0, width, height, pmap, 0, 0); im_bits->pixels = im1 = XGetImage(dpy, pmap, 0, 0, width, height, ~0L, ZPixmap); im_bits->width = width; im_bits->height = height; values.foreground = 1; XChangeGC(dpy, gc, GCForeground, &values); XFillRectangle(dpy, pmap, gc, 0, 0, width, height); XFreeGC(dpy, gc); Tk_RedrawImage(image, 0, 0, width, height, pmap, 0, 0); im2 = XGetImage(dpy, pmap, 0, 0, width, height, ~0L, ZPixmap); XFreePixmap(dpy, pmap); /* * The image structure can be setup locally (TODO). */ pmap = XCreatePixmap(dpy, ZnWindowId(win), width, height, 1); values.foreground = 0; gc = XCreateGC(dpy, pmap, GCForeground, &values); XFillRectangle(dpy, pmap, gc, 0, 0, width, height); XFreeGC(dpy, gc); mask = XGetImage(dpy, pmap, 0, 0, width, height, 1, XYPixmap); XFreePixmap(dpy, pmap); im_bits->b_bits = (BitmapBits *) ZnMalloc(sizeof(BitmapBits)); im_bits->b_bits->pixels = ZnMalloc(height * mask->bytes_per_line); memset(im_bits->b_bits->pixels, 0, height * mask->bytes_per_line); im_bits->b_bits->rowstride = mask->bytes_per_line; im_bits->b_bits->width = width; im_bits->b_bits->height = height; line = im_bits->b_bits->pixels; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (XGetPixel(im1, x, y) == XGetPixel(im2, x, y)) { XPutPixel(mask, x, y, 1L); line[x >> 3] |= 0x80 >> (x & 7); } else { full_mask = False; } } line += im_bits->b_bits->rowstride; } XDestroyImage(im2); if (full_mask) { XDestroyImage(mask); im_bits->mask = ZnUnspecifiedPattern; } else { im_bits->mask = mask; } entry = Tcl_CreateHashEntry(&image_bits, image_name, &new); Tcl_SetHashValue(entry, (ClientData) im_bits); } return im_bits; } void InvalidateImage(char *image_name) { Tcl_HashEntry *entry; ImageBits *im_bits; ImagePixmap *im_pmap, *next_im_pmap; /* * Destroy the image entry and wait the cache fault to * reload the new one. */ /*printf("InvalidateImage %s\n", image_name);*/ entry = Tcl_FindHashEntry(&image_bits, image_name); if (entry != NULL) { /*printf("deallocating bits for image %s\n", image_name);*/ im_bits = (ImageBits *) Tcl_GetHashValue(entry); XDestroyImage(im_bits->pixels); if (im_bits->mask) { XDestroyImage(im_bits->mask); } im_pmap = im_bits->pixmaps; while (im_pmap) { next_im_pmap = im_pmap->next; XFreePixmap(im_pmap->dpy, im_pmap->pixmap); if (im_bits->mask) { XFreePixmap(im_pmap->dpy, im_pmap->mask_pmap); } ZnFree(im_pmap); im_pmap = next_im_pmap; } if (im_bits->b_bits) { ZnFree(im_bits->b_bits->pixels); ZnFree(im_bits->b_bits); } #ifdef SHM if (im_bits->pixbuf) { art_pixbuf_free(im_bits->pixbuf); } #endif ZnFree(im_bits); Tcl_DeleteHashEntry(entry); } } /* ********************************************************************************** * * GetImagePixmap -- * ********************************************************************************** */ Pixmap GetImagePixmap(ZnWindow win, char *image_name, ZnImage image, Pixmap *mask_pmap) { ImageBits *im_bits; Display *dpy = Tk_Display(win); int depth = Tk_Depth(win); ImagePixmap *im_pmap, *next_im_pmap; Pixmap pixmap; GC gc; XGCValues values; im_bits = GetImageBits(win, image_name, image); im_pmap = next_im_pmap = im_bits->pixmaps; while (next_im_pmap && (im_pmap->dpy != dpy)) { im_pmap = next_im_pmap; next_im_pmap = next_im_pmap->next; } if (!im_pmap || (im_pmap->dpy != dpy)) { /* printf("New pixmap\n");*/ next_im_pmap = (ImagePixmap *) ZnMalloc(sizeof(ImagePixmap)); next_im_pmap->next = NULL; next_im_pmap->dpy = dpy; pixmap = XCreatePixmap(dpy, ZnWindowId(win), im_bits->width, im_bits->height, depth); gc = XCreateGC(dpy, pixmap, 0, NULL); XPutImage(dpy, pixmap, gc, im_bits->pixels, 0, 0, 0, 0, im_bits->width, im_bits->height); XFreeGC(dpy, gc); next_im_pmap->pixmap = pixmap; if (im_bits->mask) { next_im_pmap->mask_pmap = XCreatePixmap(dpy, ZnWindowId(win), im_bits->width, im_bits->height, 1); values.foreground = 1; values.background = 0; gc = XCreateGC(dpy, next_im_pmap->mask_pmap, GCForeground|GCBackground, &values); XPutImage(dpy, next_im_pmap->mask_pmap, gc, im_bits->mask, 0, 0, 0, 0, im_bits->width, im_bits->height); XFreeGC(dpy, gc); if (mask_pmap) { *mask_pmap = next_im_pmap->mask_pmap; } } else { next_im_pmap->mask_pmap = None; } if (im_pmap) { im_pmap->next = next_im_pmap; } else { im_bits->pixmaps = next_im_pmap; } } else { /*printf("Reusing pixmap\n");*/ pixmap = im_pmap->pixmap; if (mask_pmap) { *mask_pmap = im_pmap->mask_pmap; } } return pixmap; } /* ********************************************************************************** * * GetBitmapMask -- * ********************************************************************************** */ BitmapBits * GetBitmapMask(Display *dpy, Pixmap bitmap) { static int inited = 0; BitmapKey key; Tcl_HashEntry *entry; XImage *mask; BitmapBits *b_bits; unsigned char *line; int x, y, w, h, new; if (!inited) { Tcl_InitHashTable(&bitmap_masks, (sizeof(BitmapKey)) / sizeof(int)); inited = 1; } key.dpy = dpy; key.bitmap = bitmap; entry = Tcl_FindHashEntry(&bitmap_masks, (char *) &key); if (entry != NULL) { b_bits = (BitmapBits *) Tcl_GetHashValue(entry); } else { Tk_SizeOfBitmap(dpy, bitmap, &w, &h); mask = XGetImage(dpy, bitmap, 0, 0, w, h, 1L, XYPixmap); b_bits = (BitmapBits *) ZnMalloc(sizeof(BitmapBits)); b_bits->pixels = ZnMalloc(h * mask->bytes_per_line); memset(b_bits->pixels, 0, h * mask->bytes_per_line); b_bits->rowstride = mask->bytes_per_line; b_bits->width = w; b_bits->height = h; line = b_bits->pixels; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (XGetPixel(mask, x, y)) { line[x >> 3] |= 0x80 >> (x & 7); } } line += b_bits->rowstride; } XDestroyImage(mask); key.dpy = dpy; key.bitmap = bitmap; entry = Tcl_CreateHashEntry(&bitmap_masks, (char *) &key, &new); Tcl_SetHashValue(entry, (ClientData) b_bits); } return b_bits; } /* ********************************************************************************** * * GetFontBitmap -- * ********************************************************************************** */ FontBitmap * GetFontBitmap(ZnWindow win, ZnFont font) { static int inited = 0; Tcl_HashEntry *entry; FontBitmap *f_bits; XImage *im; Pixmap pix; GC gc; XGCValues values; Tk_FontMetrics fm; Display *dpy = Tk_Display(win); int i, x, y, black_pixel, pixel; int new, size, width, height; char str[1]; char *line; if (!inited) { Tcl_InitHashTable(&font_bitmaps, (sizeof(ZnFont)) / sizeof(int)); inited = 1; } entry = Tcl_FindHashEntry(&font_bitmaps, (char *) &font); if (entry != NULL) { f_bits = (FontBitmap *) Tcl_GetHashValue(entry); } else { f_bits = (FontBitmap *) ZnMalloc(sizeof(FontBitmap)); Tk_GetFontMetrics(font, &fm); height = fm.ascent + fm.descent; x = 0; for (i = 0; i < 256; i++) { str[0] = i; f_bits->chars[i].width = Tk_TextWidth(font, str, 1); f_bits->chars[i].bitmap_offset = x; /* Next char will be aligned on a 32 bit boundary; */ x += (f_bits->chars[i].width + 31) & -32; } width = x; f_bits->width = width; f_bits->height = height; f_bits->ascent = fm.ascent; f_bits->descent = fm.descent; pix = XCreatePixmap(dpy, ZnWindowId(win), width, height, 1); values.foreground = WhitePixel(dpy, DefaultScreen(dpy)); values.font = Tk_FontId(font); gc = XCreateGC(dpy, pix, GCForeground|GCFont, &values); XFillRectangle(dpy, pix, gc, 0, 0, width, height); black_pixel = BlackPixel(dpy, DefaultScreen(dpy)); values.foreground = black_pixel; XChangeGC(dpy, gc, GCForeground, &values); for (i = 0; i < 256; i++) { str[0] = i; XDrawString(dpy, pix, gc, f_bits->chars[i].bitmap_offset, f_bits->ascent, str, 1); } im = XGetImage(dpy, pix, 0, 0, width, height, 1L, XYPixmap); size = (width >> 3) * height; f_bits->bitmap = ZnMalloc(size); memset(f_bits->bitmap, 0, size); line = f_bits->bitmap; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { pixel = XGetPixel(im, x, y); if (pixel == black_pixel) { line[x >> 3] |= 128 >> (x & 7); } } line += width >> 3; } XDestroyImage(im); XFreePixmap(dpy, pix); XFreeGC(dpy, gc); entry = Tcl_CreateHashEntry(&font_bitmaps, (char *) &font, &new); Tcl_SetHashValue(entry, (ClientData) f_bits); } return f_bits; } static void rgb_text_opaque(art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, char *text , int num_chars, int start_x, int start_y, FontBitmap *fb, art_u32 rgb) { art_u8 *src, *src_p, *dst_p, *dst_linestart; art_u8 r, g, b; art_u8 bm; SuckChar *ch; int run_x0, run_y0; int j, x, y, tmp; int next_start, src_width, src_height, src_rowstride; int src_x0, src_y0, src_x1, src_y1; src_height = fb->height; src_rowstride = fb->width >> 3; src_y0 = 0; run_y0 = start_y - y0; if (run_y0 < 0) { src_y0 = -run_y0; run_y0 = 0; } src_y1 = src_height; tmp = start_y + src_height - y1; if (tmp > 0) { src_y1 -= tmp; } r = rgb >> 16; g = (rgb >> 8) & 0xff; b = rgb & 0xff; for (j = 0; j < num_chars; j++) { if (start_x > x1) { break; } ch = &fb->chars[(unsigned char)(*text)]; src_width = ch->width; next_start = start_x + src_width; if (next_start < x0) { goto nexto; } src = fb->bitmap + (ch->bitmap_offset >> 3); src_x0 = 0; run_x0 = start_x - x0; if (run_x0 < 0) { src_x0 = -run_x0; run_x0 = 0; } src_x1 = src_width; tmp = next_start - x1; if (tmp > 0) { src_x1 -= tmp; } dst_linestart = dst + run_y0 * dst_rowstride + run_x0 * 3; src_p = src + src_y0 * src_rowstride; for (y = src_y0; y < src_y1; y++) { dst_p = dst_linestart; for (x = src_x0; x < src_x1; x++) { bm = *(src_p + (x >> 3)); if (bm & (128 >> (x & 7))) { *dst_p = r; dst_p++; *dst_p = g; dst_p++; *dst_p = b; dst_p++; } else { dst_p += 3; } } dst_linestart += dst_rowstride; src_p += src_rowstride; } nexto: start_x = next_start; text++; } } void rgb_text(art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, char *text, int num_chars, int start_x, int start_y, FontBitmap *fb, art_u32 rgba) { art_u8 *src, *src_p, *dst_p, *dst_linestart; art_u8 r, g, b; art_u8 bm, comp; SuckChar *ch; int alpha; int run_x0, run_y0; int j, x, y, tmp; int next_start, src_width, src_height, src_rowstride; int src_x0, src_y0, src_x1, src_y1; src_height = fb->height; if ((start_y > y1) || (start_y+src_height < y0) || (start_x > x1)) { return; } alpha = rgba & 0xff; if (alpha == 0xff) { rgb_text_opaque(dst, x0, y0, x1, y1, dst_rowstride, text, num_chars, start_x, start_y, fb, rgba >> 8); return; } src_rowstride = fb->width >> 3; src_y0 = 0; run_y0 = start_y - y0; if (run_y0 < 0) { src_y0 = -run_y0; run_y0 = 0; } src_y1 = src_height; tmp = start_y + src_height - y1; if (tmp > 0) { src_y1 -= tmp; } alpha = (alpha << 8) + alpha + (alpha >> 7); r = rgba >> 24; g = (rgba >> 16) & 0xff; b = (rgba >> 8) & 0xff; for (j = 0; j < num_chars; j++) { if (start_x > x1) { break; } ch = &fb->chars[(unsigned char)(*text)]; src_width = ch->width; next_start = start_x + src_width; if (next_start < x0) { goto next; } src = fb->bitmap + (ch->bitmap_offset >> 3); src_x0 = 0; run_x0 = start_x - x0; if (run_x0 < 0) { src_x0 = -run_x0; run_x0 = 0; } src_x1 = src_width; tmp = next_start - x1; if (tmp > 0) { src_x1 -= tmp; } dst_linestart = dst + run_y0 * dst_rowstride + run_x0 * 3; src_p = src + src_y0 * src_rowstride; for (y = src_y0; y < src_y1; y++) { dst_p = dst_linestart; for (x = src_x0; x < src_x1; x++) { bm = *(src_p + (x >> 3)); if (bm & (128 >> (x & 7))) { comp = *dst_p; *dst_p = comp + (((r - comp) * alpha + 0x8000) >> 16); dst_p++; comp = *dst_p; *dst_p = comp + (((g - comp) * alpha + 0x8000) >> 16); dst_p++; comp = *dst_p; *dst_p = comp + (((b - comp) * alpha + 0x8000) >> 16); dst_p++; } else { dst_p += 3; } } dst_linestart += dst_rowstride; src_p += src_rowstride; } next: start_x = next_start; text++; } } /* rgb_image */ void rgb_image(art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, ArtPixBuf *pixbuf, int start_x, int start_y, int alpha) { art_u8 *src, *src_p, *dst_p; art_u8 *dst_linestart, *src_linestart; art_u8 r, g, b; int a; int run_x0, run_y0; int x, y, tmp; int src_x0, src_y0, src_x1, src_y1; int src_width, src_height, src_rowstride; if (pixbuf->format != ART_PIX_RGB) { ZnWarning("art_rgb_pixbuf_affine: need RGB format image\n"); return; } if (pixbuf->bits_per_sample != 8) { ZnWarning("art_rgb_pixbuf_affine: need 8-bit sample data\n"); return; } if ((pixbuf->n_channels != 4) || !pixbuf->has_alpha) { ZnWarning("art_rgb_pixbuf_affine: need RGBA sample data\n"); return; } src_width = pixbuf->width; src_height = pixbuf->height; if ((start_y > y1) || (start_y+src_height < y0) || (start_x > x1) || (start_x+src_width < x0)) { return; } src_rowstride = pixbuf->rowstride; src = pixbuf->pixels; src_x0 = src_y0 = 0; run_y0 = start_y - y0; if (run_y0 < 0) { src_y0 = -run_y0; run_y0 = 0; } src_y1 = src_height; tmp = start_y + src_height - y1; if (tmp > 0) { src_y1 -= tmp; } run_x0 = start_x - x0; if (run_x0 < 0) { src_x0 = -run_x0; run_x0 = 0; } src_x1 = src_width; tmp = start_x + src_width - x1; if (tmp > 0) { src_x1 -= tmp; } dst_linestart = dst + run_y0 * dst_rowstride + run_x0 * 3; src_linestart = src + src_y0 * src_rowstride + src_x0 * 4; for (y = src_y0; y < src_y1; y++) { dst_p = dst_linestart; src_p = src_linestart; for (x = src_x0; x < src_x1; x++) { a = src_p[3] * alpha / 255; if (a) { if (a == 255) { dst_p[0] = src_p[0]; dst_p[1] = src_p[1]; dst_p[2] = src_p[2]; } else { r = dst_p[0]; g = dst_p[1]; b = dst_p[2]; tmp = (src_p[0] - r) * a; r = r + ((tmp + (tmp >> 8) + 0x80) >> 8); tmp = (src_p[1] - g) * a; g = g + ((tmp + (tmp >> 8) + 0x80) >> 8); tmp = (src_p[2] - b) * a; b = b + ((tmp + (tmp >> 8) + 0x80) >> 8); dst_p[0] = r; dst_p[1] = g; dst_p[2] = b; } } dst_p += 3; src_p += 4; } dst_linestart += dst_rowstride; src_linestart += src_rowstride; } } /* rgb_bitmap */ static void rgb_bitmap_opaque(art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, art_u8 *src, int start_x, int start_y, int src_width, int src_height, int src_rowstride, art_u32 rgb) { art_u8 *src_p, *dst_p, *dst_linestart; art_u8 r, g, b; art_u8 bm; int run_x0, run_y0; int x, y, tmp; int src_x0, src_y0, src_x1, src_y1; src_x0 = src_y0 = 0; run_y0 = start_y - y0; if (run_y0 < 0) { src_y0 = -run_y0; run_y0 = 0; } src_y1 = src_height; tmp = start_y + src_height - y1; if (tmp > 0) { src_y1 -= tmp; } run_x0 = start_x - x0; if (run_x0 < 0) { src_x0 = -run_x0; run_x0 = 0; } src_x1 = src_width; tmp = start_x + src_width - x1; if (tmp > 0) { src_x1 -= tmp; } r = rgb >> 16; g = (rgb >> 8) & 0xff; b = rgb & 0xff; dst_linestart = dst + run_y0 * dst_rowstride + run_x0 * 3; src_p = src + src_y0 * src_rowstride; for (y = src_y0; y < src_y1; y++) { dst_p = dst_linestart; for (x = src_x0; x < src_x1; x++) { bm = *(src_p + (x >> 3)); if (bm & (128 >> (x & 7))) { *dst_p = r; dst_p++; *dst_p = g; dst_p++; *dst_p = b; dst_p++; } else { dst_p += 3; } } dst_linestart += dst_rowstride; src_p += src_rowstride; } } void rgb_bitmap(art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, art_u8 *src, int start_x, int start_y, int src_width, int src_height, int src_rowstride, art_u32 rgba) { art_u8 *src_p, *dst_p, *dst_linestart; art_u8 r, g, b; art_u8 bm, comp; int alpha; int run_x0, run_y0; int x, y, tmp; int src_x0, src_y0, src_x1, src_y1; if ((start_y > y1) || (start_y+src_height < y0) || (start_x > x1) || (start_x+src_width < x0)) { return; } alpha = rgba & 0xff; if (alpha == 0xff) { rgb_bitmap_opaque(dst, x0, y0, x1, y1, dst_rowstride, src, start_x, start_y, src_width, src_height, src_rowstride, rgba >> 8); return; } src_x0 = src_y0 = 0; run_y0 = start_y - y0; if (run_y0 < 0) { src_y0 = -run_y0; run_y0 = 0; } src_y1 = src_height; tmp = start_y + src_height - y1; if (tmp > 0) { src_y1 -= tmp; } run_x0 = start_x - x0; if (run_x0 < 0) { src_x0 = -run_x0; run_x0 = 0; } src_x1 = src_width; tmp = start_x + src_width - x1; if (tmp > 0) { src_x1 -= tmp; } alpha = (alpha << 8) + alpha + (alpha >> 7); r = rgba >> 24; g = (rgba >> 16) & 0xff; b = (rgba >> 8) & 0xff; dst_linestart = dst + run_y0 * dst_rowstride + run_x0 * 3; src_p = src + src_y0 * src_rowstride; for (y = src_y0; y < src_y1; y++) { dst_p = dst_linestart; for (x = src_x0; x < src_x1; x++) { bm = *(src_p + (x >> 3)); if (bm & (128 >> (x & 7))) { comp = *dst_p; *dst_p = comp + (((r - comp) * alpha + 0x8000) >> 16); dst_p++; comp = *dst_p; *dst_p = comp + (((g - comp) * alpha + 0x8000) >> 16); dst_p++; comp = *dst_p; *dst_p = comp + (((b - comp) * alpha + 0x8000) >> 16); dst_p++; } else { dst_p += 3; } } dst_linestart += dst_rowstride; src_p += src_rowstride; } } typedef struct _TileSVPData { ArtPixBuf *tile; int tile_x; int tile_y; art_u32 b_rgb; int alphatab[256]; art_u8 *buf; int rowstride; int x0, x1; } TileSVPData; static void tile_fill_run(art_u8 *buf, int num, art_u8 *tile_line, int tile_dx, int tile_width) { int i, start_len; art_u8 *ptr; tile_dx %= tile_width; if (tile_dx < 0) { tile_dx += tile_width; } start_len = tile_width - tile_dx; if (start_len > num) { start_len = num; } ptr = tile_line + 4*tile_dx; for (i = 0; i < start_len; i++) { *buf++ = *ptr++; *buf++ = *ptr++; *buf++ = *ptr++; ptr++; } num -= start_len; while (num > 0) { ptr = tile_line; for (i = MIN(tile_width, num); i > 0; i--) { *buf++ = *ptr++; *buf++ = *ptr++; *buf++ = *ptr++; ptr++; } num -= tile_width; } } static void tile_svp_aa_cb(void *callback_data, int y, int start, ArtSVPRenderAAStep *steps, int n_steps) { TileSVPData *data = (TileSVPData *)callback_data; art_u8 *linebuf, *tile_line; int run_x0, run_x1; art_u32 running_sum = start; art_u8 b_r, b_g, b_b; int x0, x1, k, dy; linebuf = data->buf; x0 = data->x0; x1 = data->x1; b_r = data->b_rgb >> 16; b_g = (data->b_rgb >> 8) & 0xff; b_b = data->b_rgb & 0xff; dy = y - data->tile_y; dy %= data->tile->height; if (dy < 0) { dy += data->tile->height; } tile_line = data->tile->pixels + dy * data->tile->rowstride; if (n_steps > 0) { run_x1 = steps[0].x; if (run_x1 > x0) { if (((running_sum >> 16) & 0xff) > 128) { tile_fill_run(linebuf, run_x1 - x0, tile_line, x0 - data->tile_x, data->tile->width); } else { art_rgb_fill_run(linebuf, b_r, b_g, b_b, run_x1 - x0); } } for (k = 0; k < n_steps - 1; k++) { running_sum += steps[k].delta; run_x0 = run_x1; run_x1 = steps[k + 1].x; if (run_x1 > run_x0) { if (((running_sum >> 16) & 0xff) > 128) { tile_fill_run(linebuf + (run_x0 - x0) * 3, run_x1 - run_x0, tile_line, run_x0 - data->tile_x, data->tile->width); } else { art_rgb_fill_run(linebuf + (run_x0 - x0) * 3, b_r, b_g, b_b, run_x1 - run_x0); } } } running_sum += steps[k].delta; if (x1 > run_x1) { if (((running_sum >> 16) & 0xff) > 128) { tile_fill_run(linebuf + (run_x1 - x0) * 3, x1 - run_x1, tile_line, run_x1 - data->tile_x, data->tile->width); } else { art_rgb_fill_run(linebuf + (run_x1 - x0) * 3, b_r, b_g, b_b, x1 - run_x1); } } } else { if (((running_sum >> 16) & 0xff) > 128) { tile_fill_run(linebuf, x1 - x0, tile_line, x0 - data->tile_x, data->tile->width); } else { art_rgb_fill_run(linebuf, b_r, b_g, b_b, x1 - x0); } } data->buf += data->rowstride; } void tile_svp_aa(const ArtSVP *svp, int x0, int y0, int x1, int y1, int tile_x, int tile_y, ArtPixBuf *tile, art_u32 bg_color, art_u8 *buf, int rowstride) { TileSVPData data; data.tile = tile; data.tile_x = tile_x; data.tile_y = tile_y; data.b_rgb = bg_color; data.buf = buf; data.rowstride = rowstride; data.x0 = x0; data.x1 = x1; art_svp_render_aa(svp, x0, y0, x1, y1, tile_svp_aa_cb, &data); } static void tile_fill_run_alpha(art_u8 *buf, int num, art_u8 *tile_line, int tile_dx, int tile_width, int alpha) { int v, vt, i, start_len; art_u8 *ptr; tile_dx %= tile_width; if (tile_dx < 0) { tile_dx += tile_width; } start_len = tile_width - tile_dx; if (start_len > num) { start_len = num; } ptr = tile_line + 4*tile_dx; for (i = 0; i < start_len; i++) { v = *buf; vt = *ptr++; *buf++ = v + (((vt - v) * alpha + 0x80) >> 8); v = *buf; vt = *ptr++; *buf++ = v + (((vt - v) * alpha + 0x80) >> 8); v = *buf; vt = *ptr++; *buf++ = v + (((vt - v) * alpha + 0x80) >> 8); ptr++; } num -= start_len; while (num > 0) { ptr = tile_line; for (i = MIN(tile_width, num); i > 0; i--) { v = *buf; vt = *ptr++; *buf++ = v + (((vt - v) * alpha + 0x80) >> 8); v = *buf; vt = *ptr++; *buf++ = v + (((vt - v) * alpha + 0x80) >> 8); v = *buf; vt = *ptr++; *buf++ = v + (((vt - v) * alpha + 0x80) >> 8); ptr++; } num -= tile_width; } } static void tile_svp_alpha_opaque_cb(void *callback_data, int y, int start, ArtSVPRenderAAStep *steps, int n_steps) { TileSVPData *data = (TileSVPData *)callback_data; art_u8 *linebuf, *tile_line; int run_x0, run_x1; art_u32 running_sum = start; int x0, x1, k, dy; int *alphatab; int alpha; linebuf = data->buf; x0 = data->x0; x1 = data->x1; alphatab = data->alphatab; dy = y - data->tile_y; dy %= data->tile->height; if (dy < 0) { dy += data->tile->height; } tile_line = data->tile->pixels + dy * data->tile->rowstride; if (n_steps > 0) { run_x1 = steps[0].x; if (run_x1 > x0) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) { tile_fill_run(linebuf, run_x1 - x0, tile_line, x0 - data->tile_x, data->tile->width); } else { tile_fill_run_alpha(linebuf, run_x1 - x0, tile_line, x0 - data->tile_x, data->tile->width, alphatab[alpha]); } } } for (k = 0; k < n_steps - 1; k++) { running_sum += steps[k].delta; run_x0 = run_x1; run_x1 = steps[k + 1].x; if (run_x1 > run_x0) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) { tile_fill_run(linebuf + (run_x0 - x0) * 3, run_x1 - run_x0, tile_line, run_x0 - data->tile_x, data->tile->width); } else { tile_fill_run_alpha(linebuf + (run_x0 - x0) * 3, run_x1 - run_x0, tile_line, run_x0 - data->tile_x, data->tile->width, alphatab[alpha]); } } } } running_sum += steps[k].delta; if (x1 > run_x1) { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) { tile_fill_run(linebuf + (run_x1 - x0) * 3, x1 - run_x1, tile_line, run_x1 - data->tile_x, data->tile->width); } else { tile_fill_run_alpha(linebuf + (run_x1 - x0) * 3, x1 - run_x1, tile_line, run_x1 - data->tile_x, data->tile->width, alphatab[alpha]); } } } } else { alpha = running_sum >> 16; if (alpha) { if (alpha >= 255) { tile_fill_run(linebuf, x1 - x0, tile_line, x0 - data->tile_x, data->tile->width); } else { tile_fill_run_alpha(linebuf, x1 - x0, tile_line, x0 - data->tile_x, data->tile->width, alphatab[alpha]); } } } data->buf += data->rowstride; } static void tile_svp_alpha_cb(void *callback_data, int y, int start, ArtSVPRenderAAStep *steps, int n_steps) { TileSVPData *data = (TileSVPData *)callback_data; art_u8 *linebuf, *tile_line; int run_x0, run_x1; art_u32 running_sum = start; int x0, x1, k, dy; int *alphatab; int alpha; linebuf = data->buf; x0 = data->x0; x1 = data->x1; alphatab = data->alphatab; dy = y - data->tile_y; dy %= data->tile->height; if (dy < 0) { dy += data->tile->height; } tile_line = data->tile->pixels + dy * data->tile->rowstride; if (n_steps > 0) { run_x1 = steps[0].x; if (run_x1 > x0) { alpha = (running_sum >> 16) & 0xff; if (alpha) { tile_fill_run_alpha(linebuf, run_x1 - x0, tile_line, x0 - data->tile_x, data->tile->width, alphatab[alpha]); } } for (k = 0; k < n_steps - 1; k++) { running_sum += steps[k].delta; run_x0 = run_x1; run_x1 = steps[k + 1].x; if (run_x1 > run_x0) { alpha = (running_sum >> 16) & 0xff; if (alpha) { tile_fill_run_alpha(linebuf + (run_x0 - x0) * 3, run_x1 - run_x0, tile_line, run_x0 - data->tile_x, data->tile->width, alphatab[alpha]); } } } running_sum += steps[k].delta; if (x1 > run_x1) { alpha = (running_sum >> 16) & 0xff; if (alpha) { tile_fill_run_alpha(linebuf + (run_x1 - x0) * 3, x1 - run_x1, tile_line, run_x1 - data->tile_x, data->tile->width, alphatab[alpha]); } } } else { alpha = (running_sum >> 16) & 0xff; if (alpha) { tile_fill_run_alpha(linebuf, x1 - x0, tile_line, x0 - data->tile_x, data->tile->width, alphatab[alpha]); } } data->buf += data->rowstride; } void tile_svp_alpha(const ArtSVP *svp, int x0, int y0, int x1, int y1, int tile_x, int tile_y, ArtPixBuf *tile, art_u8 alpha, art_u8 *buf, int rowstride) { TileSVPData data; int i, a, da; data.tile = tile; data.tile_x = tile_x; data.tile_y = tile_y; data.buf = buf; data.rowstride = rowstride; data.x0 = x0; data.x1 = x1; a = 0x8000; da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */ for (i = 0; i < 256; i++) { data.alphatab[i] = a >> 16; a += da; } if (alpha == 255) { art_svp_render_aa(svp, x0, y0, x1, y1, tile_svp_alpha_opaque_cb, &data); } else { art_svp_render_aa(svp, x0, y0, x1, y1, tile_svp_alpha_cb, &data); } } #ifdef SHM /* * Working only for 16 bits displays with 5r6g5b mask. */ ArtPixBuf * GetImagePixbuf(ZnWindow win, char *image_name, ZnImage image) { ImageBits *im_bits; BitmapBits *b_bits; int width, height; int x, y; int rowstride; art_u8 *obuf, *obptr; int bpl; art_u8 *pixels, *bptr, *bp2; art_u8 alpha; art_u16 temp; im_bits = GetImageBits(win, image_name, image); if (!im_bits->pixbuf) { b_bits = im_bits->b_bits; width = im_bits->width; height = im_bits->height; rowstride = width*4; bptr = pixels = art_alloc(rowstride * height); obuf = im_bits->pixels->data; bpl = im_bits->pixels->bytes_per_line; for (y = 0; y < height; y++) { bp2 = bptr; obptr = obuf; for (x = 0; x < width; x++) { /* * Configure the alpha value. */ alpha = GetBitmapPixel(b_bits, x, y) ? 255 : 0; /* * Dispatch the 3 color components. */ temp = ((art_u16 *)obptr)[0]; *bp2 = (temp >> 8) & 0xf8; /* r */ bp2++; *bp2 = (temp >> 3) & 0xfc; /* v */ bp2++; *bp2 = (temp << 3); /* b */ bp2++; *bp2 = alpha; bp2++; obptr += 2; } bptr += rowstride; obuf += bpl; } im_bits->pixbuf = art_pixbuf_new_rgba(pixels, width, height, rowstride); } return im_bits->pixbuf; } #endif