aboutsummaryrefslogtreecommitdiff
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-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);