From fe131efdd2deb5f0672b8e18549fd076a3acff8c Mon Sep 17 00:00:00 2001 From: lecoanet Date: Fri, 12 Oct 2001 07:44:41 +0000 Subject: Suppression du code LIBART. Ajout de routines pour g�rer le texte en m�moire de texture. Ajout de routines pour g�rer les images/bitmap en m�moire de texture. --- generic/Image.c | 1570 +++++++++++++++++++++---------------------------------- 1 file changed, 598 insertions(+), 972 deletions(-) (limited to 'generic/Image.c') diff --git a/generic/Image.c b/generic/Image.c index 1474291..d3f9563 100644 --- a/generic/Image.c +++ b/generic/Image.c @@ -32,6 +32,13 @@ #include "Image.h" #include "WidgetInfo.h" #include "Geo.h" +#ifdef GLX +#include +#include +#include +#include +#include "Draw.h" +#endif static const char rcsid[] = "$Id$"; @@ -53,9 +60,12 @@ typedef struct _ImagePixmap { struct _ImagePixmap *next; } ImagePixmap; +static int image_bits_inited = 0; static Tcl_HashTable image_bits; static Tcl_HashTable bitmap_masks; -static Tcl_HashTable font_bitmaps; +#ifdef GLX +static Tcl_HashTable font_textures; +#endif /* @@ -70,7 +80,6 @@ GetImageBits(ZnWindow win, char *image_name, ZnImage image) { - static int inited = 0; Tcl_HashEntry *entry; XImage *im1, *im2, *mask; Pixmap pmap; @@ -83,9 +92,9 @@ GetImageBits(ZnWindow win, ImageBits *im_bits; ZnBool full_mask=True; - if (!inited) { + if (!image_bits_inited) { Tcl_InitHashTable(&image_bits, TCL_STRING_KEYS); - inited = 1; + image_bits_inited = 1; } entry = Tcl_FindHashEntry(&image_bits, image_name); if (entry != NULL) { @@ -94,12 +103,9 @@ GetImageBits(ZnWindow win, else { Tk_SizeOfImage(image, &width, &height); im_bits = (ImageBits *) ZnMalloc(sizeof(ImageBits)); -#ifdef LIBART - im_bits->pixbuf = NULL; -#endif #ifdef GLX im_bits->texture = 0; - im_bits->i_bits = NULL; + im_bits->t_bits = NULL; #endif im_bits->pixmaps = NULL; im_bits->b_bits = NULL; @@ -160,7 +166,7 @@ GetImageBits(ZnWindow win, else { im_bits->mask = mask; } - + entry = Tcl_CreateHashEntry(&image_bits, image_name, &new); Tcl_SetHashValue(entry, (ClientData) im_bits); } @@ -175,6 +181,9 @@ InvalidateImage(char *image_name) ImageBits *im_bits; ImagePixmap *im_pmap, *next_im_pmap; + if (!image_bits_inited) { + return; + } /* * Destroy the image entry and wait the cache fault to * reload the new one. @@ -202,14 +211,9 @@ InvalidateImage(char *image_name) ZnFree(im_bits->b_bits->pixels); ZnFree(im_bits->b_bits); } -#ifdef LIBART - if (im_bits->pixbuf) { - art_pixbuf_free(im_bits->pixbuf); - } -#endif #ifdef GLX if (im_bits->texture) { - ZnFree(im_bits->i_bits); + ZnFree(im_bits->t_bits); glDeleteTextures(1, &im_bits->texture); } #endif @@ -352,1022 +356,531 @@ GetBitmapMask(Display *dpy, } -/* - ********************************************************************************** - * - * 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; -} - - -#ifdef LIBART -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; - } +#ifdef GLX +#define MAX_GLYPHS_PER_GRAB 512 /* this is big enough for 2^9 glyph + * character sets */ - r = rgb >> 16; - g = (rgb >> 8) & 0xff; - b = rgb & 0xff; +typedef struct { + short width; + short height; + short xoffset; + short yoffset; + short advance; + unsigned char *bitmap; +} PerGlyphInfo, *PerGlyphInfoPtr; - 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; - } +typedef struct { + int min_char; + int max_char; + int max_ascent; + int max_descent; + int num_glyphs; + PerGlyphInfo glyph[1]; +} FontInfo, *FontInfoPtr; - 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++; - } -} +static FontInfoPtr fontinfo; 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) +getMetric(FontInfoPtr font, + int c, + TexGlyphInfo *tgi) { - 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)) { + PerGlyphInfoPtr glyph; + unsigned char *bitmapData; + + tgi->c = c; + if ((c < font->min_char) || (c > font->max_char)) { + tgi->width = 0; + tgi->height = 0; + tgi->xoffset = 0; + tgi->yoffset = 0; + tgi->dummy = 0; + tgi->advance = 0; 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; + glyph = &font->glyph[c - font->min_char]; + bitmapData = glyph->bitmap; + if (bitmapData) { + tgi->width = glyph->width; + tgi->height = glyph->height; + tgi->xoffset = glyph->xoffset; + tgi->yoffset = glyph->yoffset; } + else { + tgi->width = 0; + tgi->height = 0; + tgi->xoffset = 0; + tgi->yoffset = 0; + } + tgi->dummy = 0; + /* printf("\'%c\' %d\n", c, glyph->advance);*/ + tgi->advance = glyph->advance; +} - 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++; - } +int +glyphCompare(const void *a, + const void *b) +{ + unsigned char *c1 = (unsigned char *) a; + unsigned char *c2 = (unsigned char *) b; + TexGlyphInfo tgi1; + TexGlyphInfo tgi2; + + getMetric(fontinfo, *c1, &tgi1); + getMetric(fontinfo, *c2, &tgi2); + return tgi2.height - tgi1.height; } -/* 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) +placeGlyph(FontInfoPtr font, + int c, + unsigned char *texarea, + int stride, + int x, + int y) { - 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; + PerGlyphInfoPtr glyph; + unsigned char *bitmapData; + int width, height, spanLength; + int i, j; - if ((start_y > y1) || - (start_y+src_height < y0) || - (start_x > x1) || - (start_x+src_width < x0)) { + /*printf("x: %d, y: %d, c: %d, texarea: 0x%X\n", x, y, c, texarea);*/ + if ((c < font->min_char) || (c > font->max_char)) { return; } + glyph = &font->glyph[c - font->min_char]; + bitmapData = glyph->bitmap; + if (bitmapData) { + width = glyph->width; + spanLength = (width + 7) / 8; + height = glyph->height; - 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; - } + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + texarea[stride * (y+i) + x + j] = (bitmapData[i*spanLength + j/8] & (1<<(j&7))) ? 255 : 0; } - 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) +FontInfoPtr +SuckGlyphsFromServer(ZnWindow win, + ZnFont font) { - 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; - } + Display *dpy = Tk_Display(win); + XFontStruct *fontinfo = NULL; + Pixmap offscreen = 0; + XImage *image = NULL; + GC xgc = 0; + XGCValues values; + int width, height, pixwidth; + int i, j; + XCharStruct *charinfo; + XChar2b character; + unsigned char *bitmapData = NULL; + int x, y; + int numchars, spanLength; + int charWidth, charHeight, maxSpanLength; + int grabList[MAX_GLYPHS_PER_GRAB]; + int glyphsPerGrab = MAX_GLYPHS_PER_GRAB; + int numToGrab, thisglyph; + FontInfoPtr myfontinfo = NULL; - 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; + fontinfo = XQueryFont(dpy, Tk_FontId(font)); + if (!fontinfo) { + return NULL; } - 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; + numchars = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1; + if (numchars < 1) { + return NULL; } - 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; + myfontinfo = (FontInfoPtr) ZnMalloc(sizeof(FontInfo) + (numchars - 1) * sizeof(PerGlyphInfo)); + if (!myfontinfo) { + return NULL; + } + + myfontinfo->num_glyphs = numchars; + myfontinfo->min_char = fontinfo->min_char_or_byte2; + myfontinfo->max_char = fontinfo->max_char_or_byte2; + myfontinfo->max_ascent = fontinfo->max_bounds.ascent; + myfontinfo->max_descent = fontinfo->max_bounds.descent; + + width = fontinfo->max_bounds.rbearing - fontinfo->min_bounds.lbearing; + height = fontinfo->max_bounds.ascent + fontinfo->max_bounds.descent; + + maxSpanLength = (width + 7) / 8; + /* Be careful determining the width of the pixmap; the X protocol allows + pixmaps of width 2^16-1 (unsigned short size) but drawing coordinates + max out at 2^15-1 (signed short size). If the width is too large, we + need to limit the glyphs per grab. */ + if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) { + glyphsPerGrab = (1 << 15) / (8 * maxSpanLength); + } + pixwidth = glyphsPerGrab * 8 * maxSpanLength; + offscreen = XCreatePixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)), + pixwidth, height, 1); + + values.font = Tk_FontId(font); + values.background = 0; + values.foreground = 0; + xgc = XCreateGC(dpy, offscreen, GCFont | GCBackground | GCForeground, &values); + + XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height); + XSetForeground(dpy, xgc, 1); + + numToGrab = 0; + if (fontinfo->per_char == NULL) { + charinfo = &(fontinfo->min_bounds); + charWidth = charinfo->rbearing - charinfo->lbearing; + charHeight = charinfo->ascent + charinfo->descent; + spanLength = (charWidth + 7) / 8; + } + for (i = 0; i < myfontinfo->num_glyphs; i++) { + if (fontinfo->per_char != NULL) { + charinfo = &(fontinfo->per_char[i]); + charWidth = charinfo->rbearing - charinfo->lbearing; + charHeight = charinfo->ascent + charinfo->descent; + if (charWidth == 0 || charHeight == 0) { + /* Still must move raster pos even if empty character */ + myfontinfo->glyph[i].width = 0; + myfontinfo->glyph[i].height = 0; + myfontinfo->glyph[i].xoffset = 0; + myfontinfo->glyph[i].yoffset = 0; + myfontinfo->glyph[i].advance = charinfo->width; + myfontinfo->glyph[i].bitmap = NULL; + goto PossiblyDoGrab; } } - dst_linestart += dst_rowstride; - src_p += src_rowstride; - } -} + grabList[numToGrab] = i; -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; + /* XXX is this right for large fonts? */ + character.byte2 = (i + fontinfo->min_char_or_byte2) & 255; + character.byte1 = (i + fontinfo->min_char_or_byte2) >> 8; - 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++; + XDrawString16(dpy, offscreen, xgc, + -charinfo->lbearing + 8 * maxSpanLength * numToGrab, + charinfo->ascent, &character, 1); + + numToGrab++; + + PossiblyDoGrab: + if ((numToGrab >= glyphsPerGrab) || (i == myfontinfo->num_glyphs - 1)) { + image = XGetImage(dpy, offscreen, 0, 0, pixwidth, height, 1, XYPixmap); + for (j = 0; j < numToGrab; j++) { + thisglyph = grabList[j]; + if (fontinfo->per_char != NULL) { + charinfo = &(fontinfo->per_char[thisglyph]); + charWidth = charinfo->rbearing - charinfo->lbearing; + charHeight = charinfo->ascent + charinfo->descent; + spanLength = (charWidth + 7) / 8; + } + bitmapData = ZnMalloc(height * spanLength * sizeof(char)); + memset(bitmapData, 0, height * spanLength * sizeof(char)); + if (bitmapData == NULL) { + goto FreeFontAndReturn; + } + for (y = 0; y < charHeight; y++) { + for (x = 0; x < charWidth; x++) { + /* XXX The algorithm used to suck across the font ensures that + each glyph begins on a byte boundary. In theory this would + make it convienent to copy the glyph into a byte oriented + bitmap. We actually use the XGetPixel function to extract + each pixel from the image which is not that efficient. We + could either do tighter packing in the pixmap or more + efficient extraction from the image. Oh well. */ + if (XGetPixel(image, j * maxSpanLength * 8 + x, y)) { + bitmapData[y * spanLength + x / 8] |= (1 << (x & 7)); + } + } + } + myfontinfo->glyph[thisglyph].width = charWidth; + myfontinfo->glyph[thisglyph].height = charHeight; + myfontinfo->glyph[thisglyph].xoffset = charinfo->lbearing; + myfontinfo->glyph[thisglyph].yoffset = charinfo->descent; + myfontinfo->glyph[thisglyph].advance = charinfo->width; + myfontinfo->glyph[thisglyph].bitmap = bitmapData; + } + XDestroyImage(image); + numToGrab = 0; + /* do we need to clear the offscreen pixmap to get more? */ + if (i < myfontinfo->num_glyphs - 1) { + XSetForeground(dpy, xgc, 0); + XFillRectangle(dpy, offscreen, xgc, 0, 0, + 8 * maxSpanLength * glyphsPerGrab, height); + XSetForeground(dpy, xgc, 1); + } } - num -= tile_width; } + XFreeFontInfo(NULL, fontinfo, 1); + XFreeGC(dpy, xgc); + XFreePixmap(dpy, offscreen); + return myfontinfo; + + FreeFontAndReturn: + XFreeFontInfo(NULL, fontinfo, 1); + XDestroyImage(image); + XFreeGC(dpy, xgc); + XFreePixmap(dpy, offscreen); + for (i = 0; i < myfontinfo->num_glyphs; i++) { + if (myfontinfo->glyph[i].bitmap) + ZnFree(myfontinfo->glyph[i].bitmap); + } + ZnFree(myfontinfo); + return NULL; } -static void -tile_svp_aa_cb(void *callback_data, - int y, - int start, - ArtSVPRenderAAStep *steps, - int n_steps) +/* + ********************************************************************************** + * + * GetTexFont -- + * + ********************************************************************************** + */ +TexFont * +GetTexFont(ZnWindow win, + ZnFont font) { - 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; + unsigned char *glisto = " ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijmklmnopqrstuvwxyz?.;,!*:\"'èéêëïîôâàçûùü/+@#$%^&()\\-_<>\t\020\021\022\023"; + unsigned char *glist = NULL; + TexFont *txf; + TexGlyphInfo *tgi; + int i, j; + int min_glyph, max_glyph; + int gap = 1; /* gap between glyphs */ + int px, py, maxheight; + int new, width, height; + GLfloat xstep, ystep, texw, texh; + static int inited = 0; + Tcl_HashEntry *entry; - 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; + if (!inited) { + Tcl_InitHashTable(&font_textures, sizeof(ZnFont)/sizeof(int)); + inited = 1; } - 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); - } - } + entry = Tcl_FindHashEntry(&font_textures, (char *) font); + if (entry != NULL) { + return (TexFont *) Tcl_GetHashValue(entry); } else { - if (((running_sum >> 16) & 0xff) > 128) { - tile_fill_run(linebuf, x1 - x0, - tile_line, x0 - data->tile_x, data->tile->width); + txf = (TexFont *) ZnMalloc(sizeof(TexFont)); + if (txf == NULL) { + goto error; } - else { - art_rgb_fill_run(linebuf, b_r, b_g, b_b, x1 - x0); + txf->tgi = NULL; + txf->tgvi = NULL; + txf->lut = NULL; + txf->teximage = NULL; + texw = txf->tex_width = 256; /* Size of texture */ + texh = txf->tex_height = 256; + xstep = 0/*0.5 / texw*/; + ystep = 0/*0.5 / texh*/; + + txf->teximage = ZnMalloc(texw * texh * sizeof(unsigned char)); + if (txf->teximage == NULL) { + goto error; + } + memset(txf->teximage, 0x55, texw * texh * sizeof(unsigned char)); + + fontinfo = SuckGlyphsFromServer(win, font); + if (fontinfo == NULL) { + goto error; } - } - - 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; + txf->max_ascent = fontinfo->max_ascent; + txf->max_descent = fontinfo->max_descent; + txf->num_glyphs = strlen(glisto); + glist = ZnMalloc((txf->num_glyphs+1) * sizeof(unsigned char)); + strcpy(glist, glisto); - 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++; + txf->tgi = (TexGlyphInfo *) ZnMalloc(txf->num_glyphs * sizeof(TexGlyphInfo)); + if (txf->tgi == NULL) { + goto error; } - 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]); - } - } + txf->tgvi = (TexGlyphVertexInfo *) ZnMalloc(txf->num_glyphs * sizeof(TexGlyphVertexInfo)); + if (txf->tgvi == NULL) { + goto error; } - 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); + qsort(glist, txf->num_glyphs, sizeof(unsigned char), glyphCompare); + + px = gap; + py = gap; + maxheight = 0; + for (i = 0; i < txf->num_glyphs; i++) { + if (glist[i] != 0) { /* If not already processed... */ + int foundWidthFit = 0; + int c; + + /* Try to find a character from the glist that will fit on the + remaining space on the current row. */ + tgi = &txf->tgi[i]; + getMetric(fontinfo, glist[i], tgi); + width = tgi->width; + height = tgi->height; + if ((height > 0) && (width > 0)) { + for (j = i; j < txf->num_glyphs;) { + if ((height > 0) && (width > 0)) { + if (px + width + gap < texw) { + foundWidthFit = 1; + if (j != i) { + i--; /* Step back so i loop increment leaves us at same character. */ + } + break; + } + } + do { + j++; + } while (glist[j] == 0); + if (j < txf->num_glyphs) { + tgi = &txf->tgi[j]; + getMetric(fontinfo, glist[j], tgi); + width = tgi->width; + height = tgi->height; + } + } + + /* If a fit was found, use that character; otherwise, advance a line + in the texture. */ + if (foundWidthFit) { + if (height > maxheight) { + maxheight = height; + } + c = j; } 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]); + tgi = &txf->tgi[i]; + getMetric(fontinfo, glist[i], tgi); + width = tgi->width; + height = tgi->height; + + py += maxheight + gap; + px = gap; + maxheight = height; + if (py + height + gap >= texh) { + ZnWarning("Font texture overflow"); + goto error; /* Overflowed texture space */ + } + c = i; } - } - } - } - 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); + + /* Place the glyph in the texture image. */ + placeGlyph(fontinfo, glist[c], txf->teximage, texw, px, py); + + /* Assign glyph's texture coordinate. */ + tgi->x = px; + tgi->y = py; + + /* Advance by glyph width, remaining in the current line. */ + px += width + gap; } 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]); + /* No texture image; assign invalid bogus texture coordinates. */ + tgi->x = -1; + tgi->y = -1; + c = i; } + glist[c] = 0; /* Mark processed; don't process again. */ + + txf->tgvi[c].t0[0] = tgi->x / texw + xstep; + txf->tgvi[c].t0[1] = tgi->y / texh + ystep; + txf->tgvi[c].v0[0] = tgi->xoffset; + txf->tgvi[c].v0[1] = tgi->yoffset - tgi->height; + txf->tgvi[c].t1[0] = (tgi->x + tgi->width) / texw + xstep; + txf->tgvi[c].t1[1] = tgi->y / texh + ystep; + txf->tgvi[c].v1[0] = (tgi->xoffset + tgi->width); + txf->tgvi[c].v1[1] = tgi->yoffset - tgi->height; + txf->tgvi[c].t2[0] = (tgi->x + tgi->width) / texw + xstep; + txf->tgvi[c].t2[1] = (tgi->y + tgi->height) / texh + ystep; + txf->tgvi[c].v2[0] = (tgi->xoffset + tgi->width); + txf->tgvi[c].v2[1] = tgi->yoffset; + txf->tgvi[c].t3[0] = tgi->x / texw + xstep; + txf->tgvi[c].t3[1] = (tgi->y + tgi->height) / texh + ystep; + txf->tgvi[c].v3[0] = tgi->xoffset; + txf->tgvi[c].v3[1] = tgi->yoffset; + txf->tgvi[c].advance = tgi->advance; } } - } - 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]); + + min_glyph = txf->tgi[0].c; + max_glyph = txf->tgi[0].c; + for (i = 1; i < txf->num_glyphs; i++) { + if (txf->tgi[i].c < min_glyph) { + min_glyph = txf->tgi[i].c; } - } - } - - 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]); + if (txf->tgi[i].c > max_glyph) { + max_glyph = txf->tgi[i].c; } } + /* printf("min glyph: (%d) \"%c\", max glyph: (%d) \"%c\"\n", + min_glyph, min_glyph, max_glyph, max_glyph);*/ + txf->min_glyph = min_glyph; + txf->range = max_glyph - min_glyph + 1; - 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]); - } - } + txf->lut = (TexGlyphVertexInfo **) ZnMalloc(txf->range * sizeof(TexGlyphVertexInfo *)); + memset(txf->lut, 0, txf->range * sizeof(TexGlyphVertexInfo *)); + if (txf->lut == NULL) { + goto error; } - 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]); - } + for (i = 0; i < txf->num_glyphs; i++) { + txf->lut[txf->tgi[i].c - txf->min_glyph] = &txf->tgvi[i]; } - } - 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]); + + glGenTextures(1, &txf->texobj); + glBindTexture(GL_TEXTURE_2D, txf->texobj); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4, 256, 256, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage); + + for (i = 0; i < fontinfo->num_glyphs; i++) { + if (fontinfo->glyph[i].bitmap) + ZnFree(fontinfo->glyph[i].bitmap); } + ZnFree(fontinfo); + ZnFree(glist); + + entry = Tcl_CreateHashEntry(&font_textures, (char *) font, &new); + Tcl_SetHashValue(entry, (ClientData) txf); + return txf; } - 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); + error: + if (glist) { + ZnFree(glist); + } + if (fontinfo) { + for (i = 0; i < fontinfo->num_glyphs; i++) { + if (fontinfo->glyph[i].bitmap) + ZnFree(fontinfo->glyph[i].bitmap); + } + ZnFree(fontinfo); } -} - -/* - * 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; + if (txf) { + if (txf->tgi) { + ZnFree(txf->tgi); } - - im_bits->pixbuf = art_pixbuf_new_rgba(pixels, width, height, rowstride); + if (txf->tgvi) { + ZnFree(txf->tgvi); + } + if (txf->lut) { + ZnFree(txf->lut); + } + if (txf->teximage) { + ZnFree(txf->teximage); + } + ZnFree(txf); } - return im_bits->pixbuf; + return NULL; } -#endif -#ifdef GLX /* - * Working only for 16 bits displays with 5r6g5b mask. - * Need more work at least to support 24 and 32 bit displays. + * Working only for 16 bits displays with 5r6g5b mask, + * and 24/32 bits displays. Byte ordering ok on Intel + * plateform only. */ void From5r6g5b(unsigned char *data, @@ -1377,7 +890,7 @@ From5r6g5b(unsigned char *data, int t_width, int t_height, BitmapBits *b_bits, - unsigned char *i_bits) + unsigned char *t_bits) { int x, y; int rowstride = t_width * 4; @@ -1386,7 +899,7 @@ From5r6g5b(unsigned char *data, unsigned char alpha; unsigned short temp; - bptr = i_bits; + bptr = t_bits; for (y = 0; y < height; y++) { bp2 = bptr; @@ -1396,7 +909,7 @@ From5r6g5b(unsigned char *data, * Configure the alpha value. */ alpha = GetBitmapPixel(b_bits, x, y) ? 255 : 0; - alpha = 255; + /* * Dispatch the 3 color components. */ @@ -1430,6 +943,63 @@ From5r6g5b(unsigned char *data, } } +void +From8r8g8b(unsigned char *data, + int width, + int height, + int bytes_per_line, + int t_width, + int t_height, + BitmapBits *b_bits, + unsigned char *t_bits) +{ + int x, y; + int rowstride = t_width * 4; + unsigned char *obptr; + unsigned char *bptr, *bp2; + unsigned char alpha; + + bptr = t_bits; + + for (y = 0; y < height; y++) { + bp2 = bptr; + obptr = data; + for (x = 0; x < width; x++) { + /* + * Configure the alpha value. + */ + alpha = GetBitmapPixel(b_bits, x, y) ? 255 : 0; + + /* + * Dispatch the 3 color components. + * Be careful the Red and Blue are swapped it works on an Intel + * plateform but may need some more tests to be fully generic. + */ + *bp2++ = obptr[2]; /* r */ + *bp2++ = obptr[1]; /* v */ + *bp2++ = obptr[0]; /* b */ + obptr += 4; + *bp2++ = alpha; + } + for (x = width; x < t_width; x++) { + *bp2 = 0; + bp2++; + *bp2 = 0; + bp2++; + *bp2 = 0; + bp2++; + *bp2 = 0; + bp2++; + } + bptr += rowstride; + data += bytes_per_line; + } + for (y = height; y < t_height; y++) { + memset(bptr, 0, rowstride); + bptr += rowstride; + } +} + static int To2Power(int a) { @@ -1448,19 +1018,27 @@ GetImageTexture(ZnWindow win, { ImageBits *im_bits; int t_width, t_height; + int depth = Tk_Depth(win); + /* int error;*/ im_bits = GetImageBits(win, image_name, image); - if (!im_bits->i_bits) { + if (!im_bits->t_bits) { t_width = To2Power(im_bits->width); t_height = To2Power(im_bits->height); im_bits->s = im_bits->width / (ZnReal) t_width; im_bits->t = im_bits->height / (ZnReal) t_height; - im_bits->i_bits = ZnMalloc(t_width * 4 * t_height); - From5r6g5b(im_bits->pixels->data, im_bits->width, im_bits->height, - im_bits->pixels->bytes_per_line, t_width, t_height, - im_bits->b_bits, im_bits->i_bits); + im_bits->t_bits = ZnMalloc(t_width * 4 * t_height); + if (depth == 16) { + From5r6g5b(im_bits->pixels->data, im_bits->width, im_bits->height, + im_bits->pixels->bytes_per_line, t_width, t_height, + im_bits->b_bits, im_bits->t_bits); + } + else if (depth == 24) { + From8r8g8b(im_bits->pixels->data, im_bits->width, im_bits->height, + im_bits->pixels->bytes_per_line, t_width, t_height, + im_bits->b_bits, im_bits->t_bits); + } - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &im_bits->texture); /*printf("creation texture %d pour image %s\n", im_bits->texture, image_name);*/ glBindTexture(GL_TEXTURE_2D, im_bits->texture); @@ -1468,12 +1046,60 @@ GetImageTexture(ZnWindow win, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - t_width, t_height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, - im_bits->i_bits); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, t_width, t_height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, im_bits->t_bits); + /* + error = glGetError(); + if (error != GL_NO_ERROR) { + printf("GetImageTexture: %s\n", gluErrorString(error)); + } + */ } return im_bits; } + +BitmapBits * +GetBitmapTexture(Display *dpy, + Pixmap bitmap) +{ + BitmapBits *b_bits; + int t_width, t_height; + int i, j; + unsigned char *o, *ostart, *d, *dstart; + + b_bits = GetBitmapMask(dpy, bitmap); + if (!b_bits->texture) { + t_width = To2Power(b_bits->width); + t_height = To2Power(b_bits->height); + b_bits->s = b_bits->width / (ZnReal) t_width; + b_bits->t = b_bits->height / (ZnReal) t_height; + b_bits->t_bits = ZnMalloc(t_width * t_height); + memset(b_bits->t_bits, 0, t_width * t_height); + + ostart = b_bits->pixels; + dstart = b_bits->t_bits; + for (i = 0; i < b_bits->height; i++) { + d = dstart; + o = ostart; + for (j = 0; j < b_bits->width; j++) { + *d++ = GetBitmapPixel(b_bits, j, i) ? 255 : 0; + } + ostart += b_bits->rowstride; + dstart += t_width; + } + + glGenTextures(1, &b_bits->texture); + glBindTexture(GL_TEXTURE_2D, b_bits->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4, t_width, t_height, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, b_bits->t_bits); + } + + return b_bits; +} + #endif -- cgit v1.1