src/lib/memgfx.c 1.54

1.54 2010/06/05 19:29:53 braney
add support for 32-bit color (make USE_PNG have global consequence)
Index: src/lib/memgfx.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/lib/memgfx.c,v
retrieving revision 1.53
retrieving revision 1.54
diff -b -B -U 4 -r1.53 -r1.54
--- src/lib/memgfx.c	22 Apr 2010 19:35:38 -0000	1.53
+++ src/lib/memgfx.c	5 Jun 2010 19:29:53 -0000	1.54
@@ -11,10 +11,33 @@
 #include "vGfx.h"
 #include "vGfxPrivate.h"
 #include "colHash.h"
 
+#define MAKECOLOR_32(r,g,b) (((unsigned int)0xff<<24) | ((unsigned int)b<<16) | ((unsigned int)g << 8) | (unsigned int)r)
+
 static char const rcsid[] = "$Id$";
 
+Color multiply(Color src, Color new)
+{
+#ifdef COLOR32
+unsigned char rs = (src >> 0) & 0xff;
+unsigned char gs = (src >> 8) & 0xff;
+unsigned char bs = (src >> 16) & 0xff;
+unsigned char rn = (new >> 0) & 0xff;
+unsigned char gn = (new >> 8) & 0xff;
+unsigned char bn = (new >> 16) & 0xff;
+
+unsigned char ro = ((unsigned) rn * rs) / 255;
+unsigned char go = ((unsigned) gn * gs) / 255;
+unsigned char bo = ((unsigned) bn * bs) / 255;
+return MAKECOLOR_32(ro, go, bo);
+#else
+/* no multiply write mode in 8 bit */
+return new;
+#endif /* COLOR32 */
+}
+
+
 #ifndef min3
 #define min3(x,y,z) (min(x,min(y,z)))
 /* Return min of x,y, and z. */
 #endif
@@ -23,22 +46,40 @@
 #define max3(x,y,z) (max(x,max(y,z)))
 /* Return max of x,y, and z. */
 #endif
 
+void _mgPutDotMultiply(struct memGfx *mg, int x, int y,Color color)
+{
+Color src = *_mgPixAdr(mg,x,y);
+*_mgPixAdr(mg,x,y) = multiply(src, color);
+}
+
 
 static void mgSetDefaultColorMap(struct memGfx *mg)
 /* Set up default color map for a memGfx. */
 {
+#ifdef COLOR32
+    return;
+#else
+
 /* Note dependency in order here and in MG_WHITE, MG_BLACK, etc. */
 int i;
 for (i=0; i<ArraySize(mgFixedColors); ++i)
     {
     struct rgbColor *c = &mgFixedColors[i];
     mgAddColor(mg, c->r, c->g, c->b);
     }
+#endif
 }
 
 
+
+void mgSetWriteMode(struct memGfx *mg, unsigned int writeMode)
+/* Set write mode */
+{
+mg->writeMode = writeMode;
+}
+
 void mgSetClip(struct memGfx *mg, int x, int y, int width, int height)
 /* Set clipping rectangle. */
 {
 int x2, y2;
@@ -69,46 +110,68 @@
 {
 struct memGfx *mg;
 
 mg = needMem(sizeof(*mg));
-mg->pixels = needLargeMem(width*height);
 mg->width = width;
 mg->height = height;
+mg->pixels = needLargeMem(width*height*sizeof(Color));
+#ifndef COLOR32
 mg->colorHash = colHashNew();
+#endif
 mgSetDefaultColorMap(mg);
 mgUnclip(mg);
 return mg;
 }
 
 void mgClearPixels(struct memGfx *mg)
 /* Set all pixels to background. */
 {
+#ifdef COLOR32
+memset((unsigned char *)mg->pixels, 0xff, mg->width*mg->height*sizeof(unsigned int));
+#else
 zeroBytes(mg->pixels, mg->width*mg->height);
+#endif
 }
 
 Color mgFindColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
 /* Returns closest color in color map to rgb values.  If it doesn't
  * already exist in color map and there's room, it will create
  * exact color in map. */
 {
+#ifdef COLOR32
+return MAKECOLOR_32(r,g,b);
+#else
 struct colHashEl *che;
 if ((che = colHashLookup(mg->colorHash, r, g, b)) != NULL)
     return che->ix;
 if (mgColorsFree(mg))
     return mgAddColor(mg, r, g, b);
 return mgClosestColor(mg, r, g, b);
+#endif
 }
 
 
 struct rgbColor mgColorIxToRgb(struct memGfx *mg, int colorIx)
 /* Return rgb value at color index. */
 {
+#ifdef COLOR32
+static struct rgbColor rgb;
+rgb.r = (colorIx >> 0) & 0xff;
+rgb.g = (colorIx >> 8) & 0xff;
+rgb.b = (colorIx >> 16) & 0xff;
+
+return rgb;
+#else
 return mg->colorMap[colorIx];
+#endif
 }
 
 Color mgClosestColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
 /* Returns closest color in color map to r,g,b */
 {
+#ifdef COLOR32
+return MAKECOLOR_32(r,g,b);
+#else
 struct rgbColor *c = mg->colorMap;
 int closestDist = 0x7fffffff;
 int closestIx = -1;
 int dist, dif;
@@ -128,14 +191,18 @@
         }
     ++c;
     }
 return closestIx;
+#endif
 }
 
 
 Color mgAddColor(struct memGfx *mg, unsigned char r, unsigned char g, unsigned char b)
 /* Adds color to end of color map if there's room. */
 {
+#ifdef COLOR32
+return MAKECOLOR_32(r,g,b);
+#else
 int colIx = mg->colorsUsed;
 if (colIx < 256)
     {
     struct rgbColor *c = mg->colorMap + mg->colorsUsed;
@@ -145,14 +212,19 @@
     mg->colorsUsed += 1;
     colHashAdd(mg->colorHash, r, g, b, colIx);
     }
 return (Color)colIx;
+#endif
 }
 
 int mgColorsFree(struct memGfx *mg)
 /* Returns # of unused colors in color map. */
 {
+#ifdef COLOR32
+return 1 << 23;
+#else
 return 256-mg->colorsUsed;
+#endif
 }
 
 void mgFree(struct memGfx **pmg)
 {
@@ -160,15 +232,17 @@
 if (mg != NULL)
     {
     if (mg->pixels != NULL)
 	freeMem(mg->pixels);
+    if (mg->colorHash)
     colHashFree(&mg->colorHash);
     zeroBytes(mg, sizeof(*mg));
     freeMem(mg);
     }
 *pmg = NULL;
 }
 
+#ifndef COLOR32
 static void nonZeroCopy(Color *d, Color *s, int width)
 /* Copy non-zero colors. */
 {
 Color c;
@@ -178,13 +252,16 @@
     if ((c = s[i]) != 0)
         d[i] = c;
     }
 }
+#endif
 
-static void mgPutSegMaybeZeroClear(struct memGfx *mg, int x, int y, int width, Color *dots, boolean zeroClear)
+static void mgPutSegMaybeZeroClear8(struct memGfx *mg, int x, int y, int width, unsigned char *dots, boolean zeroClear)
 /* Put a series of dots starting at x, y and going to right width pixels.
  * Possibly don't put zero dots though. */
 {
+#ifdef COLOR32
+#else
 int x2;
 Color *pt;
 if (y < mg->clipMinY || y > mg->clipMaxY)
     return;
@@ -202,25 +279,30 @@
     pt = _mgPixAdr(mg, x, y);
     if (zeroClear)
         nonZeroCopy(pt, dots, width);
     else
-	memcpy(pt, dots, width);
+        {
+        width *= sizeof(Color);
+        memcpy(pt, dots, width * sizeof(int));
     }
+    }
+#endif /* COLOR32 */
 }
 
-void mgVerticalSmear(struct memGfx *mg,
+void mgVerticalSmear8(struct memGfx *mg,
 	int xOff, int yOff, int width, int height, 
 	unsigned char *dots, boolean zeroClear)
 /* Put a series of one 'pixel' width vertical lines. */
 {
 while (--height >= 0)
     {
-    mgPutSegMaybeZeroClear(mg, xOff, yOff, width, dots, zeroClear);
+    mgPutSegMaybeZeroClear8(mg, xOff, yOff, width, dots, zeroClear);
     ++yOff;
     }
 }
 
-void mgDrawBox(struct memGfx *mg, int x, int y, int width, int height, Color color)
+
+void mgDrawBoxNormal(struct memGfx *mg, int x, int y, int width, int height, Color color)
 {
 int i;
 Color *pt;
 int x2 = x + width;
@@ -243,16 +325,67 @@
     /*colorBin[x][color]++;  increment color count for this pixel */
     wrapCount = _mgBpr(mg) - width;
     while (--height >= 0)
 	{
+        //Color src = *pt;
 	i = width;
 	while (--i >= 0)
 	    *pt++ = color;
 	pt += wrapCount;
 	}
     }
 }
 
+void mgDrawBoxMultiply(struct memGfx *mg, int x, int y, int width, int height, Color color)
+{
+int i;
+Color *pt;
+int x2 = x + width;
+int y2 = y + height;
+int wrapCount;
+
+if (x < mg->clipMinX)
+    x = mg->clipMinX;
+if (y < mg->clipMinY)
+    y = mg->clipMinY;
+if (x2 > mg->clipMaxX)
+    x2 = mg->clipMaxX;
+if (y2 > mg->clipMaxY)
+    y2 = mg->clipMaxY;
+width = x2-x;
+height = y2-y;
+if (width > 0 && height > 0)
+    {
+    pt = _mgPixAdr(mg,x,y);
+    wrapCount = _mgBpr(mg) - width;
+    while (--height >= 0)
+	{
+        Color src = *pt;
+	i = width;
+	while (--i >= 0)
+	    *pt++ = multiply(src, color);
+	pt += wrapCount;
+	}
+    }
+}
+
+void mgDrawBox(struct memGfx *mg, int x, int y, int width, int height, Color color)
+{
+switch(mg->writeMode)
+    {
+    case MG_WRITE_MODE_NORMAL:
+        {
+        mgDrawBoxNormal(mg,x,y, width, height, color);
+        }
+        break;
+    case MG_WRITE_MODE_MULTIPLY:
+        {
+        mgDrawBoxMultiply(mg,x,y, width, height, color);
+        }
+        break;
+    }
+}
+
 void mgBrezy(struct memGfx *mg, int x1, int y1, int x2, int y2, Color color,
 	int yBase, boolean fillFromBase)
 /* Brezenham line algorithm.  Optionally fill in under line. */
 {
@@ -385,19 +518,19 @@
 {
 mgBrezy(mg, x1, y1, x2, y2, color, bottom, TRUE);
 }
 
-void mgPutSeg(struct memGfx *mg, int x, int y, int width, Color *dots)
+void mgPutSeg8(struct memGfx *mg, int x, int y, int width, unsigned char *dots)
 /* Put a series of dots starting at x, y and going to right width pixels. */
 {
-mgPutSegMaybeZeroClear(mg, x, y, width, dots, FALSE);
+mgPutSegMaybeZeroClear8(mg, x, y, width, dots, FALSE);
 }
 
-void mgPutSegZeroClear(struct memGfx *mg, int x, int y, int width, Color *dots)
+void mgPutSegZeroClear8(struct memGfx *mg, int x, int y, int width, unsigned char *dots)
 /* Put a series of dots starting at x, y and going to right width pixels.
  * Don't put zero dots though. */
 {
-mgPutSegMaybeZeroClear(mg, x, y, width, dots, TRUE);
+mgPutSegMaybeZeroClear8(mg, x, y, width, dots, TRUE);
 }
 
 
 void mgDrawHorizontalLine(struct memGfx *mg, int y1, Color color)
@@ -458,9 +591,9 @@
 	struct memGfx *dest, int destX, int destY, 
 	Color color, Color backgroundColor)
 {
 UBYTE *inLine;
-UBYTE *outLine;
+Color *outLine;
 UBYTE inLineBit;
 
 if (!mgClipForBlit(&width, &height, &bitX, &bitY, dest, &destX, &destY))
     return;
@@ -470,9 +603,9 @@
 outLine = _mgPixAdr(dest,destX,destY);
 while (--height >= 0)
     {
     UBYTE *in = inLine;
-    UBYTE *out = outLine;
+    Color *out = outLine;
     UBYTE inBit = inLineBit;
     UBYTE inByte = *in++;
     int i = width;
     while (--i >= 0)
@@ -496,9 +629,9 @@
 	struct memGfx *dest, int destX, int destY, 
 	Color color, Color backgroundColor)
 {
 UBYTE *inLine;
-UBYTE *outLine;
+Color *outLine;
 UBYTE inLineBit;
 
 if (!mgClipForBlit(&width, &height, &bitX, &bitY, dest, &destX, &destY))
     return;
@@ -507,9 +640,9 @@
 outLine = _mgPixAdr(dest,destX,destY);
 while (--height >= 0)
     {
     UBYTE *in = inLine;
-    UBYTE *out = outLine;
+    Color *out = outLine;
     UBYTE inBit = inLineBit;
     UBYTE inByte = *in++;
     int i = width;
     while (--i >= 0)
@@ -780,11 +913,12 @@
 vg->textRight = (vg_textRight)mgTextRight;
 vg->textCentered = (vg_textCentered)mgTextCentered;
 vg->findColorIx = (vg_findColorIx)mgFindColor;
 vg->colorIxToRgb = (vg_colorIxToRgb)mgColorIxToRgb;
+vg->setWriteMode = (vg_setWriteMode)mgSetWriteMode;
 vg->setClip = (vg_setClip)mgSetClip;
 vg->unclip = (vg_unclip)mgUnclip;
-vg->verticalSmear = (vg_verticalSmear)mgVerticalSmear;
+vg->verticalSmear8 = (vg_verticalSmear8)mgVerticalSmear8;
 vg->fillUnder = (vg_fillUnder)mgFillUnder;
 vg->drawPoly = (vg_drawPoly)mgDrawPoly;
 vg->setHint = (vg_setHint)mgSetHint;
 vg->getHint = (vg_getHint)mgGetHint;