From d7c5b765038579619622377bb7a8bed709744825 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Thu, 16 May 2002 08:33:27 +0000 Subject: Re�criture compl�te de la gestion du chargement/lib�ration des images, des bitmaps et des fontes. On n'utilise plus Tk que pour initialiser l'image, le compte de r�f�rence est gard� en local. Les images et bitmap sont sp�cialis�es par display pour X, par fen�tre pour GL. Les fontes sont sp�cialis�es par fen�tres en GL. Le code de modification dynamique des images propos� par Tk n'est plus pris en compte. Les textures et la m�moire utilis�es par les images/bitmap/fontes sont lib�r�es d�s que possible, r�sultant en une bien meilleure utilisation des ressources (surtout en ce qui concerne les textures). Ces modifs corrigent le bug de dessin des images/fontes observ� sous GL avec deux ou plusieurs Zinc cr��s simultan�ment ou cons�cutivement dans la M�ME application. --- generic/Image.c | 1576 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 1030 insertions(+), 546 deletions(-) (limited to 'generic/Image.c') diff --git a/generic/Image.c b/generic/Image.c index 52ba2eb..3ef66b4 100644 --- a/generic/Image.c +++ b/generic/Image.c @@ -45,240 +45,642 @@ 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 int image_bits_inited = 0; -static Tcl_HashTable image_bits; -static Tcl_HashTable bitmap_masks; +static int images_inited = 0; +static Tcl_HashTable images; #ifdef GLX static Tcl_HashTable font_textures; #endif +typedef struct _ImageStruct { + union { + struct { + Pixmap pixmap; + Pixmap mask_pmap; + Display *dpy; + } x; + struct { + GLuint texobj; + struct _WidgetInfo *wi; + } gl; + } i; + struct _ImageBits *bits; + + /* Bookkeeping */ + + ZnBool for_gl; + int refcount; + struct _ImageStruct *next; +} ImageStruct, *Image; + + +typedef struct _ImageBits { + int width; + int height; + unsigned char *bpixels; /* Needed at least to know the bounds (Pick), or if + * the image is a bitmap. Can be NULL if no mask is + * defined for the image (i.e the image is + * rectangular) and the image is not a bitmap. */ + int rowstride; +#ifdef GLX + ZnReal t; /* Texture parameters for the image. */ + ZnReal s; +#endif + + /* Bookeeping */ + + Tcl_HashEntry *hash; /* From this it is easy to get the image/bitmap + * name. */ + XImage *ipixels; /* Keep this to create textures and pixmaps as + * needed. NULL if the image is a bitmap. This + * can be tested to tell if this is an image or + * a bitmap. */ + XImage *mask; /* Keep this to build special clip mask in X (Icon). + * Can be NULL if no mask is defined for the image + * (i.e the image is rectangular) or if the image + * is a bitmap. */ +#ifdef GLX + int t_width; /* Texture size used for this image. */ + int t_height; + unsigned char *t_bits; /* Can be NULL if texture is not used (no GL + * rendering active on this image). */ +#endif + Image images; /* Linked list of widget/display dependant + * specializations of this image. If NULL, the + * image has no specialization and can be freed. */ +} ImageBits; + + +/* + * Working only for 16 bits displays with 5r6g5b mask, + * and 24/32 bits displays. Byte ordering ok on Intel + * plateform only. + */ +static void +From5r6g5b(unsigned char *data, + int width, + int height, + int bytes_per_line, + int t_width, + int t_height, + unsigned char *bpixels, + int bstride, + unsigned char *t_bits) +{ + int x, y; + int rowstride = t_width * 4; + unsigned char *obptr; + unsigned char *bptr, *bp2; + unsigned char alpha; + unsigned short temp; + + bptr = t_bits; + + for (y = 0; y < height; y++) { + bp2 = bptr; + obptr = data; + for (x = 0; x < width; x++) { + /* + * Configure the alpha value. + */ + alpha = ZnGetBitmapPixel(bpixels, bstride, x, y) ? 255 : 0; + + /* + * Dispatch the 3 color components. + */ + temp = ((unsigned short *)obptr)[0]; + *bp2 = (temp >> 8) & 0xf8; /* r */ + bp2++; + *bp2 = (temp >> 3) & 0xfc; /* v */ + bp2++; + *bp2 = (temp << 3); /* b */ + bp2++; + *bp2 = alpha; + bp2++; + obptr += 2; + } + 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 void +From8r8g8b(unsigned char *data, + int width, + int height, + int bytes_per_line, + int t_width, + int t_height, + unsigned char *bpixels, + int bstride, + 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. + */ + if (bpixels) { + alpha = ZnGetBitmapPixel(bpixels, bstride, x, y) ? 255 : 0; + } + else { + alpha = 255; + } + + /* + * 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) +{ + int result = 1; + + while (result < a) { + result *= 2; + } + return result; +} + + /* ********************************************************************************** * - * ValidateImage -- - * Make sure an image is ok for use in an attribute - * and do any needed housekeeping. + * ZnGetImage -- * ********************************************************************************** */ -int -ValidateImage(WidgetInfo *wi, - void *item_or_field, - char *image_name, - Tk_ImageChangedProc *image_proc, - Tk_Image *image_ref, - char *msg) +static void +InvalidateImage(ClientData client_data, + int x, + int y, + int width, + int height, + int image_width, + int image_height) +{ + /* + * Void stub that keeps the Tk image mecanism happy. Zinc does + * _not_ implement image update. + */ +} + +static void +GatherImageBits(WidgetInfo *wi, + Tk_Image tkimage, + ImageBits *bits) { - Tk_Image image; - int w, h, status = ZN_OK; + Pixmap pmap; + int depth = DefaultDepthOfScreen(wi->screen); + int x, y; + unsigned char *line; + GC gc; + XImage *im1, *im2; + ZnBool full_mask=True; + + /* + * Nothing known about this image, collect the image bits. + */ + pmap = XCreatePixmap(wi->dpy, RootWindowOfScreen(wi->screen), + bits->width, bits->height, depth); + gc = XCreateGC(wi->dpy, pmap, 0, NULL); + XSetForeground(wi->dpy, gc, 0); + XFillRectangle(wi->dpy, pmap, gc, 0, 0, bits->width, bits->height); + Tk_RedrawImage(tkimage, 0, 0, bits->width, bits->height, pmap, 0, 0); + im1 = bits->ipixels = XGetImage(wi->dpy, pmap, 0, 0, + bits->width, bits->height, ~0L, ZPixmap); - if (strcmp(image_name, "") != 0) { - image = Tk_GetImage(wi->interp, wi->win, image_name, - image_proc, (ClientData) item_or_field); - /* - * The name will not be in sync with the image in - * these cases. - */ - if (image == NULL) { + XSetForeground(wi->dpy, gc, 1); + XFillRectangle(wi->dpy, pmap, gc, 0, 0, bits->width, bits->height); + Tk_RedrawImage(tkimage, 0, 0, bits->width, bits->height, pmap, 0, 0); + im2 = XGetImage(wi->dpy, pmap, 0, 0, bits->width, bits->height, ~0L, ZPixmap); + XFreePixmap(wi->dpy, pmap); + + /* + * The image structure can be setup locally (TODO). + */ + XFreeGC(wi->dpy, gc); + pmap = XCreatePixmap(wi->dpy, RootWindowOfScreen(wi->screen), + bits->width, bits->height, 1); + gc = XCreateGC(wi->dpy, pmap, 0, NULL); + XSetForeground(wi->dpy, gc, 0); + XFillRectangle(wi->dpy, pmap, gc, 0, 0, bits->width, bits->height); + XFreeGC(wi->dpy, gc); + bits->mask = XGetImage(wi->dpy, pmap, 0, 0, bits->width, bits->height, 1, XYPixmap); + XFreePixmap(wi->dpy, pmap); + + bits->rowstride = bits->mask->bytes_per_line; + bits->bpixels = ZnMalloc(bits->height * bits->rowstride); + memset(bits->bpixels, 0, bits->height * bits->rowstride); + line = bits->bpixels; + for (y = 0; y < bits->height; y++) { + for (x = 0; x < bits->width; x++) { + if (XGetPixel(im1, x, y) == XGetPixel(im2, x, y)) { + XPutPixel(bits->mask, x, y, 1L); + line[x >> 3] |= 0x80 >> (x & 7); + } + else { + full_mask = False; + } + } + line += bits->rowstride; + } + + XDestroyImage(im2); + if (full_mask) { + XDestroyImage(bits->mask); + bits->mask = NULL; + ZnFree(bits->bpixels); + bits->bpixels = NULL; + } +} + +static Image +GetImageInstance(WidgetInfo *wi, + ImageBits *bits) +{ + int depth = DefaultDepthOfScreen(wi->screen); + ZnBool for_gl = wi->render>0; + XGCValues values; + GC gc; + Image image; + + /* + * Try to find an image instance that fits this widget/display. + */ + for (image = bits->images; image != NULL; image = image->next) { + if (image->for_gl == for_gl) { + if (for_gl && (image->i.gl.wi == wi)) { + image->refcount++; + return image; + } + else if (!for_gl && (image->i.x.dpy == wi->dpy)) { + image->refcount++; + return image; + } + } + } + /* + * Create a new instance for this case. + */ + image = ZnMalloc(sizeof(ImageStruct)); + image->bits = bits; + image->refcount = 1; + image->for_gl = for_gl; + if (image->for_gl) { +#ifdef GLX + image->i.gl.wi = wi; + image->i.gl.texobj = 0; + } +#endif + else { + image->i.x.dpy = wi->dpy; + image->i.x.pixmap = XCreatePixmap(wi->dpy, RootWindowOfScreen(wi->screen), + bits->width, bits->height, depth); + gc = XCreateGC(wi->dpy, image->i.x.pixmap, 0, NULL); + XPutImage(wi->dpy, image->i.x.pixmap, gc, bits->ipixels, 0, 0, 0, 0, + bits->width, bits->height); + XFreeGC(wi->dpy, gc); + if (bits->mask) { + image->i.x.mask_pmap = XCreatePixmap(wi->dpy, RootWindowOfScreen(wi->screen), + bits->width, bits->height, 1); + values.foreground = 1; + values.background = 0; + gc = XCreateGC(wi->dpy, image->i.x.mask_pmap, + GCForeground|GCBackground, &values); + XPutImage(wi->dpy, image->i.x.mask_pmap, gc, bits->mask, 0, 0, 0, 0, + bits->width, bits->height); + XFreeGC(wi->dpy, gc); + } + else { + image->i.x.mask_pmap = None; + } + } + image->next = bits->images; + bits->images = image; + + return image; +} + +ZnImage +ZnGetImage(WidgetInfo *wi, + char *image_name) +{ + Tcl_HashEntry *entry; + int new; + ImageBits *bits; + Tk_Image tkimage; + + /*printf("ZnGetImage: %s\n", image_name);*/ + if (!images_inited) { + Tcl_InitHashTable(&images, TCL_STRING_KEYS); + images_inited = 1; + } + entry = Tcl_FindHashEntry(&images, image_name); + if (entry != NULL) { + /*printf("Image %s déjà connue\n", image_name);*/ + bits = (ImageBits *) Tcl_GetHashValue(entry); + } + else { + /*printf("Nouvelle Image %s\n", image_name);*/ + if (strcmp(image_name, "") == 0) { + return ZnUnspecifiedImage; + } + bits = ZnMalloc(sizeof(ImageBits)); + tkimage = Tk_GetImage(wi->interp, wi->win, image_name, + InvalidateImage, (ClientData) bits); + if (tkimage == NULL) { im_val_err: - image = ZnUnspecifiedImage; - /*Tcl_AppendResult(wi->interp, "unknown or bogus image \"", - image_name, "\" in ", msg, NULL); - status = ZN_ERROR; */ + ZnFree(bits); ZnWarning("unknown or bogus image \""); ZnWarning(image_name); - ZnWarning("\" in "); - ZnWarning(msg); - ZnWarning("\n"); - status = ZN_OK; + ZnWarning("\"\n"); + return ZnUnspecifiedImage; } else { - Tk_SizeOfImage(image, &w, &h); - if ((w == 0) || (h == 0)) { + Tk_SizeOfImage(tkimage, &bits->width, &bits->height); + if ((bits->width == 0) || (bits->height == 0)) { + Tk_FreeImage(tkimage); goto im_val_err; } } +#ifdef GLX + bits->t_bits = NULL; +#endif + bits->images = NULL; + bits->mask = NULL; + bits->bpixels = NULL; + entry = Tcl_CreateHashEntry(&images, image_name, &new); + bits->hash = entry; + Tcl_SetHashValue(entry, (ClientData) bits); } - else { - image = ZnUnspecifiedImage; - } - if (*image_ref != ZnUnspecifiedImage) { - Tk_FreeImage(*image_ref); + + if (!bits->ipixels) { + GatherImageBits(wi, tkimage, bits); + Tk_FreeImage(tkimage); } - *image_ref = image; - - return status; + return GetImageInstance(wi, bits); } - /* ********************************************************************************** * - * GetImageBits -- + * ZnGetBitmap -- * ********************************************************************************** */ -ImageBits * -GetImageBits(ZnWindow win, - char *image_name, - ZnImage image) +ZnImage +ZnGetBitmap(WidgetInfo *wi, + char *bitmap_name) { Tcl_HashEntry *entry; - XImage *im1, *im2, *mask; + ImageBits *bits; Pixmap pmap; - Display *dpy = Tk_Display(win); - int depth = Tk_Depth(win); + XImage *mask; + Image image; + ZnBool for_gl = wi->render>0; int x, y, new, width, height; unsigned char *line; - XGCValues values; - GC gc; - ImageBits *im_bits; - ZnBool full_mask=True; - /* printf("GetImageBits: %s\n", image_name);*/ - if (!image_bits_inited) { - Tcl_InitHashTable(&image_bits, TCL_STRING_KEYS); - image_bits_inited = 1; + /*printf("ZnGetBitmap: %s\n", bitmap_name);*/ + if (!images_inited) { + Tcl_InitHashTable(&images, TCL_STRING_KEYS); + images_inited = 1; } - entry = Tcl_FindHashEntry(&image_bits, image_name); + entry = Tcl_FindHashEntry(&images, bitmap_name); if (entry != NULL) { - im_bits = (ImageBits *) Tcl_GetHashValue(entry); + bits = (ImageBits *) Tcl_GetHashValue(entry); } else { - Tk_SizeOfImage(image, &width, &height); - im_bits = (ImageBits *) ZnMalloc(sizeof(ImageBits)); + pmap = Tk_GetBitmap(wi->interp, wi->win, Tk_GetUid(bitmap_name)); + if (pmap == ZnUnspecifiedImage) { + return ZnUnspecifiedImage; + } + Tk_SizeOfBitmap(wi->dpy, pmap, &width, &height); + bits = ZnMalloc(sizeof(ImageBits)); + bits->width = width; + bits->height = height; #ifdef GLX - im_bits->texture = 0; - im_bits->t_bits = NULL; + bits->t_bits = 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; + bits->images = NULL; + bits->mask = NULL; + bits->bpixels = NULL; + bits->ipixels = NULL; + mask = XGetImage(wi->dpy, pmap, 0, 0, width, height, 1L, XYPixmap); + bits->rowstride = mask->bytes_per_line; + bits->bpixels = ZnMalloc(height * bits->rowstride); + memset(bits->bpixels, 0, height * bits->rowstride); + line = bits->bpixels; 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); + if (XGetPixel(mask, x, y)) { line[x >> 3] |= 0x80 >> (x & 7); } - else { - full_mask = False; - } } - line += im_bits->b_bits->rowstride; + line += bits->rowstride; } + XDestroyImage(mask); + entry = Tcl_CreateHashEntry(&images, bitmap_name, &new); + Tcl_SetHashValue(entry, (ClientData) bits); + bits->hash = entry; + } - XDestroyImage(im2); - if (full_mask) { - XDestroyImage(mask); - im_bits->mask = ZnUnspecifiedPattern; + /* + * Try to find an image instance that fits this widget/display. + */ + for (image = bits->images; image != NULL; image = image->next) { + if (image->for_gl == for_gl) { + if (for_gl && (image->i.gl.wi == wi)) { + image->refcount++; + return image; + } + else if (!for_gl && (image->i.x.dpy == wi->dpy)) { + image->refcount++; + return image; + } + } + } + + /* + * Create a new instance for this widget/display conf. + */ + image = ZnMalloc(sizeof(ImageStruct)); + image->bits = bits; + image->refcount = 1; + image->for_gl = for_gl; + if (image->for_gl) { +#ifdef GLX + image->i.gl.wi = wi; + image->i.gl.texobj = 0; + } +#endif + else { + image->i.x.dpy = wi->dpy; + image->i.x.mask_pmap = None; + if (bits->images == NULL) { + /* + * For the first one, the Tk_GetBitmap call has already been done. + */ + image->i.x.pixmap = pmap; } else { - im_bits->mask = mask; + /* + * Need to get a pixmap that match this dpy. + */ + image->i.x.pixmap = Tk_GetBitmap(wi->interp, wi->win, bitmap_name); } - - entry = Tcl_CreateHashEntry(&image_bits, image_name, &new); - Tcl_SetHashValue(entry, (ClientData) im_bits); } + image->next = bits->images; + bits->images = image; - return im_bits; + return image; } + +/* + ********************************************************************************** + * + * ZnGetImageByValue -- + * + ********************************************************************************** + */ +ZnImage +ZnGetImageByValue(ZnImage image) +{ + ((Image) image)->refcount++; + return image; +} + +/* + ********************************************************************************** + * + * ZnFreeImage -- + * + ********************************************************************************** + */ void -InvalidateImage(char *image_name) +ZnFreeImage(ZnImage image) { - Tcl_HashEntry *entry; - ImageBits *im_bits; - ImagePixmap *im_pmap, *next_im_pmap; - - if (!image_bits_inited) { + Image prev, scan, this = ((Image) image); + ImageBits *bits = this->bits; + + /* + * Search the instance in the list. + */ + for (prev=NULL, scan=bits->images; (scan!=NULL)&&(scan!=this); + prev=scan, scan=scan->next); + if (scan != this) { + return; /* Not found ? */ + } + + this->refcount--; + if (this->refcount != 0) { return; } + /* - * Destroy the image entry and wait the cache fault to - * reload the new one. + * Unlink the deleted image instance. */ - /*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); + if (prev == NULL) { + bits->images = this->next; + } + else { + prev->next = this->next; + } + if (this->for_gl) { + if (this->i.gl.texobj) { + glDeleteTextures(1, &this->i.gl.texobj); } - 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; + } + else if (bits->ipixels) { + /* + * This is an image, we need to free the pixmaps. + */ + if (this->i.x.pixmap != None) { + XFreePixmap(this->i.x.dpy, this->i.x.pixmap); } - if (im_bits->b_bits) { - ZnFree(im_bits->b_bits->pixels); - ZnFree(im_bits->b_bits); + if (this->i.x.mask_pmap != None) { + XFreePixmap(this->i.x.dpy, this->i.x.mask_pmap); } -#ifdef GLX - if (im_bits->texture) { - ZnFree(im_bits->t_bits); - glDeleteTextures(1, &im_bits->texture); + } + else { + /* + * This is a bitmap ask Tk to free the resource. + */ + Tk_FreeBitmap(this->i.x.dpy, this->i.x.pixmap); + } + ZnFree(this); + + /* + * No clients for this image, it can be freed. + */ + if (bits->images == NULL) { + /*printf("destruction complète de l'image %s\n", ZnNameOfImage(this));*/ + if (bits->t_bits) { + ZnFree(bits->t_bits); } -#endif - ZnFree(im_bits); - Tcl_DeleteHashEntry(entry); + if (bits->mask) { + XDestroyImage(bits->mask); + } + if (bits->ipixels) { + XDestroyImage(bits->ipixels); + } + if (bits->bpixels) { + ZnFree(bits->bpixels); + } + Tcl_DeleteHashEntry(bits->hash); + ZnFree(bits); } } @@ -286,141 +688,242 @@ InvalidateImage(char *image_name) /* ********************************************************************************** * - * GetImagePixmap -- + * ZnNameOfImage -- * ********************************************************************************** */ -Pixmap -GetImagePixmap(ZnWindow win, - char *image_name, - ZnImage image, - Pixmap *mask_pmap) +char * +ZnNameOfImage(ZnImage image) { - 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 Tcl_GetHashKey(&images, ((Image) image)->bits->hash); +} + + +/* + ********************************************************************************** + * + * ZnSizeOfImage -- + * + ********************************************************************************** + */ +void +ZnSizeOfImage(ZnImage image, + int *width, + int *height) +{ + Image im = (Image) image; + *width = im->bits->width; + *height = im->bits->height; +} + + +/* + ********************************************************************************** + * + * ZnImagePattern -- + * + ********************************************************************************** + */ +char * +ZnImagePattern(ZnImage image, + int *stride) +{ + if (stride) { + *stride = ((Image) image)->bits->rowstride; } + return ((Image) image)->bits->bpixels; +} - return pixmap; +/* + ********************************************************************************** + * + * ZnImageIsBitmap -- + * + ********************************************************************************** + */ +ZnBool +ZnImageIsBitmap(ZnImage image) +{ + return (((Image) image)->bits->ipixels == NULL); } +/* + ********************************************************************************** + * + * ZnImageMask -- + * + ********************************************************************************** + */ +XImage * +ZnImageMask(ZnImage image) +{ + return ((Image) image)->bits->mask; +} /* ********************************************************************************** * - * GetBitmapMask -- + * ZnImagePixmap -- * ********************************************************************************** */ -BitmapBits * -GetBitmapMask(Display *dpy, - Pixmap bitmap) +Pixmap +ZnImagePixmap(ZnImage image, + Pixmap *mask_pmap) { - 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; + if (((Image) image)->for_gl) { + return None; } - key.dpy = dpy; - key.bitmap = bitmap; - entry = Tcl_FindHashEntry(&bitmap_masks, (char *) &key); - if (entry != NULL) { - b_bits = (BitmapBits *) Tcl_GetHashValue(entry); + if (mask_pmap) { + *mask_pmap = ((Image) image)->i.x.mask_pmap; } - 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); + return ((Image) image)->i.x.pixmap; +} + +/* + ********************************************************************************** + * + * ZnImageTex -- + * + ********************************************************************************** + */ +#ifdef GLX +GLuint +ZnImageTex(ZnImage image, + ZnReal *t, + ZnReal *s) +{ + Image this = (Image) image; + ImageBits *bits = this->bits; + ZnBool is_bmap = ZnImageIsBitmap(image); + int depth, t_size; + + if (!this->for_gl) { + return 0; + } + if (!bits->t_bits) { + /*printf("chargement texture pour image %s\n", ZnNameOfImage(this));*/ + bits->t_width = To2Power(bits->width); + bits->t_height = To2Power(bits->height); + bits->s = bits->width / (ZnReal) bits->t_width; + bits->t = bits->height / (ZnReal) bits->t_height; + if (is_bmap) { + int i, j; + unsigned char *ostart, *dstart, *d, *o; + + t_size = bits->t_width * bits->t_height; + bits->t_bits = ZnMalloc(t_size); + memset(bits->t_bits, 0, t_size); + ostart = bits->bpixels; + dstart = bits->t_bits; + for (i = 0; i < bits->height; i++) { + d = dstart; + o = ostart; + for (j = 0; j < bits->width; j++) { + *d++ = ZnGetBitmapPixel(bits->bpixels, bits->rowstride, j, i) ? 255 : 0; } + ostart += bits->rowstride; + dstart += bits->t_width; + } + } + else { + t_size = bits->t_width * 4 * bits->t_height; + bits->t_bits = ZnMalloc(t_size); + if (this->for_gl) { + depth = DefaultDepthOfScreen(this->i.gl.wi->screen); + } + else { + depth = DefaultDepthOfScreen(DefaultScreenOfDisplay(this->i.x.dpy)); + } + if (depth == 16) { + From5r6g5b(bits->ipixels->data, bits->width, bits->height, + bits->ipixels->bytes_per_line, bits->t_width, bits->t_height, + bits->bpixels, bits->rowstride, bits->t_bits); + } + else if ((depth == 24) || (depth == 32)) { + From8r8g8b(bits->ipixels->data, bits->width, bits->height, + bits->ipixels->bytes_per_line, bits->t_width, bits->t_height, + bits->bpixels, bits->rowstride, bits->t_bits); } - 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; + if (!this->i.gl.texobj) { + glGenTextures(1, &this->i.gl.texobj); + /*printf("creation texture %d pour image %s\n", + this->i.gl.texobj, ZnNameOfImage(this));*/ + glBindTexture(GL_TEXTURE_2D, this->i.gl.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); + if (ZnImageIsBitmap(image)) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4, + this->bits->t_width, this->bits->t_height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, this->bits->t_bits); + } + else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + this->bits->t_width, this->bits->t_height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, this->bits->t_bits); + } + glBindTexture(GL_TEXTURE_2D, 0); + } + *t = this->bits->t; + *s = this->bits->s; + return this->i.gl.texobj; } +#endif + #ifdef GLX +/* Copyright (c) Mark J. Kilgard, 1997. */ + +/* This program is freely distributable without licensing fees and is + provided without guarantee or warrantee expressed or implied. This + program is -not- in the public domain. */ + #define MAX_GLYPHS_PER_GRAB 512 /* this is big enough for 2^9 glyph * character sets */ typedef struct { + unsigned short c; /* Potentially support 16-bit glyphs. */ + unsigned char width; + unsigned char height; + char xoffset; + char yoffset; + char advance; + char dummy; /* Space holder for alignment reasons. */ + short x; + short y; +} TexGlyphInfo; + +typedef struct _TexFontInfo { + GLuint texobj; + struct _TexFont *txf; + WidgetInfo *wi; + int refcount; + struct _TexFontInfo *next; +} TexFontInfo; + +typedef struct _TexFont { + TexFontInfo *tfi; + ZnFont tkfont; + int tex_width; + int tex_height; + int max_ascent; + int max_descent; + int num_glyphs; + int min_glyph; + int range; + unsigned char *teximage; + TexGlyphInfo *tgi; + ZnTexGVI *tgvi; + ZnTexGVI **lut; + Tcl_HashEntry *hash; +} TexFont; + +typedef struct { short width; short height; short xoffset; @@ -504,7 +1007,8 @@ placeGlyph(FontInfoPtr font, int width, height, spanLength; int i, j; - /*printf("x: %d, y: %d, c: %d, texarea: 0x%X\n", x, y, c, texarea);*/ + /*printf("x: %d, y: %d, c: %d, texarea: 0x%X, stride: %d\n", + x, y, c, texarea, stride);*/ if ((c < font->min_char) || (c > font->max_char)) { return; } @@ -514,10 +1018,9 @@ placeGlyph(FontInfoPtr font, width = glyph->width; spanLength = (width + 7) / 8; height = glyph->height; - 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; + texarea[stride * (y+i) + x + j] = (bitmapData[i*spanLength + j/8] & (1<<(j&7))) ? 255 : 0; } } } @@ -637,10 +1140,10 @@ SuckGlyphsFromServer(ZnWindow win, spanLength = (charWidth + 7) / 8; } bitmapData = ZnMalloc(height * spanLength * sizeof(char)); - memset(bitmapData, 0, height * spanLength * sizeof(char)); if (bitmapData == NULL) { goto FreeFontAndReturn; } + memset(bitmapData, 0, height * spanLength * sizeof(char)); for (y = 0; y < charHeight; y++) { for (x = 0; x < charWidth; x++) { /* XXX The algorithm used to suck across the font ensures that @@ -687,59 +1190,144 @@ SuckGlyphsFromServer(ZnWindow win, if (myfontinfo->glyph[i].bitmap) ZnFree(myfontinfo->glyph[i].bitmap); } - ZnFree(myfontinfo); - return NULL; + ZnFree(myfontinfo); + return NULL; +} + +/* + ********************************************************************************** + * + * ZnGetTexFont -- + * + ********************************************************************************** + */ +ZnTexFontInfo +ZnGetTexFont(WidgetInfo *wi, + ZnFont font) +{ + TexFont *txf; + TexFontInfo *tfi; + static int inited = 0; + Tcl_HashEntry *entry; + char *fontname = Tk_NameOfFont(font); + int new; + + if (!inited) { + Tcl_InitHashTable(&font_textures, TCL_STRING_KEYS); + inited = 1; + } + entry = Tcl_FindHashEntry(&font_textures, fontname); + if (entry != NULL) { + /*printf("found font: %s\n", fontname);*/ + txf = (TexFont *) Tcl_GetHashValue(entry); + } + else { + /*printf("new font: |%s|\n", fontname);*/ + txf = ZnMalloc(sizeof(TexFont)); + if (txf == NULL) { + return NULL; + } + txf->tfi = NULL; + txf->tgi = NULL; + txf->tgvi = NULL; + txf->lut = NULL; + txf->teximage = NULL; + txf->tkfont = font; + + entry = Tcl_CreateHashEntry(&font_textures, fontname, &new); + Tcl_SetHashValue(entry, (ClientData) txf); + txf->hash = entry; + } + + /* + * Now locate the texture obj in the texture list for this widget. + */ + tfi = txf->tfi; + while (tfi != NULL) { + if (tfi->wi == wi) { + tfi->refcount++; + return tfi; + } + } + /* + * Not found allocate a new texture object. + */ + tfi = ZnMalloc(sizeof(TexFontInfo)); + if (tfi == NULL) { + ZnFree(txf); + return NULL; + } + tfi->refcount = 1; + tfi->texobj = 0; + tfi->wi = wi; + tfi->txf = txf; + tfi->next = txf->tfi; + txf->tfi = tfi; + + return tfi; +} + + +/* + ********************************************************************************** + * + * ZnNameOfTexFont -- + * + ********************************************************************************** + */ +char * +ZnNameOfTexFont(ZnTexFontInfo tfi) +{ + return Tcl_GetHashKey(&font_textures, ((TexFontInfo *) tfi)->txf->hash); } /* ********************************************************************************** * - * GetTexFont -- + * ZnTexFontTex -- * ********************************************************************************** */ -TexFont * -GetTexFont(ZnWindow win, - ZnFont font) +GLuint +ZnTexFontTex(ZnTexFontInfo tfi) { + TexFontInfo *this = (TexFontInfo *) tfi; + TexFont *txf = this->txf; unsigned char *glisto = " ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijmklmnopqrstuvwxyz?.;,!*:\"'èéêëïîôâàçûùü/+@#$%^&~{[|`]}()=\\-_<>\t\024\025\026\027"; unsigned char *glist=NULL, *glist2=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; + int width, height; GLfloat xstep, ystep, texw, texh; - static int inited = 0; - Tcl_HashEntry *entry; - int max_tex_size[1]; - - if (!inited) { - Tcl_InitHashTable(&font_textures, sizeof(ZnFont)/sizeof(int)); - inited = 1; - } - entry = Tcl_FindHashEntry(&font_textures, (char *) font); - if (entry != NULL) { - return (TexFont *) Tcl_GetHashValue(entry); - } - else { - txf = (TexFont *) ZnMalloc(sizeof(TexFont)); - if (txf == NULL) { + GLuint max_tex_size[1]; + + if (!txf->teximage) { + /*printf("Chargement de la texture pour la fonte %s\n", + ZnNameOfTexFont(tfi));*/ + glGetIntegerv(GL_MAX_TEXTURE_SIZE, max_tex_size); + fontinfo = SuckGlyphsFromServer(this->wi->win, txf->tkfont); + if (fontinfo == NULL) { goto error; } - glGetIntegerv(GL_MAX_TEXTURE_SIZE, max_tex_size); - txf->tgi = NULL; - txf->tgvi = NULL; - txf->lut = NULL; - txf->teximage = NULL; + txf->max_ascent = fontinfo->max_ascent; + txf->max_descent = fontinfo->max_descent; + txf->num_glyphs = strlen(glisto); + /* * Initial size of texture. - * Assume that max_tex_size is at least 256 texels. + * Assume that max_tex_size is at least 128 texels. */ texw = 128; texh = 64; + while (texh < txf->max_ascent+txf->max_descent) { + texh *= 2; + } + if (texh > max_tex_size[0]) { + goto error; + } xstep = 0/*0.5 / texw*/; ystep = 0/*0.5 / texh*/; @@ -749,20 +1337,11 @@ GetTexFont(ZnWindow win, } /*memset(txf->teximage, 0x55, texw * texh * sizeof(unsigned char));*/ - fontinfo = SuckGlyphsFromServer(win, font); - if (fontinfo == NULL) { - goto error; - } - - txf->max_ascent = fontinfo->max_ascent; - txf->max_descent = fontinfo->max_descent; - txf->num_glyphs = strlen(glisto); - - txf->tgi = (TexGlyphInfo *) ZnMalloc(txf->num_glyphs * sizeof(TexGlyphInfo)); + txf->tgi = ZnMalloc(txf->num_glyphs * sizeof(TexGlyphInfo)); if (txf->tgi == NULL) { goto error; } - txf->tgvi = (TexGlyphVertexInfo *) ZnMalloc(txf->num_glyphs * sizeof(TexGlyphVertexInfo)); + txf->tgvi = ZnMalloc(txf->num_glyphs * sizeof(ZnTexGVI)); if (txf->tgvi == NULL) { goto error; } @@ -776,7 +1355,7 @@ GetTexFont(ZnWindow win, */ glist2 = ZnMalloc((txf->num_glyphs+1) * sizeof(unsigned char)); strcpy(glist2, glist); - + restart: px = gap; py = gap; @@ -910,24 +1489,15 @@ GetTexFont(ZnWindow win, txf->min_glyph = min_glyph; txf->range = max_glyph - min_glyph + 1; - txf->lut = (TexGlyphVertexInfo **) ZnMalloc(txf->range * sizeof(TexGlyphVertexInfo *)); - memset(txf->lut, 0, txf->range * sizeof(TexGlyphVertexInfo *)); + txf->lut = ZnMalloc(txf->range * sizeof(ZnTexGVI *)); if (txf->lut == NULL) { goto error; } + memset(txf->lut, 0, txf->range * sizeof(ZnTexGVI *)); for (i = 0; i < txf->num_glyphs; i++) { txf->lut[txf->tgi[i].c - txf->min_glyph] = &txf->tgvi[i]; } - 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, txf->tex_width, txf->tex_height, 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); @@ -935,11 +1505,23 @@ GetTexFont(ZnWindow win, ZnFree(fontinfo); ZnFree(glist); ZnFree(glist2); + } - entry = Tcl_CreateHashEntry(&font_textures, (char *) font, &new); - Tcl_SetHashValue(entry, (ClientData) txf); - return txf; + if (!this->texobj) { + glGenTextures(1, &this->texobj); + /*printf("creation texture %d pour la fonte %s\n", + this->texobj, ZnNameOfTexFont(tfi));*/ + glBindTexture(GL_TEXTURE_2D, this->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, txf->tex_width, txf->tex_height, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage); + glBindTexture(GL_TEXTURE_2D, 0); } + + return this->texobj; error: if (glist) { @@ -955,247 +1537,149 @@ GetTexFont(ZnWindow win, } ZnFree(fontinfo); } - if (txf) { - if (txf->tgi) { - ZnFree(txf->tgi); - } - if (txf->tgvi) { - ZnFree(txf->tgvi); - } - if (txf->lut) { - ZnFree(txf->lut); - } - if (txf->teximage) { - ZnFree(txf->teximage); - } - ZnFree(txf); + + if (txf->tgi) { + ZnFree(txf->tgi); + txf->tgi = NULL; } - return NULL; + if (txf->tgvi) { + ZnFree(txf->tgvi); + txf->tgvi = NULL; + } + if (txf->lut) { + ZnFree(txf->lut); + txf->lut = NULL; + } + if (txf->teximage) { + ZnFree(txf->teximage); + txf->teximage = NULL; + } + + return 0; } + /* - * Working only for 16 bits displays with 5r6g5b mask, - * and 24/32 bits displays. Byte ordering ok on Intel - * plateform only. + ********************************************************************************** + * + * ZnFreeTexFont -- + * + ********************************************************************************** */ void -From5r6g5b(unsigned char *data, - int width, - int height, - int bytes_per_line, - int t_width, - int t_height, - BitmapBits *b_bits, - unsigned char *t_bits) +ZnFreeTexFont(ZnTexFontInfo tfi) { - int x, y; - int rowstride = t_width * 4; - unsigned char *obptr; - unsigned char *bptr, *bp2; - unsigned char alpha; - unsigned short temp; - - 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; + TexFontInfo *this = ((TexFontInfo *) tfi); + TexFont *txf = this->txf; + TexFontInfo *prev, *scan; - /* - * Dispatch the 3 color components. - */ - temp = ((unsigned short *)obptr)[0]; - *bp2 = (temp >> 8) & 0xf8; /* r */ - bp2++; - *bp2 = (temp >> 3) & 0xfc; /* v */ - bp2++; - *bp2 = (temp << 3); /* b */ - bp2++; - *bp2 = alpha; - bp2++; - obptr += 2; - } - 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; + for (prev=NULL, scan=this->txf->tfi; (scan!=NULL)&&(scan != this); + prev=scan, scan=this->next); + if (scan != this) { + return; } -} - -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; + /* + * Decrement tex font object refcount. + */ + this->refcount--; + if (this->refcount != 0) { + return; + } - /* - * 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; + /* + * Unlink the deleted tex font info. + */ + if (prev == NULL) { + txf->tfi = this->next; } - for (y = height; y < t_height; y++) { - memset(bptr, 0, rowstride); - bptr += rowstride; + else { + prev->next = this->next; + } + if (this->texobj) { + /*printf("Libération de la texture %d pour la fonte %s\n", + this->texobj, ZnNameOfTexFont(tfi));*/ + glDeleteTextures(1, &this->texobj); } -} - -static int -To2Power(int a) -{ - int result = 1; - while (result < a) { - result *= 2; + /* + * There is no more client for this font + * deallocate the structures. + */ + if (txf->tfi == NULL) { + /*printf("destruction complète du txf pour %s\n", + ZnNameOfTexFont(tfi));*/ + ZnFree(txf->tgi); + ZnFree(txf->tgvi); + ZnFree(txf->lut); + ZnFree(txf->teximage); + ZnFree(txf); + Tcl_DeleteHashEntry(txf->hash); } - return result; + + ZnFree(this); } - -ImageBits * -GetImageTexture(ZnWindow win, - char *image_name, - ZnImage image) + +/* + ********************************************************************************** + * + * ZnCharInTexFont -- + * + ********************************************************************************** + */ +ZnBool +ZnCharInTexFont(ZnTexFontInfo tfi, + int c) { - 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->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->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); - } + TexFont *txf = ((TexFontInfo *) tfi)->txf; - 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); - 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_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)); + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + if (txf->lut[c - txf->min_glyph]) { + return True; } - */ } - - return im_bits; + return False; } -BitmapBits * -GetBitmapTexture(Display *dpy, - Pixmap bitmap) +/* + ********************************************************************************** + * + * ZnTexFontGVI -- + * + ********************************************************************************** + */ +ZnTexGVI * +ZnTexFontGVI(ZnTexFontInfo tfi, + int c) { - 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; + TexFont *txf = ((TexFontInfo *) tfi)->txf; + ZnTexGVI *tgvi; + + /* Automatically substitute uppercase letters with lowercase if not + uppercase available (and vice versa). */ + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + tgvi = txf->lut[c - txf->min_glyph]; + if (tgvi) { + return tgvi; + } + if (islower(c)) { + c = toupper(c); + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + return txf->lut[c - txf->min_glyph]; + } + } + if (isupper(c)) { + c = tolower(c); + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + return txf->lut[c - txf->min_glyph]; } - 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; + fprintf(stderr, + "Tried to access unavailable texture font character '%c'(\\0%o)\n", + c, c); + return txf->lut[(int)'!' - txf->min_glyph]; } + #endif -- cgit v1.1