diff options
author | lecoanet | 2003-10-03 14:17:08 +0000 |
---|---|---|
committer | lecoanet | 2003-10-03 14:17:08 +0000 |
commit | 2ea14f2e0c8b5d56bddc38a024e913e3aa7a375f (patch) | |
tree | a8223c33ffb4e36123751721389460e8e01d2dfc | |
parent | 28feb2f0bb1b769da852452e40f1799093e8ba2e (diff) | |
download | tkzinc-2ea14f2e0c8b5d56bddc38a024e913e3aa7a375f.zip tkzinc-2ea14f2e0c8b5d56bddc38a024e913e3aa7a375f.tar.gz tkzinc-2ea14f2e0c8b5d56bddc38a024e913e3aa7a375f.tar.bz2 tkzinc-2ea14f2e0c8b5d56bddc38a024e913e3aa7a375f.tar.xz |
Added code to propagate updates on tk images.
Added code to construct the valid region of
an image (shaped) even if TkPhotoGetValidRegion
is not available (perl or not a photo).
Added a fun telling if a point is on the active
area of the image.
Changed the internal api for using images to
match the changes above.
A tkfont reference is kept for each txf using
the font so that the font can be freed if no
longer used.
Use of the max texture size is now reliable and
texture allocation for fonts start with the largest
tex and increase the tex height from 64 to the max
tex limit. This seems to work ok for large fonts.
-rw-r--r-- | generic/Image.c | 794 |
1 files changed, 566 insertions, 228 deletions
diff --git a/generic/Image.c b/generic/Image.c index e15d2d4..0c93cf4 100644 --- a/generic/Image.c +++ b/generic/Image.c @@ -30,6 +30,7 @@ #include "WidgetInfo.h" #include "Geo.h" #include "Draw.h" +#include "perfos.h" #include <memory.h> #include <ctype.h> @@ -48,45 +49,49 @@ static Tcl_HashTable images; static Tcl_HashTable font_textures; #endif +typedef struct _ClientStruct { + void (*inv_proc)(void *cd); + void *client_data; +} ClientStruct; + typedef struct _ImageStruct { union { - struct { - Pixmap pixmap; - Screen *screen; - } x; - struct { + Pixmap pixmap; #ifdef GL - GLuint texobj; + GLuint texobj; #endif - struct _ZnWInfo *wi; - } gl; } i; - struct _ImageBits *bits; + struct _ZnWInfo *wi; + struct _ImageBits *bits; /* Bookkeeping */ ZnBool for_gl; int refcount; + ZnList clients; struct _ImageStruct *next; } ImageStruct, *Image; typedef struct _ImageBits { unsigned char *bpixels; /* Needed for bitmaps. Set to NULL if the image - * is a photo. */ + * is not a bitmap. */ int rowstride; #ifdef GL ZnReal t; /* Texture parameters for the image. */ ZnReal s; - int t_width; /* Texture size used for this image. */ + 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). */ + unsigned char *t_bits; /* Can be NULL if texture is not used (no GL + * rendering active on this image). */ #endif /* Bookeeping */ + struct _ZnWInfo *wi; /* The widget that created the tkimage below (the first + * to use this image). */ Tk_Image tkimage; /* Keep this handle to be informed of changes */ Tk_PhotoHandle tkphoto; + TkRegion valid_region; int width; int height; Tcl_HashEntry *hash; /* From this it is easy to get the image/bitmap @@ -122,7 +127,7 @@ To2Power(int a) ********************************************************************************** */ static void -InvalidateImage(ClientData client_data __unused, +InvalidateImage(ClientData client_data, int x __unused, int y __unused, int width __unused, @@ -130,186 +135,178 @@ InvalidateImage(ClientData client_data __unused, int image_width __unused, int image_height __unused) { - /* - * Void stub that keeps the Tk image mecanism happy. Zinc does - * _not_ implement image update yet. - */ -} - -ZnImage -ZnGetImage(ZnWInfo *wi, - Tk_Uid image_name) -{ - Tcl_HashEntry *entry; - int new; - ImageBits *bits; - ZnBool for_gl = wi->render>0; - Image image; - - /*printf("ZnGetImage: %s\n", image_name);*/ - if (!images_inited) { - Tcl_InitHashTable(&images, TCL_STRING_KEYS); - images_inited = 1; - } - image_name = Tk_GetUid(image_name); - entry = Tcl_FindHashEntry(&images, image_name); - if (entry != NULL) { - /*printf("Image %s déjà connue\n", image_name);*/ - bits = (ImageBits *) Tcl_GetHashValue(entry); + ImageBits *bits = (ImageBits *) client_data; + Image this; + int num_cs, count, i; + ClientStruct *cs; + + if (ZnImageIsBitmap(bits->images)) { + /* This is a bitmap nothing to update + * (This should not happen) */ + return; } - else { - /*printf("Nouvelle Image %s\n", image_name);*/ - if (strcmp(image_name, "") == 0) { - return ZnUnspecifiedImage; - } - bits = ZnMalloc(sizeof(ImageBits)); - bits->tkphoto = Tk_FindPhoto(wi->interp, image_name); - if (bits->tkphoto == NULL) { - im_val_err: - ZnWarning("unknown or bogus photo image \""); - ZnWarning(image_name); - ZnWarning("\"\n"); - ZnFree(bits); - return ZnUnspecifiedImage; - } - else { - Tk_PhotoGetSize(bits->tkphoto, &bits->width, &bits->height); - if ((bits->width == 0) || (bits->height == 0)) { - goto im_val_err; - } + #ifdef GL - bits->t_bits = NULL; + if (bits->t_bits) { + ZnFree(bits->t_bits); + bits->t_bits = NULL; + } #endif - bits->images = NULL; - bits->bpixels = NULL; - bits->tkimage = Tk_GetImage(wi->interp, wi->win, image_name, - InvalidateImage, (ClientData) bits); - entry = Tcl_CreateHashEntry(&images, image_name, &new); - bits->hash = entry; - Tcl_SetHashValue(entry, (ClientData) bits); - } + if (bits->valid_region) { + TkDestroyRegion(bits->valid_region); + bits->valid_region = NULL; } - /* - * 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.screen == wi->screen)) { - image->refcount++; - return image; - } + count = 0; + this = bits->images; + while (this) { + if (bits->tkphoto) { + Tk_PhotoGetSize(bits->tkphoto, &bits->width, &bits->height); + } + else { + Tk_SizeOfImage(bits->tkimage, &bits->width, &bits->height); } - } - /* - * 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) { - image->i.gl.wi = wi; #ifdef GL - image->i.gl.texobj = 0; -#endif - } - else { - Tk_Image tkimage; - - image->i.x.screen = wi->screen; - if (bits->images == NULL) { - /* This is the first instance we can use safely the - * main tkimage. - */ - tkimage = bits->tkimage; + if (this->for_gl) { + if (this->i.texobj) { + ZnGLMakeCurrent(this->wi); + glDeleteTextures(1, &this->i.texobj); + ZnGLRelease(this->wi); + this->i.texobj = 0; + } } else { - /* Create a temporary tkimage to draw the pixmap. - */ - tkimage = Tk_GetImage(wi->interp, wi->win, image_name, NULL, NULL); +#endif + if (this->i.pixmap != None) { + Tk_FreePixmap(this->wi->dpy, this->i.pixmap); + this->i.pixmap = None; + } +#ifdef GL } - image->i.x.pixmap = Tk_GetPixmap(wi->dpy, RootWindowOfScreen(wi->screen), - bits->width, bits->height, - DefaultDepthOfScreen(wi->screen)); - Tk_RedrawImage(tkimage, 0, 0, bits->width, bits->height, - image->i.x.pixmap, 0, 0); - if (tkimage != bits->tkimage) { - Tk_FreeImage(tkimage); +#endif + + num_cs = ZnListSize(this->clients); + cs = ZnListArray(this->clients); + for (i = 0; i < num_cs; i++, cs++) { + if (cs->inv_proc) { + (*cs->inv_proc)(cs->client_data); + } } + count += num_cs; + this = this->next; } - image->next = bits->images; - bits->images = image; + /*printf("Invalidate on image %s with %d clients\n", + Tcl_GetHashKey(&images, bits->hash), count);*/ - return image; } -/* - ********************************************************************************** - * - * ZnGetBitmap -- - * - ********************************************************************************** - */ ZnImage -ZnGetBitmap(ZnWInfo *wi, - Tk_Uid bitmap_name) +ZnGetImage(ZnWInfo *wi, + Tk_Uid image_name, + void (*inv_proc)(void *cd), + void *client_data) { Tcl_HashEntry *entry; + int new, num_cs, i; ImageBits *bits; - Image image; ZnBool for_gl = wi->render>0; + Image image; + Tk_ImageType *type; + ClientStruct cs, *cs_ptr; - /*printf("ZnGetBitmap: %s\n", bitmap_name);*/ + /*printf("ZnGetImage: %s\n", image_name);*/ if (!images_inited) { Tcl_InitHashTable(&images, TCL_STRING_KEYS); images_inited = 1; } - bitmap_name = Tk_GetUid(bitmap_name); - entry = Tcl_FindHashEntry(&images, bitmap_name); + image_name = Tk_GetUid(image_name); + entry = Tcl_FindHashEntry(&images, image_name); if (entry != NULL) { + /*printf("Image %s déjà connue\n", image_name);*/ bits = (ImageBits *) Tcl_GetHashValue(entry); } else { - Pixmap pmap; - XImage *mask; - int x, y, new; - unsigned char *line; - - pmap = Tk_GetBitmap(wi->interp, wi->win, bitmap_name); - if (pmap == ZnUnspecifiedImage) { + /*printf("Nouvelle Image %s\n", image_name);*/ + if (strcmp(image_name, "") == 0) { return ZnUnspecifiedImage; } + bits = ZnMalloc(sizeof(ImageBits)); - Tk_SizeOfBitmap(wi->dpy, pmap, &bits->width, &bits->height); + bits->wi = wi; #ifdef GL bits->t_bits = NULL; #endif bits->images = NULL; - mask = XGetImage(wi->dpy, pmap, 0, 0, (unsigned int) bits->width, - (unsigned int) bits->height, 1L, XYPixmap); - bits->rowstride = mask->bytes_per_line; - bits->bpixels = ZnMalloc((unsigned int) (bits->height * bits->rowstride)); - memset(bits->bpixels, 0, (unsigned int) (bits->height * bits->rowstride)); - line = bits->bpixels; - for (y = 0; y < bits->height; y++) { - for (x = 0; x < bits->width; x++) { - if (XGetPixel(mask, x, y)) { - line[x >> 3] |= 0x80 >> (x & 7); + bits->bpixels = NULL; + bits->valid_region = NULL; + bits->tkimage = NULL; + bits->tkphoto = NULL; + + if (!Tk_GetImageMasterData(wi->interp, image_name, &type)) { + /* + * This doesn't seem to be a Tk image, try to load + * a Tk bitmap. + */ + Pixmap pmap; + XImage *mask; + int x, y; + unsigned char *line; + + pmap = Tk_GetBitmap(wi->interp, wi->win, image_name); + if (pmap == None) { + ZnWarning("unknown bitmap/image \""); + goto im_error; + } + + Tk_SizeOfBitmap(wi->dpy, pmap, &bits->width, &bits->height); + mask = XGetImage(wi->dpy, pmap, 0, 0, (unsigned int) bits->width, + (unsigned int) bits->height, 1L, XYPixmap); + bits->rowstride = mask->bytes_per_line; + bits->bpixels = ZnMalloc((unsigned int) (bits->height * bits->rowstride)); + memset(bits->bpixels, 0, (unsigned int) (bits->height * bits->rowstride)); + line = bits->bpixels; + for (y = 0; y < bits->height; y++) { + for (x = 0; x < bits->width; x++) { + if (XGetPixel(mask, x, y)) { + line[x >> 3] |= 0x80 >> (x & 7); + } } + line += bits->rowstride; } - line += bits->rowstride; + XDestroyImage(mask); + Tk_FreeBitmap(wi->dpy, pmap); } - XDestroyImage(mask); - Tk_FreeBitmap(wi->dpy, pmap); - entry = Tcl_CreateHashEntry(&images, bitmap_name, &new); - Tcl_SetHashValue(entry, (ClientData) bits); + + else if (strcmp(type->name, "photo") == 0) { + /* Processing will yield an image photo */ + bits->tkphoto = Tk_FindPhoto(wi->interp, image_name); + Tk_PhotoGetSize(bits->tkphoto, &bits->width, &bits->height); + if ((bits->width == 0) || (bits->height == 0)) { + ZnWarning("bogus photo image \""); + goto im_error; + } + bits->tkimage = Tk_GetImage(wi->interp, wi->win, image_name, + InvalidateImage, (ClientData) bits); + } + else { /* Other image types */ + bits->tkimage = Tk_GetImage(wi->interp, wi->win, image_name, + InvalidateImage, (ClientData) bits); + Tk_SizeOfImage(bits->tkimage, &bits->width, &bits->height); + if ((bits->width == 0) || (bits->height == 0)) { + ZnWarning("bogus "); + ZnWarning(type->name); + ZnWarning(" image \""); + im_error: + ZnWarning(image_name); + ZnWarning("\"\n"); + ZnFree(bits); + return ZnUnspecifiedImage; + } + } + + entry = Tcl_CreateHashEntry(&images, image_name, &new); bits->hash = entry; + Tcl_SetHashValue(entry, (ClientData) bits); } /* @@ -317,36 +314,55 @@ ZnGetBitmap(ZnWInfo *wi, */ 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.screen == wi->screen)) { + if ((for_gl && (image->wi == wi)) || + (!for_gl && (image->wi->screen == wi->screen))) { + if (!ZnImageIsBitmap(image)) { + cs_ptr = ZnListArray(image->clients); + num_cs = ZnListSize(image->clients); + for (i = 0; i < num_cs; i++, cs_ptr++) { + if ((cs_ptr->inv_proc == inv_proc) && + (cs_ptr->client_data == client_data)) { + return image; + } + } + /* Add a new client reference to call back. + */ + cs.inv_proc = inv_proc; + cs.client_data = client_data; + ZnListAdd(image->clients, &cs, ZnListTail); + } image->refcount++; return image; } } } - /* - * Create a new instance for this widget/display conf. + * Create a new instance for this case. */ image = ZnMalloc(sizeof(ImageStruct)); image->bits = bits; image->refcount = 1; image->for_gl = for_gl; + image->wi = wi; + + if (!ZnImageIsBitmap(image)) { + image->clients = ZnListNew(1, sizeof(ClientStruct)); + cs.inv_proc = inv_proc; + cs.client_data = client_data; + ZnListAdd(image->clients, &cs, ZnListTail); + } + + /* Init the real resource and let the client load it + * on demand */ if (image->for_gl) { - image->i.gl.wi = wi; -#ifdef GL - image->i.gl.texobj = 0; +#ifdef GL + image->i.texobj = 0; #endif } else { - image->i.x.screen = wi->screen; - /* - * Need to get a pixmap that match this dpy. - */ - image->i.x.pixmap = Tk_GetBitmap(wi->interp, wi->win, bitmap_name); + image->i.pixmap = None; + /* image->i.pixmap = Tk_GetBitmap(wi->interp, wi->win, image_name); + printf("pmap: %d\n", image->i.pixmap);*/ } image->next = bits->images; bits->images = image; @@ -363,9 +379,30 @@ ZnGetBitmap(ZnWInfo *wi, ********************************************************************************** */ ZnImage -ZnGetImageByValue(ZnImage image) +ZnGetImageByValue(ZnImage image, + void (*inv_proc)(void *cd), + void *client_data) { - ((Image) image)->refcount++; + Image this = (Image) image; + ClientStruct cs, *cs_ptr; + int i, num_cs; + + /*printf("ZnGetImageByValue: %s\n", ZnNameOfImage(image));*/ + if (!ZnImageIsBitmap(image)) { + cs_ptr = ZnListArray(this->clients); + num_cs = ZnListSize(this->clients); + for (i = 0; i < num_cs; i++, cs_ptr++) { + if ((cs_ptr->inv_proc == inv_proc) && + (cs_ptr->client_data == client_data)) { + return image; + } + } + cs.inv_proc = inv_proc; + cs.client_data = client_data; + ZnListAdd(this->clients, &cs, ZnListTail); + } + + this->refcount++; return image; } @@ -390,11 +427,16 @@ ZnImageIsBitmap(ZnImage image) ********************************************************************************** */ void -ZnFreeImage(ZnImage image) +ZnFreeImage(ZnImage image, + void (*inv_proc)(void *cd), + void *client_data) { Image prev, scan, this = ((Image) image); ImageBits *bits = this->bits; + ClientStruct *cs_ptr; + int i, num_cs; + /*printf("ZnFreeImage: %s\n", ZnNameOfImage(image));*/ /* * Search the instance in the list. */ @@ -404,7 +446,21 @@ ZnFreeImage(ZnImage image) return; /* Not found ? */ } - this->refcount--; + if (!ZnImageIsBitmap(image)) { + cs_ptr = ZnListArray(this->clients); + num_cs = ZnListSize(this->clients); + for (i = 0; i < num_cs; i++, cs_ptr++) { + if ((cs_ptr->inv_proc == inv_proc) && + (cs_ptr->client_data == client_data)) { + ZnListDelete(this->clients, i); + this->refcount--; + break; + } + } + } + else { + this->refcount--; + } if (this->refcount != 0) { return; } @@ -420,25 +476,29 @@ ZnFreeImage(ZnImage image) } if (this->for_gl) { #ifdef GL - ZnWInfo *wi = this->i.gl.wi; - if (this->i.gl.texobj && wi->win) { + ZnWInfo *wi = this->wi; + if (this->i.texobj && wi->win) { ZnGLMakeCurrent(wi); - glDeleteTextures(1, &this->i.gl.texobj); + glDeleteTextures(1, &this->i.texobj); ZnGLRelease(wi); } #endif } - else if (!ZnImageIsBitmap(image)) { + else if (bits->tkimage) { /* * This is an image, we need to free the instances. */ - Tk_FreePixmap(DisplayOfScreen(this->i.x.screen), this->i.x.pixmap); + if (this->i.pixmap != None) { + Tk_FreePixmap(this->wi->dpy, this->i.pixmap); + } } else { /* * This is a bitmap ask Tk to free the resource. */ - Tk_FreeBitmap(DisplayOfScreen(this->i.x.screen), this->i.x.pixmap); + if (this->i.pixmap != None) { + Tk_FreeBitmap(this->wi->dpy, this->i.pixmap); + } } ZnFree(this); @@ -452,12 +512,15 @@ ZnFreeImage(ZnImage image) ZnFree(bits->t_bits); } #endif - if (ZnImageIsBitmap(image)) { + if (bits->bpixels) { ZnFree(bits->bpixels); } - else { + if (bits->tkimage) { Tk_FreeImage(bits->tkimage); } + if (bits->valid_region) { + TkDestroyRegion(bits->valid_region); + } Tcl_DeleteHashEntry(bits->hash); ZnFree(bits); } @@ -507,41 +570,139 @@ ZnSizeOfImage(ZnImage image, Pixmap ZnImagePixmap(ZnImage image) { - Image this = (Image) image; + Image this = (Image) image; + ImageBits *bits = this->bits; + ZnWInfo *wi = bits->wi; + /*printf("ZnImagePixmap: %s\n", ZnNameOfImage(image));*/ if (this->for_gl) { printf("Bogus use of an image, it was created for GL and used in an X11 context\n"); return None; } - return this->i.x.pixmap; + + if (this->i.pixmap == None) { + if (ZnImageIsBitmap(image)) { + this->i.pixmap = Tk_GetBitmap(wi->interp, wi->win, Tk_GetUid(ZnNameOfImage(image))); + } + else { + Tk_Image tkimage; + + if (bits->wi == wi) { + tkimage = bits->tkimage; + } + else { + /* Create a temporary tkimage to draw the pixmap. */ + tkimage = Tk_GetImage(wi->interp, wi->win, ZnNameOfImage(image), NULL, NULL); + } + + this->i.pixmap = Tk_GetPixmap(wi->dpy, Tk_WindowId(wi->win), + bits->width, bits->height, Tk_Depth(wi->win)); + Tk_RedrawImage(tkimage, 0, 0, bits->width, bits->height, this->i.pixmap, 0, 0); + + if (tkimage != bits->tkimage) { + Tk_FreeImage(tkimage); + } + } + } + + return this->i.pixmap; } + /* ********************************************************************************** * - * ZnImageMask -- + * ZnPointInImage -- + * + * Return whether the given point is inside the image. * ********************************************************************************** */ -char * -ZnImageMask(ZnImage image, - int *stride) +ZnBool +ZnPointInImage(ZnImage image, + int x, + int y) { - Image this = (Image) image; - - if (stride) { - *stride = this->bits->rowstride; + if (ZnImageIsBitmap(image)) { + ImageBits *bits = ((Image) image)->bits; + if ((x < 0) || (y < 0) || + (x >= bits->width) || (y >= bits->height)) { + return False; + } + return ZnGetBitmapPixel(bits->bpixels, bits->rowstride, x, y); + } + else { + return ZnPointInRegion(ZnImageRegion(image), x, y); } - return this->bits->bpixels; } + /* ********************************************************************************** * * ZnImageRegion -- * + * Only defined for Tk images (including Tk images defined from bitmaps). + * ********************************************************************************** */ +static void +BuildImageRegion(ImageBits *bits) +{ + ZnWInfo *wi = bits->wi; + Pixmap pmap; + int x, y, end; + GC gc; + XImage *im1, *im2; + XRectangle rect; + + /*printf("BuildImageRegion: %s\n", ZnNameOfImage(bits->images));*/ + pmap = Tk_GetPixmap(wi->dpy, Tk_WindowId(wi->win), + bits->width, bits->height, Tk_Depth(wi->win)); + 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(bits->tkimage, 0, 0, bits->width, bits->height, pmap, 0, 0); + im1 = XGetImage(wi->dpy, pmap, 0, 0, bits->width, bits->height, ~0L, ZPixmap); + + XSetForeground(wi->dpy, gc, 1); + XFillRectangle(wi->dpy, pmap, gc, 0, 0, bits->width, bits->height); + Tk_RedrawImage(bits->tkimage, 0, 0, bits->width, bits->height, pmap, 0, 0); + im2 = XGetImage(wi->dpy, pmap, 0, 0, bits->width, bits->height, ~0L, ZPixmap); + Tk_FreePixmap(wi->dpy, pmap); + XFreeGC(wi->dpy, gc); + + bits->valid_region = TkCreateRegion(); + + for (y = 0; y < bits->height; y++) { + x = 0; + while (x < bits->width) { + while ((x < bits->width) && + (XGetPixel(im1, x, y) != XGetPixel(im2, x, y))) { + /* Search the first non-transparent pixel */ + x++; + } + end = x; + while ((end < bits->width) && + (XGetPixel(im1, end, y) == XGetPixel(im2, end, y))) { + /* Search the first transparent pixel */ + end++; + } + if (end > x) { + rect.x = x; + rect.y = y; + rect.width = end - x; + rect.height = 1; + TkUnionRectWithRegion(&rect, bits->valid_region, bits->valid_region); + } + x = end; + } + } + + XDestroyImage(im1); + XDestroyImage(im2); +} + TkRegion ZnImageRegion(ZnImage image) { @@ -549,14 +710,27 @@ ZnImageRegion(ZnImage image) return NULL; } else { + ImageBits *bits = ((Image) image)->bits; #ifdef PTK - return NULL; + if (!bits->valid_region) { + BuildImageRegion(bits); + } + return bits->valid_region; #else - return TkPhotoGetValidRegion(((Image) image)->bits->tkphoto); + if (bits->tkphoto) { + return TkPhotoGetValidRegion(bits->tkphoto); + } + else { + if (!bits->valid_region) { + BuildImageRegion(bits); + } + return bits->valid_region; + } #endif } } + /* ********************************************************************************** * @@ -565,15 +739,172 @@ ZnImageRegion(ZnImage image) ********************************************************************************** */ #ifdef GL +/* + * 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, + unsigned char *t_bits, + int t_width, + int t_height, + TkRegion valid_region) +{ + 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 = ZnPointInRegion(valid_region, 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, + unsigned char *t_bits, + int t_width, + int t_height, + TkRegion valid_region) +{ + 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 = ZnPointInRegion(valid_region, 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 void +GatherImageTexels(ImageBits *bits) +{ + Pixmap pmap; + XImage *im; + TkRegion valid_region; + int t_size, depth; + ZnWInfo *wi = bits->wi; + + /*printf("GatherImageTexels: %s\n", ZnNameOfImage(bits->images));*/ + valid_region = ZnImageRegion(bits->images); + + t_size = bits->t_width * 4 * bits->t_height; + bits->t_bits = ZnMalloc(t_size); + depth = Tk_Depth(wi->win); + + pmap = Tk_GetPixmap(wi->dpy, Tk_WindowId(wi->win), + bits->width, bits->height, depth); + Tk_RedrawImage(bits->tkimage, 0, 0, bits->width, bits->height, pmap, 0, 0); + im = XGetImage(wi->dpy, pmap, 0, 0, bits->width, bits->height, ~0L, ZPixmap); + Tk_FreePixmap(wi->dpy, pmap); + + if (depth == 16) { + From5r6g5b(im->data, bits->width, bits->height, im->bytes_per_line, + bits->t_bits, bits->t_width, bits->t_height, valid_region); + } + else if ((depth == 24) || (depth == 32)) { + From8r8g8b(im->data, bits->width, bits->height, im->bytes_per_line, + bits->t_bits, bits->t_width, bits->t_height, valid_region); + } + + XDestroyImage(im); +} + GLuint ZnImageTex(ZnImage image, ZnReal *t, ZnReal *s) { - Image this = (Image) image; - ImageBits *bits = this->bits; - ZnBool is_bmap = ZnImageIsBitmap(image); - unsigned int t_size, width, height; + Image this = (Image) image; + ImageBits *bits = this->bits; + ZnBool is_bmap = ZnImageIsBitmap(image); + unsigned int t_size, width, height; if (!this->for_gl) { printf("Bogus use of an image, it was created for X11 and used in a GL context\n"); @@ -586,6 +917,10 @@ ZnImageTex(ZnImage image, bits->t_height = To2Power((int) height); bits->s = width / (ZnReal) bits->t_width; bits->t = height / (ZnReal) bits->t_height; + + /* + * This is a bitmap: use the pixels stored in bpixels. + */ if (is_bmap) { unsigned int i, j; unsigned char *ostart, *dstart, *d, *o; @@ -605,7 +940,11 @@ ZnImageTex(ZnImage image, dstart += bits->t_width; } } - else { + + /* + * This is a photo: use the photo API, it is simple. + */ + else if (bits->tkphoto) { unsigned int x, y, t_stride; unsigned char *obptr, *bptr, *bp2, *pixels; int green_off, blue_off, alpha_off; @@ -652,18 +991,28 @@ ZnImageTex(ZnImage image, bptr += t_stride; }*/ } + + /* + * This is another image format (not a photo): try to + * guess the pixels and the transparency (on or off) + * from a locally drawn pixmap. + */ + else { + GatherImageTexels(bits); + } } - if (!this->i.gl.texobj) { - glGenTextures(1, &this->i.gl.texobj); + + if (!this->i.texobj) { + glGenTextures(1, &this->i.texobj); /*printf("creation texture %d pour image %s\n", - this->i.gl.texobj, ZnNameOfImage(this));*/ - glBindTexture(GL_TEXTURE_2D, this->i.gl.texobj); + this->i.texobj, ZnNameOfImage(this));*/ + glBindTexture(GL_TEXTURE_2D, this->i.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); glGetError(); - if (ZnImageIsBitmap(image)) { + if (is_bmap) { 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); @@ -683,7 +1032,7 @@ ZnImageTex(ZnImage image, *t = this->bits->t; *s = this->bits->s; - return this->i.gl.texobj; + return this->i.texobj; } #endif @@ -875,7 +1224,7 @@ SuckGlyphsFromServer(ZnWInfo *wi, myfontinfo->descent = fm.descent; /* - * Compute the max character size is the font. This may be + * Compute the max character size in the font. This may be * a bit heavy hammer style but it avoid guessing on characters * not available in the font. */ @@ -885,6 +1234,7 @@ SuckGlyphsFromServer(ZnWInfo *wi, Tk_MeasureChars(font, str, 1, 0, TK_AT_LEAST_ONE, &length); width = MAX(width, length); } + if (width == 0) { /* * Something weird with the font, abort! @@ -1018,7 +1368,6 @@ ZnGetTexFont(ZnWInfo *wi, int width, height; unsigned int texw, texh; GLfloat xstep, ystep; - ZnBool increase_h = False; if (!inited) { Tcl_InitHashTable(&font_textures, TCL_ONE_WORD_KEYS); @@ -1039,7 +1388,9 @@ ZnGetTexFont(ZnWInfo *wi, txf->tgi = NULL; txf->tgvi = NULL; txf->lut = NULL; - txf->tkfont = font; + /* Get a local reference to the font, it will be deallocated + * when no further references on this TexFont exist. */ + txf->tkfont = Tk_GetFont(wi->interp, wi->win, Tk_NameOfFont(font)); /*printf("Chargement de la texture pour la fonte %s\n", ZnNameOfTexFont(tfi));*/ @@ -1054,21 +1405,20 @@ ZnGetTexFont(ZnWInfo *wi, /* * Initial size of texture. */ - texw = texh = wi->max_tex_size; + texw = wi->max_tex_size; texh = 64; while (texh < (unsigned int) (txf->ascent+txf->descent)) { texh *= 2; } + /*printf("Taille réelle de texture utilisée: %d\n", wi->max_tex_size);*/ /* * This is temporarily disabled until we find out * how to reliably get max_tex_size up front without * waiting for the window mapping. */ -#ifdef MAX_TEX_SIZE if (texh > wi->max_tex_size) { goto error; } -#endif xstep = 0/*0.5 / texw*/; ystep = 0/*0.5 / texh*/; @@ -1152,37 +1502,24 @@ ZnGetTexFont(ZnWInfo *wi, px = gap; maxheight = height; if ((unsigned int) (py + height + gap) >= texh) { -#ifdef MAX_TEX_SIZE if (texh*2 < wi->max_tex_size) { -#else - if (increase_h) { - increase_h = False; -#endif texh *= 2; ZnFree(txf->teximage); txf->teximage = ZnMalloc(texw * texh * sizeof(unsigned char)); strcpy(glist, glist2); goto restart; } -#ifdef MAX_TEX_SIZE else if (texw*2 < wi->max_tex_size) { -#else - else { - increase_h = True; -#endif texw *= 2; ZnFree(txf->teximage); txf->teximage = ZnMalloc(texw * texh * sizeof(unsigned char)); strcpy(glist, glist2); goto restart; } -#ifdef MAX_TEX_SIZE else { /* Overflowed texture space */ - ZnWarning("Font texture overflow\n"); goto error; } -#endif } c = i; } @@ -1298,7 +1635,7 @@ ZnGetTexFont(ZnWInfo *wi, Tcl_SetHashValue(entry, (ClientData) txf); txf->hash = entry; } - + /* * Now locate the texture obj in the texture list for this widget. */ @@ -1337,8 +1674,7 @@ ZnGetTexFont(ZnWInfo *wi, char const * ZnNameOfTexFont(ZnTexFontInfo tfi) { - return Tk_NameOfFont((Tk_Font) Tcl_GetHashKey(&font_textures, - ((TexFontInfo *) tfi)->txf->hash)); + return Tk_NameOfFont(((TexFontInfo *) tfi)->txf->tkfont); } /* @@ -1364,6 +1700,7 @@ ZnTexFontTex(ZnTexFontInfo tfi) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glGetError(); + /*printf("Demande texture de %d x %d\n", txf->tex_width, txf->tex_height);*/ glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4, txf->tex_width, txf->tex_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage); @@ -1431,7 +1768,8 @@ ZnFreeTexFont(ZnTexFontInfo tfi) * deallocate the structures. */ if (txf->tfi == NULL) { - /*printf("%d destruction complète du txf pour %s\n", this->wi, ZnNameOfTexFont(tfi));*/ + /*printf("%d destruction complète du txf pour %s\n", this, ZnNameOfTexFont(tfi));*/ + Tk_FreeFont(txf->tkfont); ZnFree(txf->tgi); ZnFree(txf->tgvi); ZnFree(txf->lut); |