aboutsummaryrefslogtreecommitdiff
path: root/generic/Image.c
diff options
context:
space:
mode:
authorlecoanet2003-10-03 14:17:08 +0000
committerlecoanet2003-10-03 14:17:08 +0000
commit2ea14f2e0c8b5d56bddc38a024e913e3aa7a375f (patch)
treea8223c33ffb4e36123751721389460e8e01d2dfc /generic/Image.c
parent28feb2f0bb1b769da852452e40f1799093e8ba2e (diff)
downloadtkzinc-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.
Diffstat (limited to 'generic/Image.c')
-rw-r--r--generic/Image.c794
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);