b8180d9f6d41dc708a2f249ba892cbca311e7a06
jcasper
  Mon Feb 27 11:38:55 2023 -0800
Adding transparency support for colors refs #30569

diff --git src/lib/basicBed.c src/lib/basicBed.c
index fa0db23..5d46a6f 100644
--- src/lib/basicBed.c
+++ src/lib/basicBed.c
@@ -10,31 +10,31 @@
 /* Copyright (C) 2014 The Regents of the University of California 
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 
 #include "common.h"
 #include "hash.h"
 #include "linefile.h"
 #include "dystring.h"
 #include "sqlNum.h"
 #include "sqlList.h"
 #include "rangeTree.h"
 #include "binRange.h"
 #include "asParse.h"
 #include "htmlColor.h"
 #include "basicBed.h"
-
+#include "memgfx.h"
 
 void bedStaticLoad(char **row, struct bed *ret)
 /* Load a row from bed table into ret.  The contents of ret will
  * be replaced at the next call to this function. */
 {
 ret->chrom = row[0];
 ret->chromStart = sqlUnsigned(row[1]);
 ret->chromEnd = sqlUnsigned(row[2]);
 ret->name = row[3];
 }
 
 struct bed *bedLoad(char **row)
 /* Load a bed from row fetched with select * from bed
  * from database.  Dispose of this with bedFree(). */
 {
@@ -1014,62 +1014,95 @@
         assert(size > 1);
 	hashAdd(hash, name, bk);
         }
     }
 while (lineFileNextRow(bf, row, ArraySize(row)))
     {
     bed = bedLoadN(row, wordCount);
     bk = hashMustFindVal(hash, bed->chrom);
     binKeeperAdd(bk, bed->chromStart, bed->chromEnd, bed);
     }
 lineFileClose(&bf);
 lineFileClose(&lf);
 return hash;
 }
 
+struct rgbColor bedColorToRgb(unsigned int color)
+/* Convert from the bed concept of a color uint, where the rgb bits
+ * are always in the same order, to a memgfx color structure. */
+{
+    Color gfxColor = bedColorToGfxColor(color);
+    return colorIxToRgb(gfxColor);
+}
+
+Color bedColorToGfxColor(unsigned int color)
+/* Convert from the bed concept of a color uint, where the rgb bits
+ * are always in the same order, to a memgfx concept of color where
+ * the bit order depends on architecture. Assumes that a bed color
+ * will never have 0 alpha. */
+{
+    int r,g,b,a;
+    a = (color & 0xff000000) >> 24;
+    if (a == 0)
+        a = 0xff;
+    r = (color & 0xff0000) >> 16;
+    g = (color & 0xff00) >> 8;
+    b = (color & 0xff);
+    return MAKECOLOR_32_A(r,g,b,a);
+}
+
 void bedOutputRgb(FILE *f, unsigned int color)
-/*      Output a string: "r,g,b" for 24 bit number */
+/*      Output a string: "r,g,b" for 24 bit number.  Note
+ *      that this ignores any associated alpha value. */
 {
-int colorIx = (int)color;
-struct rgbColor rgb = colorIxToRgb(colorIx);
-//fprintf(f, "%d,%d,%d", rgb.r, rgb.g, rgb.b);
-// FIXME: endian issue ??
-fprintf(f, "%d,%d,%d", rgb.b, rgb.g, rgb.r);
+struct rgbColor rgb = bedColorToRgb(color);
+fprintf(f, "%d,%d,%d", rgb.r, rgb.g, rgb.b);
 }
 
-int bedParseRgb(char *itemRgb)
-/*      parse a string: "r,g,b" into three unsigned char values
-        returned as 24 bit number, or -1 for failure */
+unsigned int bedParseRgb(char *itemRgb)
+/*      parse a string: "r,g,b" with optional ",a" into three or four unsigned
+ *      char values returned as 32 bit number, or -1 for failure.  Byte order
+ *      has alpha in the highest-order byte, then r, then g, then b in the
+ *      lowest-order byte. This is a "bed" concept of an unsigned color,
+ *      which may not match the way the graphics libraries handle color bytes. */
 {
 char dupe[64];
 int wordCount;
 char *row[4];
 
 strncpy(dupe, itemRgb, sizeof(dupe));
 wordCount = chopString(dupe, ",", row, ArraySize(row));
 
-if ((wordCount != 3) || (!isdigit(row[0][0]) ||
-    !isdigit(row[1][0]) || !isdigit(row[2][0])))
-        return (-1);
+if ((wordCount == 3) && (isdigit(row[0][0]) &&
+    isdigit(row[1][0]) && isdigit(row[2][0])))
+        return ( ((atoi(row[0]) & 0xff) << 16) |
+                ((atoi(row[1]) & 0xff) << 8) |
+                (atoi(row[2]) & 0xff) |
+                (0xff << 24));
 
+if ((wordCount == 4) && (isdigit(row[0][0]) &&
+    isdigit(row[1][0]) && isdigit(row[2][0]) && isdigit(row[3][0])))
         return ( ((atoi(row[0]) & 0xff) << 16) |
                 ((atoi(row[1]) & 0xff) << 8) |
-        (atoi(row[2]) & 0xff) );
+                (atoi(row[2]) & 0xff) |
+                ((atoi(row[3]) & 0xff) << 24) );
+
+return (-1);
 }
 
-int bedParseColor(char *colorSpec)
-/* Parse an HTML color string, a  string of 3 comma-sep unsigned color values 0-255, 
+unsigned int bedParseColor(char *colorSpec)
+/* Parse an HTML color string, a  string of 3 or 4 comma-sep unsigned color values 0-255, 
  * or a 6-digit hex string  preceded by #. 
  * O/w return unsigned integer value.  Return -1 on error */
 {
 if (strchr(colorSpec,','))
     return bedParseRgb(colorSpec);
 unsigned rgb;
 if (htmlColorForCode(colorSpec, &rgb))
     return rgb;
 if (htmlColorForName(colorSpec, &rgb))
     return rgb;
 return sqlUnsigned(colorSpec);
 }
 
 long long bedTotalSize(struct bed *bedList)
 /* Add together sizes of all beds in list. */
@@ -1474,34 +1507,41 @@
 		   bed->name, bed->chromStart, bed->chromEnd,
 		   bed->thickStart, bed->thickEnd);
     }
 else
      bed->thickEnd = bed->chromEnd;
 
 if (bedFieldCount > 8)
     {
     if (strchr(row[8],','))
 	{
 	unsigned char colors[4];
 	char *saveColorString = cloneString(row[8]);
 	int numColors = lineFileAllIntsArray(lf, row, 8, colors, sizeof colors, FALSE, 1, "integer", FALSE);
 	if (numColors == 3)
 	    {
-	    bed->itemRgb = (((unsigned)colors[0]) << 2*8) | (((unsigned)colors[1]) << 1*8) | (unsigned)colors[2];
+	    bed->itemRgb = (0xff << 3*8) | (((unsigned)colors[0]) << 2*8) | (((unsigned)colors[1]) << 1*8) | (unsigned)colors[2];
+	    }
+	else
+            {
+            if (numColors == 4)
+                {
+                bed->itemRgb = (((unsigned)colors[3]) << 3*8) | (((unsigned)colors[0]) << 2*8) | (((unsigned)colors[1]) << 1*8) | (unsigned)colors[2];
                 }
             else
                 lineFileAbort(lf, "Expecting color to consist of r,g,b values from 0 to 255. Got [%s]", saveColorString);
+            }
 	freeMem(saveColorString);
 	}
     else 
 	{
 	lineFileAllInts(lf, row, 8, &bed->itemRgb, FALSE, 4, "integer", FALSE);
 	}
     }
 
 int tempArraySize = 1;	// How big arrays are below
 if (bedFieldCount > 9)
     {
     lineFileAllInts(lf, row, 9, &bed->blockCount, FALSE, 4, "integer", FALSE);
     if (!(bed->blockCount >= 1))
 	lineFileAbort(lf, "Expecting blockCount (%d) to be 1 or more.", bed->blockCount);
     tempArraySize = bed->blockCount;