diff options
Diffstat (limited to 'generic')
-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); |