Index: generic/tkImgPhoto.c =================================================================== RCS file: /cvsroot/tktoolkit/tk/generic/tkImgPhoto.c,v retrieving revision 1.36.2.2 diff -u -r1.36.2.2 tkImgPhoto.c --- generic/tkImgPhoto.c 17 Jul 2003 13:05:53 -0000 1.36.2.2 +++ generic/tkImgPhoto.c 24 Oct 2003 23:34:11 -0000 @@ -178,10 +178,14 @@ * components. * IMAGE_CHANGED: 1 means that the instances of this image * need to be redithered. + * COMPLEX_ALPHA: 1 means that rendering this image is + * non-trivial and requires blending with + * whatever is behind the image. */ #define COLOR_IMAGE 1 #define IMAGE_CHANGED 2 +#define COMPLEX_ALPHA 4 /* * The following data structure represents all of the instances of @@ -213,6 +217,12 @@ * windows are using. */ GC gc; /* Graphics context for writing images * to the pixmap. */ + + unsigned char *ditheredOverlay; /* The pix32 array dithered. Only + * valid if COMPLEX_ALPHA flag is set. */ + + int overlayWidth, overlayHeight; /*MAX of userWidth,width and userHeight,height */ + } PhotoInstance; /* @@ -374,6 +384,40 @@ * Forward declarations */ +/*GPS*/ +static int ToggleComplexAlphaIfNeeded _ANSI_ARGS_(( + PhotoMaster *mPtr)); + +static unsigned char * CopyTo32BitOverlay _ANSI_ARGS_((unsigned char *from, + unsigned char *overlay, size_t len)); + + +static int BuildOverlayFor32Bits _ANSI_ARGS_(( + PhotoInstance *iPtr)); + + +static unsigned char * CopyTo15BitOverlay _ANSI_ARGS_((unsigned char *from, + unsigned short *overlay, size_t len)); + + +static int BuildOverlayFor15Bits _ANSI_ARGS_(( + PhotoInstance *iPtr)); + +static int BuildDitheredOverlayIfNeeded _ANSI_ARGS_(( + PhotoInstance *iPtr)); + +static void BlendOverlay _ANSI_ARGS_(( + int depth, int xOffset, int yOffset, + int outW, int outH, unsigned char *out, + int overlayW, int overlayH, unsigned char *overlay, + unsigned char *alphaAr)); + +static void DisplayComplexAlphaImage _ANSI_ARGS_(( + PhotoInstance *iPtr, Drawable d, int dx, int dy, + int xOffset, int yOffset, int width, int height)); + +/*END GPS*/ + static void PhotoFormatThreadExitProc _ANSI_ARGS_(( ClientData clientData)); static int ImgPhotoCmd _ANSI_ARGS_((ClientData clientData, @@ -430,6 +474,234 @@ #undef MAX #define MAX(a, b) ((a) > (b)? (a): (b)) +/*GPS*/ +static int +ToggleComplexAlphaIfNeeded(mPtr) + PhotoMaster *mPtr; +{ + size_t i, end = MAX(mPtr->userWidth, mPtr->width) * + MAX(mPtr->userHeight, mPtr->height) * 4; + unsigned char c; + + mPtr->flags &= ~COMPLEX_ALPHA; + for (i = 3; i < end; i += 4) { + c = mPtr->pix32[i]; + if (255 != c && 0 != c) { + mPtr->flags |= COMPLEX_ALPHA; + break; + } + } + return mPtr->flags & COMPLEX_ALPHA; +} + +/*GPS*/ +static unsigned char * +CopyTo32BitOverlay(from, overlay, len) + unsigned char *from, *overlay; + size_t len; +{ + size_t i; + + for (i = 0; i < len; i += 4) { + overlay[i] = from[i + 2]; + overlay[i + 1] = from[i + 1]; + overlay[i + 2] = from[i]; + overlay[i + 3] = 0; + } + return overlay; +} + +/*GPS*/ +static int +BuildOverlayFor32Bits(iPtr) + PhotoInstance *iPtr; +{ + size_t s; + + iPtr->overlayWidth = + MAX(iPtr->masterPtr->userWidth, iPtr->masterPtr->width); + iPtr->overlayHeight = + MAX(iPtr->masterPtr->userHeight, iPtr->masterPtr->height); + s = iPtr->overlayWidth * iPtr->overlayHeight * 4; /* 4 bytes or 32 bits */ + if (s == 0) { + return -1; + } + iPtr->ditheredOverlay = attemptckalloc(s); + + if (NULL == iPtr->ditheredOverlay) { + return -1; + } + CopyTo32BitOverlay(iPtr->masterPtr->pix32, iPtr->ditheredOverlay, s); + return 1; +} + +/*GPS*/ +static unsigned char * +CopyTo15BitOverlay(from, overlay, len) + unsigned char *from; + unsigned short *overlay; + size_t len; +{ + size_t i = 0, overlayI = 0; + unsigned char r, g, b; + + while (i < len) { + r = from[i]; g = from[i + 1]; b = from[i + 2]; + overlay[overlayI] = (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10); + overlayI++; + i += 4; + } + return (unsigned char *) overlay; +} + +/*GPS*/ +static int +BuildOverlayFor15Bits(iPtr) + PhotoInstance *iPtr; +{ + size_t s; + + iPtr->overlayWidth = + MAX(iPtr->masterPtr->userWidth, iPtr->masterPtr->width); + iPtr->overlayHeight = + MAX(iPtr->masterPtr->userHeight, iPtr->masterPtr->height); + /* + * 2 bytes or 16 bits per pixel + */ + s = iPtr->overlayWidth * iPtr->overlayHeight * 2; + iPtr->ditheredOverlay = attemptckalloc (s); + if (NULL == iPtr->ditheredOverlay) { + return -1; + } + CopyTo15BitOverlay(iPtr->masterPtr->pix32, + (unsigned short *) iPtr->ditheredOverlay, s*2); + return 1; +} + +/*GPS*/ +/*-1 not built an error occured*/ +/*0 not-built/not-needed*/ +/*1 built without error*/ +static int +BuildDitheredOverlayIfNeeded(iPtr) + PhotoInstance *iPtr; +{ + if (!(iPtr->masterPtr->flags & COMPLEX_ALPHA) + || iPtr->visualInfo.depth < 15) { + return 0; + } + if (NULL != iPtr->ditheredOverlay) { + ckfree(iPtr->ditheredOverlay); + iPtr->ditheredOverlay = NULL; + } +#ifdef __WIN32__ + return BuildOverlayFor32Bits(iPtr); +#else + if (iPtr->visualInfo.depth >= 24) { + return BuildOverlayFor32Bits(iPtr); + } else if (iPtr->visualInfo.depth >= 15) { + return BuildOverlayFor15Bits(iPtr); + } +#endif + return -1; +} + +/*GPS*/ +#define BlendAlpha(out,overlay,alpha) out += (overlay - out) * alpha / 255 + +static void +BlendOverlay(depth, xOffset, yOffset, outWidth, outHeight, out, + overlayWidth, overlayHeight, overlay, alphaAr) + int depth, xOffset, yOffset, outWidth, outHeight; + int overlayWidth, overlayHeight; + unsigned char *out, *overlay, *alphaAr; +{ + /* + * I'm still trying to figure this out. I'll factor it once I'm + * done experimenting here. + */ + + fprintf(stderr, "depth %d xOffset %d yOffset %d outW %d outH %d overlayW %d overlayH %d\n", + depth, xOffset, yOffset, outWidth, outHeight, overlayWidth, overlayHeight); + + if (24 == depth || 32 == depth) { + unsigned int overlayI, overlayY; + unsigned int outI, outY; + + for (overlayY = yOffset, outY = 0; + overlayY < overlayHeight && outY < outHeight; + overlayY++, outY++) { + size_t outOffset = outWidth * outY * 4; + size_t overlayOffset = overlayWidth * overlayY * 4; + + for (overlayI = xOffset * 4, outI = 0; + overlayI < (overlayWidth * 4) && outI < (outWidth * 4); + overlayI+=4, outI+=4) { + unsigned char alpha = alphaAr[overlayOffset + overlayI + 3]; + + BlendAlpha(out[outOffset + outI], + overlay[overlayOffset + overlayI], alpha); + BlendAlpha(out[outOffset + outI + 1], + overlay[overlayOffset + overlayI + 1], alpha); + BlendAlpha(out[outOffset + outI + 2], + overlay[overlayOffset + overlayI + 2], alpha); + out[outOffset + outI + 3] = 0; + } + } + } else if (15 == depth || 16 == depth) { + size_t outY; + size_t i; + unsigned short *sout = (unsigned short *) out; + + puts("FOO"); + + for (outY = 0; outY < outHeight; ++outY) { + for (i = 0; i < outWidth; ++i) { + sout[(outY * outWidth) + i] = 32767; + } + } + + /*We have a range of 0 to 31 or 0 to 1fh*/ + /*31 << 10 = 31744 + *31 << 5 = 992 + *We can get the leftmost color (B) by doing (P & 31744) >> 10 + *We can then get the middle like so: (P & 992) >> 5 + */ + + } else { + + } +} + +#define GetBackgroundImageFromDrawable(dis,d,x,y,w,h) \ + XGetImage(dis, d, x, y, (unsigned int )w, (unsigned int)h, AllPlanes, ZPixmap) + + +/*0 TkPutImage an error occured or something isn't ready*/ +/*1 TkPutImage worked */ +static void +DisplayComplexAlphaImage(iPtr, d, dx, dy, xOffset, yOffset, width, height) + PhotoInstance *iPtr; + Drawable d; + int dx, dy, xOffset, yOffset, width, height; +{ + XImage *bgImg; + + bgImg = GetBackgroundImageFromDrawable(iPtr->display, d, dx, dy, + width, height); + if ((NULL == bgImg) || (NULL == iPtr->ditheredOverlay)) { + return; + } + /*Possible bug: Tk's XGetImage in Windows seems to always have a depth of 32*/ + BlendOverlay(bgImg->depth, xOffset, yOffset, width, height, bgImg->data, + iPtr->overlayWidth, iPtr->overlayHeight, + iPtr->ditheredOverlay, iPtr->masterPtr->pix32); + + TkPutImage(iPtr->colorTablePtr, iPtr->colorTablePtr->numColors, + iPtr->display, d, iPtr->gc, bgImg, 0, 0, dx, dy, + (unsigned int) width, (unsigned int) height); +} + /* *---------------------------------------------------------------------- * @@ -2082,6 +2354,9 @@ if (oldFormat != NULL) { Tcl_DecrRefCount(oldFormat); } + + ToggleComplexAlphaIfNeeded(masterPtr); + return TCL_OK; errorExit: @@ -2235,6 +2510,7 @@ } } + BuildDitheredOverlayIfNeeded(instancePtr); } /* @@ -2344,6 +2620,7 @@ instancePtr->height = 0; instancePtr->imagePtr = 0; instancePtr->nextPtr = masterPtr->instancePtr; + instancePtr->ditheredOverlay = NULL; masterPtr->instancePtr = instancePtr; /* @@ -2428,8 +2705,13 @@ masterPtr->width, masterPtr->height); } + + BuildDitheredOverlayIfNeeded(instancePtr); + return (ClientData) instancePtr; } + + /* *---------------------------------------------------------------------- @@ -2471,21 +2753,27 @@ return; } - /* - * masterPtr->region describes which parts of the image contain - * valid data. We set this region as the clip mask for the gc, - * setting its origin appropriately, and use it when drawing the - * image. - */ - - TkSetRegion(display, instancePtr->gc, instancePtr->masterPtr->validRegion); - XSetClipOrigin(display, instancePtr->gc, drawableX - imageX, - drawableY - imageY); - XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc, - imageX, imageY, (unsigned) width, (unsigned) height, - drawableX, drawableY); - XSetClipMask(display, instancePtr->gc, None); - XSetClipOrigin(display, instancePtr->gc, 0, 0); + if ((instancePtr->masterPtr->flags & COMPLEX_ALPHA) + && instancePtr->visualInfo.depth >= 15) { + DisplayComplexAlphaImage(instancePtr, drawable, drawableX, drawableY, + imageX, imageY, width, height); + } else { + /* + * masterPtr->region describes which parts of the image contain + * valid data. We set this region as the clip mask for the gc, + * setting its origin appropriately, and use it when drawing the + * image. + */ + TkSetRegion(display, instancePtr->gc, instancePtr->masterPtr->validRegion); + XSetClipOrigin(display, instancePtr->gc, drawableX - imageX, + drawableY - imageY); + XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc, + imageX, imageY, (unsigned) width, (unsigned) height, + drawableX, drawableY); + XSetClipMask(display, instancePtr->gc, None); + XSetClipOrigin(display, instancePtr->gc, 0, 0); + } + XFlush (display); } /* @@ -2789,6 +3077,9 @@ masterPtr->ditherY = 0; } } + + /*GPS*/ + ToggleComplexAlphaIfNeeded(masterPtr); /* * Now adjust the sizes of the pixmaps for all of the instances.