summaryrefslogtreecommitdiff
path: root/src/runtime/rcolor.r
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/rcolor.r')
-rw-r--r--src/runtime/rcolor.r722
1 files changed, 722 insertions, 0 deletions
diff --git a/src/runtime/rcolor.r b/src/runtime/rcolor.r
new file mode 100644
index 0000000..a3ac813
--- /dev/null
+++ b/src/runtime/rcolor.r
@@ -0,0 +1,722 @@
+/*
+ * File: rcolor.r
+ * graphics tables and functions related to color
+ */
+
+#ifdef Graphics
+
+static int colorphrase (char *buf, long *r, long *g, long *b);
+static double rgbval (double n1, double n2, double hue);
+
+/*
+ * Structures and tables used for color parsing.
+ * Tables must be kept lexically sorted.
+ */
+
+typedef struct { /* color name entry */
+ char name[8]; /* basic color name */
+ char ish[12]; /* -ish form */
+ short hue; /* hue, in degrees */
+ char lgt; /* lightness, as percentage */
+ char sat; /* saturation, as percentage */
+} colrname;
+
+typedef struct { /* arbitrary lookup entry */
+ char word[10]; /* word */
+ char val; /* value, as percentage */
+} colrmod;
+
+static colrname colortable[] = { /* known colors */
+ /* color ish-form hue lgt sat */
+ { "black", "blackish", 0, 0, 0 },
+ { "blue", "bluish", 240, 50, 100 },
+ { "brown", "brownish", 30, 25, 100 },
+ { "cyan", "cyanish", 180, 50, 100 },
+ { "gray", "grayish", 0, 50, 0 },
+ { "green", "greenish", 120, 50, 100 },
+ { "grey", "greyish", 0, 50, 0 },
+ { "magenta", "magentaish", 300, 50, 100 },
+ { "orange", "orangish", 15, 50, 100 },
+ { "pink", "pinkish", 345, 75, 100 },
+ { "purple", "purplish", 270, 50, 100 },
+ { "red", "reddish", 0, 50, 100 },
+ { "violet", "violetish", 270, 75, 100 },
+ { "white", "whitish", 0, 100, 0 },
+ { "yellow", "yellowish", 60, 50, 100 },
+ };
+
+static colrmod lighttable[] = { /* lightness modifiers */
+ { "dark", 0 },
+ { "deep", 0 }, /* = very dark (see code) */
+ { "light", 100 },
+ { "medium", 50 },
+ { "pale", 100 }, /* = very light (see code) */
+ };
+
+static colrmod sattable[] = { /* saturation levels */
+ { "moderate", 50 },
+ { "strong", 75 },
+ { "vivid", 100 },
+ { "weak", 25 },
+ };
+
+/*
+ * parsecolor(w, s, &r, &g, &b) - parse a color specification
+ *
+ * parsecolor interprets a color specification and produces r/g/b values
+ * scaled linearly from 0 to 65535. parsecolor returns Succeeded or Failed.
+ *
+ * An Icon color specification can be any of the forms
+ *
+ * #rgb (hexadecimal digits)
+ * #rrggbb
+ * #rrrgggbbb
+ * #rrrrggggbbbb
+ * nnnnn,nnnnn,nnnnn (integers 0 - 65535)
+ * <Icon color phrase>
+ * <native color spec>
+ */
+
+int parsecolor(w, buf, r, g, b)
+wbp w;
+char *buf;
+long *r, *g, *b;
+ {
+ int len, mul;
+ char *fmt, c;
+ double dr, dg, db;
+
+ *r = *g = *b = 0L;
+
+ /* trim leading spaces */
+ while (isspace(*buf))
+ buf++;
+
+ /* try interpreting as three comma-separated integers */
+ if (sscanf(buf, "%lf,%lf,%lf%c", &dr, &dg, &db, &c) == 3) {
+ *r = dr;
+ *g = dg;
+ *b = db;
+ if (*r>=0 && *r<=65535 && *g>=0 && *g<=65535 && *b>=0 && *b<=65535)
+ return Succeeded;
+ else
+ return Failed;
+ }
+
+ /* try interpreting as a hexadecimal value */
+ if (*buf == '#') {
+ buf++;
+ for (len = 0; isalnum(buf[len]); len++);
+ switch (len) {
+ case 3: fmt = "%1x%1x%1x%c"; mul = 0x1111; break;
+ case 6: fmt = "%2x%2x%2x%c"; mul = 0x0101; break;
+ case 9: fmt = "%3x%3x%3x%c"; mul = 0x0010; break;
+ case 12: fmt = "%4x%4x%4x%c"; mul = 0x0001; break;
+ default: return Failed;
+ }
+ if (sscanf(buf, fmt, r, g, b, &c) != 3)
+ return Failed;
+ *r *= mul;
+ *g *= mul;
+ *b *= mul;
+ return Succeeded;
+ }
+
+ /* try interpreting as a color phrase or as a native color spec */
+ if (colorphrase(buf, r, g, b) || nativecolor(w, buf, r, g, b))
+ return Succeeded;
+ else
+ return Failed;
+ }
+
+/*
+ * colorphrase(s, &r, &g, &b) -- parse Icon color phrase.
+ *
+ * An Icon color phrase matches the pattern
+ *
+ * weak
+ * pale moderate
+ * light strong
+ * [[very] medium ] [ vivid ] [color[ish]] color
+ * dark
+ * deep
+ *
+ * where "color" is any of:
+ *
+ * black gray grey white pink violet brown
+ * red orange yellow green cyan blue purple magenta
+ *
+ * A single space or hyphen separates each word from its neighbor. The
+ * default lightness is "medium", and the default saturation is "vivid".
+ *
+ * "pale" means "very light"; "deep" means "very dark".
+ *
+ * This naming scheme is based loosely on
+ * A New Color-Naming System for Graphics Languages
+ * Toby Berk, Lee Brownston, and Arie Kaufman
+ * IEEE Computer Graphics & Applications, May 1982
+ */
+
+static int colorphrase(buf, r, g, b)
+char *buf;
+long *r, *g, *b;
+ {
+ int len, very;
+ char c, *p, *ebuf, cbuffer[MAXCOLORNAME];
+ float lgt, sat, blend, bl2, m1, m2;
+ float h1, l1, s1, h2, l2, s2, r2, g2, b2;
+
+ lgt = -1.0; /* default no lightness mod */
+ sat = 1.0; /* default vivid saturation */
+ len = strlen(buf);
+ while (isspace(buf[len-1]))
+ len--; /* trim trailing spaces */
+
+ if (len >= sizeof(cbuffer))
+ return 0; /* if too long for valid Icon spec */
+
+ /*
+ * copy spec, lowering case and replacing spaces and hyphens with NULs
+ */
+ for(p = cbuffer; (c = *buf) != 0; p++, buf++) {
+ if (isupper(c)) *p = tolower(c);
+ else if (c == ' ' || c == '-') *p = '\0';
+ else *p = c;
+ }
+ *p = '\0';
+
+ buf = cbuffer;
+ ebuf = buf + len;
+ /* check for "very" */
+ if (strcmp(buf, "very") == 0) {
+ very = 1;
+ buf += strlen(buf) + 1;
+ if (buf >= ebuf)
+ return 0;
+ }
+ else
+ very = 0;
+
+ /* check for lightness adjective */
+ p = qsearch(buf, (char *)lighttable,
+ ElemCount(lighttable), ElemSize(lighttable), strcmp);
+ if (p) {
+ /* set the "very" flag for "pale" or "deep" */
+ if (strcmp(buf, "pale") == 0)
+ very = 1; /* pale = very light */
+ else if (strcmp(buf, "deep") == 0)
+ very = 1; /* deep = very dark */
+ /* skip past word */
+ buf += strlen(buf) + 1;
+ if (buf >= ebuf)
+ return 0;
+ /* save lightness value, but ignore "medium" */
+ if ((((colrmod *)p) -> val) != 50)
+ lgt = ((colrmod *)p) -> val / 100.0;
+ }
+ else if (very)
+ return 0;
+
+ /* check for saturation adjective */
+ p = qsearch(buf, (char *)sattable,
+ ElemCount(sattable), ElemSize(sattable), strcmp);
+ if (p) {
+ sat = ((colrmod *)p) -> val / 100.0;
+ buf += strlen(buf) + 1;
+ if (buf >= ebuf)
+ return 0;
+ }
+
+ if (buf + strlen(buf) >= ebuf)
+ blend = h1 = l1 = s1 = 0.0; /* only one word left */
+ else {
+ /* we have two (or more) name words; get the first */
+ if ((p = qsearch(buf, colortable[0].name,
+ ElemCount(colortable), ElemSize(colortable), strcmp)) != NULL) {
+ blend = 0.5;
+ }
+ else if ((p = qsearch(buf, colortable[0].ish,
+ ElemCount(colortable), ElemSize(colortable), strcmp)) != NULL) {
+ p -= sizeof(colortable[0].name);
+ blend = 0.25;
+ }
+ else
+ return 0;
+
+ h1 = ((colrname *)p) -> hue;
+ l1 = ((colrname *)p) -> lgt / 100.0;
+ s1 = ((colrname *)p) -> sat / 100.0;
+ buf += strlen(buf) + 1;
+ }
+
+ /* process second (or only) name word */
+ p = qsearch(buf, colortable[0].name,
+ ElemCount(colortable), ElemSize(colortable), strcmp);
+ if (!p || buf + strlen(buf) < ebuf)
+ return 0;
+ h2 = ((colrname *)p) -> hue;
+ l2 = ((colrname *)p) -> lgt / 100.0;
+ s2 = ((colrname *)p) -> sat / 100.0;
+
+ /* at this point we know we have a valid spec */
+
+ /* interpolate hls specs */
+ if (blend > 0) {
+ bl2 = 1.0 - blend;
+
+ if (s1 == 0.0)
+ ; /* use h2 unchanged */
+ else if (s2 == 0.0)
+ h2 = h1;
+ else if (h2 - h1 > 180)
+ h2 = blend * h1 + bl2 * (h2 - 360);
+ else if (h1 - h2 > 180)
+ h2 = blend * (h1 - 360) + bl2 * h2;
+ else
+ h2 = blend * h1 + bl2 * h2;
+ if (h2 < 0)
+ h2 += 360;
+
+ l2 = blend * l1 + bl2 * l2;
+ s2 = blend * s1 + bl2 * s2;
+ }
+
+ /* apply saturation and lightness modifiers */
+ if (lgt >= 0.0) {
+ if (very)
+ l2 = (2 * lgt + l2) / 3.0;
+ else
+ l2 = (lgt + 2 * l2) / 3.0;
+ }
+ s2 *= sat;
+
+ /* convert h2,l2,s2 to r2,g2,b2 */
+ /* from Foley & Van Dam, 1st edition, p. 619 */
+ /* beware of dangerous typos in 2nd edition */
+ if (s2 == 0)
+ r2 = g2 = b2 = l2;
+ else {
+ if (l2 < 0.5)
+ m2 = l2 * (1 + s2);
+ else
+ m2 = l2 + s2 - l2 * s2;
+ m1 = 2 * l2 - m2;
+ r2 = rgbval(m1, m2, h2 + 120);
+ g2 = rgbval(m1, m2, h2);
+ b2 = rgbval(m1, m2, h2 - 120);
+ }
+
+ /* scale and convert the calculated result */
+ *r = 65535 * r2;
+ *g = 65535 * g2;
+ *b = 65535 * b2;
+
+ return 1;
+ }
+
+/*
+ * rgbval(n1, n2, hue) - helper function for HLS to RGB conversion
+ */
+static double rgbval(n1, n2, hue)
+double n1, n2, hue;
+ {
+ if (hue > 360)
+ hue -= 360;
+ else if (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ return n1 + (n2 - n1) * hue / 60.0;
+ else if (hue < 180)
+ return n2;
+ else if (hue < 240)
+ return n1 + (n2 - n1) * (240 - hue) / 60.0;
+ else
+ return n1;
+ }
+
+/*
+ * Static data for XDrawImage and XPalette functions
+ */
+
+/*
+ * c<n>list - the characters of the palettes that are not contiguous ASCII
+ */
+char c1list[] = "0123456789?!nNAa#@oOBb$%pPCc&|\
+qQDd,.rREe;:sSFf+-tTGg*/uUHh`'vVIi<>wWJj()xXKk[]yYLl{}zZMm^=";
+char c2list[] = "kbgcrmywx";
+char c3list[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZabcd";
+char c4list[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}$%&*+-/?@";
+
+/*
+ * cgrays -- lists of grayscales contained within color palettes
+ */
+static char *cgrays[] = { "0123456", "kxw", "@abMcdZ", "0$%&L*+-g/?@}",
+"\0}~\177\200\37\201\202\203\204>\205\206\207\210]\211\212\213\214|",
+"\0\330\331\332\333\334+\335\336\337\340\341V\342\343\344\345\346\201\
+\347\350\351\352\353\254\354\355\356\357\360\327" };
+
+/*
+ * c1cube - a precomputed mapping from a color cube to chars in c1 palette
+ *
+ * This is 10x10x10 cube (A Thousand Points of Light).
+ */
+#define C1Side 10 /* length of one side of C1 cube */
+static char c1cube[] = {
+ '0', '0', 'w', 'w', 'w', 'W', 'W', 'W', 'J', 'J', '0', '0', 'v', 'v', 'v',
+ 'W', 'W', 'W', 'J', 'J', 's', 't', 't', 'v', 'v', 'V', 'V', 'V', 'V', 'J',
+ 's', 't', 't', 'u', 'u', 'V', 'V', 'V', 'V', 'I', 's', 't', 't', 'u', 'u',
+ 'V', 'V', 'V', 'I', 'I', 'S', 'S', 'T', 'T', 'T', 'U', 'U', 'U', 'I', 'I',
+ 'S', 'S', 'T', 'T', 'T', 'U', 'U', 'U', 'U', 'I', 'S', 'S', 'T', 'T', 'T',
+ 'U', 'U', 'U', 'U', 'H', 'F', 'F', 'T', 'T', 'G', 'G', 'U', 'U', 'H', 'H',
+ 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', 'H', '0', '0', 'x', 'x', 'x',
+ 'W', 'W', 'W', 'J', 'J', '!', '1', '1', 'v', 'v', 'W', 'W', 'W', 'J', 'J',
+ 'r', '1', '1', 'v', 'v', 'V', 'V', 'V', 'j', 'j', 'r', 'r', 't', 'u', 'u',
+ 'V', 'V', 'V', 'j', 'j', 'r', 'r', 't', 'u', 'u', 'V', 'V', 'V', 'I', 'I',
+ 'S', 'S', 'T', 'T', 'T', 'U', 'U', 'U', 'I', 'I', 'S', 'S', 'T', 'T', 'T',
+ 'U', 'U', 'U', 'i', 'i', 'S', 'S', 'T', 'T', 'T', 'U', 'U', 'U', 'i', 'i',
+ 'F', 'F', 'f', 'f', 'G', 'G', 'g', 'g', 'H', 'H', 'F', 'F', 'f', 'f', 'G',
+ 'G', 'g', 'g', 'H', 'H', 'n', 'z', 'x', 'x', 'x', 'X', 'X', 'X', 'X', 'J',
+ '!', '1', '1', 'x', 'x', 'X', 'X', 'X', 'j', 'j', 'p', '1', '1', '2', '2',
+ ')', 'V', 'j', 'j', 'j', 'r', 'r', '2', '2', '2', ')', 'V', 'j', 'j', 'j',
+ 'r', 'r', '2', '2', '2', '>', '>', '>', 'j', 'j', 'R', 'R', '-', '-', '/',
+ '/', '>', '>', 'i', 'i', 'R', 'R', 'R', 'T', '/', '/', '\'','i', 'i', 'i',
+ 'R', 'R', 'f', 'f', '/', '/', 'g', 'g', 'i', 'i', 'R', 'f', 'f', 'f', 'f',
+ 'g', 'g', 'g', 'h', 'h', 'F', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'h', 'h',
+ 'n', 'z', 'z', 'y', 'y', 'X', 'X', 'X', 'X', 'K', 'o', 'o', 'z', 'y', 'y',
+ 'X', 'X', 'X', 'j', 'j', 'p', 'p', '2', '2', '2', ')', 'X', 'j', 'j', 'j',
+ 'q', 'q', '2', '2', '2', ')', ')', 'j', 'j', 'j', 'q', 'q', '2', '2', '2',
+ '>', '>', '>', 'j', 'j', 'R', 'R', '-', '-', '/', '/', '>', '>', 'i', 'i',
+ 'R', 'R', 'R', '-', '/', '/', '\'','\'','i', 'i', 'R', 'R', 'f', 'f', '/',
+ '/', '\'','g', 'i', 'i', 'R', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'h', 'h',
+ 'E', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'h', 'h', 'n', 'z', 'z', 'y', 'y',
+ 'X', 'X', 'X', 'K', 'K', 'o', 'o', 'z', 'y', 'y', 'X', 'X', 'X', 'K', 'K',
+ '?', '?', '?', '2', '2', ']', ']', ']', 'j', 'j', 'q', 'q', '2', '2', '2',
+ ']', ']', ']', 'j', 'j', 'q', 'q', '2', '2', '3', '3', '>', '>', 'j', 'j',
+ 'R', 'R', ':', ':', '3', '3', '>', '>', 'i', 'i', 'R', 'R', ':', ':', ':',
+ '/', '\'','\'','i', 'i', 'R', 'R', ':', ':', ':', '/', '\'','\'','i', 'i',
+ 'E', 'E', 'f', 'f', 'f', 'g', 'g', 'g', 'h', 'h', 'E', 'E', 'f', 'f', 'f',
+ 'g', 'g', 'g', 'h', 'h', 'N', 'N', 'Z', 'Z', 'Z', 'Y', 'Y', 'Y', 'K', 'K',
+ 'O', 'O', 'Z', 'Z', 'Z', 'Y', 'Y', 'Y', 'K', 'K', '?', '?', '?', '@', '=',
+ ']', ']', ']', 'k', 'k', 'P', 'P', '@', '@', '=', ']', ']', ']', 'k', 'k',
+ 'P', 'P', '%', '%', '%', '3', ']', ']', 'k', 'k', 'Q', 'Q', '|', '|', '3',
+ '3', '4', '4', '(', '(', 'Q', 'Q', ':', ':', ':', '4', '4', '4', '(', '(',
+ 'Q', 'Q', ':', ':', ':', '4', '4', '4', '<', '<', 'E', 'E', 'e', 'e', 'e',
+ '+', '+', '*', '*', '<', 'E', 'E', 'e', 'e', 'e', '+', '+', '*', '*', '`',
+ 'N', 'N', 'Z', 'Z', 'Z', 'Y', 'Y', 'Y', 'Y', 'K', 'O', 'O', 'Z', 'Z', 'Z',
+ 'Y', 'Y', 'Y', 'k', 'k', 'O', 'O', 'O', 'Z', '=', '=', '}', 'k', 'k', 'k',
+ 'P', 'P', 'P', '@', '=', '=', '}', '}', 'k', 'k', 'P', 'P', '%', '%', '%',
+ '=', '}', '}', 'k', 'k', 'Q', 'Q', '|', '|', '|', '4', '4', '4', '(', '(',
+ 'Q', 'Q', '.', '.', '.', '4', '4', '4', '(', '(', 'Q', 'Q', 'e', '.', '.',
+ '4', '4', '4', '<', '<', 'Q', 'e', 'e', 'e', 'e', '+', '+', '*', '*', '<',
+ 'E', 'e', 'e', 'e', 'e', '+', '+', '*', '*', '`', 'N', 'N', 'Z', 'Z', 'Z',
+ 'Y', 'Y', 'Y', 'Y', 'L', 'O', 'O', 'Z', 'Z', 'Z', 'Y', 'Y', 'Y', 'k', 'k',
+ 'O', 'O', 'O', 'a', '=', '=', 'm', 'k', 'k', 'k', 'P', 'P', 'a', 'a', '=',
+ '=', '}', 'k', 'k', 'k', 'P', 'P', '%', '%', '%', '=', '}', '8', '8', '8',
+ 'Q', 'Q', '|', '|', '|', '4', '4', '8', '8', '8', 'Q', 'Q', 'c', '.', '.',
+ '4', '4', '4', '[', '[', 'Q', 'Q', 'c', 'c', '9', '9', '4', '5', '5', '<',
+ 'Q', 'e', 'e', 'e', 'e', ';', ';', '5', '5', '<', 'D', 'e', 'e', 'e', 'e',
+ ';', ';', ';', '*', '`', 'A', 'A', 'Z', 'Z', 'M', 'M', 'Y', 'Y', 'L', 'L',
+ 'A', 'A', 'a', 'a', 'M', 'M', 'm', 'm', 'L', 'L', 'B', 'B', 'a', 'a', 'a',
+ 'm', 'm', 'm', 'l', 'l', 'B', 'B', 'a', 'a', 'a', 'm', 'm', 'm', 'l', 'l',
+ 'C', 'C', 'b', 'b', 'b', '7', '7', '7', '8', '8', 'C', 'C', 'b', 'b', 'b',
+ '7', '7', '^', '[', '[', 'Q', 'c', 'c', 'c', 'c', '#', '#', '^', '[', '[',
+ 'Q', 'c', 'c', 'c', '9', '9', '$', '5', '5', '[', 'D', 'D', 'd', 'd', '9',
+ '&', '&', '5', '5', '6', 'D', 'D', 'd', 'd', 'd', ';', ';', ';', '6', '6',
+ 'A', 'A', 'A', 'M', 'M', 'M', 'M', 'L', 'L', 'L', 'A', 'A', 'a', 'a', 'M',
+ 'M', 'm', 'm', 'L', 'L', 'B', 'B', 'a', 'a', 'a', 'm', 'm', 'm', 'l', 'l',
+ 'B', 'B', 'a', 'a', 'a', 'm', 'm', 'm', 'l', 'l', 'C', 'C', 'b', 'b', 'b',
+ '7', '7', '7', 'l', 'l', 'C', 'C', 'b', 'b', 'b', '7', '7', '^', '^', '{',
+ 'C', 'c', 'c', 'c', 'c', '#', '#', '^', '^', '{', 'D', 'c', 'c', 'c', '9',
+ '9', '$', '$', '^', '{', 'D', 'D', 'd', 'd', '9', '&', '&', '&', '6', '6',
+ 'D', 'D', 'd', 'd', 'd', ',', ',', ',', '6', '6'
+};
+
+/*
+ * c1rgb - RGB values for c1 palette entries
+ *
+ * Entry order corresponds to c1list (above).
+ * Each entry gives r,g,b in linear range 0 to 48.
+ */
+static unsigned char c1rgb[] = {
+ 0, 0, 0, /* 0 black */
+ 8, 8, 8, /* 1 very dark gray */
+ 16, 16, 16, /* 2 dark gray */
+ 24, 24, 24, /* 3 gray */
+ 32, 32, 32, /* 4 light gray */
+ 40, 40, 40, /* 5 very light gray */
+ 48, 48, 48, /* 6 white */
+ 48, 24, 30, /* 7 pink */
+ 36, 24, 48, /* 8 violet */
+ 48, 36, 24, /* 9 very light brown */
+ 24, 12, 0, /* ? brown */
+ 8, 4, 0, /* ! very dark brown */
+ 16, 0, 0, /* n very dark red */
+ 32, 0, 0, /* N dark red */
+ 48, 0, 0, /* A red */
+ 48, 16, 16, /* a light red */
+ 48, 32, 32, /* # very light red */
+ 30, 18, 18, /* @ weak red */
+ 16, 4, 0, /* o very dark orange */
+ 32, 8, 0, /* O dark orange */
+ 48, 12, 0, /* B orange */
+ 48, 24, 16, /* b light orange */
+ 48, 36, 32, /* $ very light orange */
+ 30, 21, 18, /* % weak orange */
+ 16, 8, 0, /* p very dark red-yellow */
+ 32, 16, 0, /* P dark red-yellow */
+ 48, 24, 0, /* C red-yellow */
+ 48, 32, 16, /* c light red-yellow */
+ 48, 40, 32, /* & very light red-yellow */
+ 30, 24, 18, /* | weak red-yellow */
+ 16, 16, 0, /* q very dark yellow */
+ 32, 32, 0, /* Q dark yellow */
+ 48, 48, 0, /* D yellow */
+ 48, 48, 16, /* d light yellow */
+ 48, 48, 32, /* , very light yellow */
+ 30, 30, 18, /* . weak yellow */
+ 8, 16, 0, /* r very dark yellow-green */
+ 16, 32, 0, /* R dark yellow-green */
+ 24, 48, 0, /* E yellow-green */
+ 32, 48, 16, /* e light yellow-green */
+ 40, 48, 32, /* ; very light yellow-green */
+ 24, 30, 18, /* : weak yellow-green */
+ 0, 16, 0, /* s very dark green */
+ 0, 32, 0, /* S dark green */
+ 0, 48, 0, /* F green */
+ 16, 48, 16, /* f light green */
+ 32, 48, 32, /* + very light green */
+ 18, 30, 18, /* - weak green */
+ 0, 16, 8, /* t very dark cyan-green */
+ 0, 32, 16, /* T dark cyan-green */
+ 0, 48, 24, /* G cyan-green */
+ 16, 48, 32, /* g light cyan-green */
+ 32, 48, 40, /* * very light cyan-green */
+ 18, 30, 24, /* / weak cyan-green */
+ 0, 16, 16, /* u very dark cyan */
+ 0, 32, 32, /* U dark cyan */
+ 0, 48, 48, /* H cyan */
+ 16, 48, 48, /* h light cyan */
+ 32, 48, 48, /* ` very light cyan */
+ 18, 30, 30, /* ' weak cyan */
+ 0, 8, 16, /* v very dark blue-cyan */
+ 0, 16, 32, /* V dark blue-cyan */
+ 0, 24, 48, /* I blue-cyan */
+ 16, 32, 48, /* i light blue-cyan */
+ 32, 40, 48, /* < very light blue-cyan */
+ 18, 24, 30, /* > weak blue-cyan */
+ 0, 0, 16, /* w very dark blue */
+ 0, 0, 32, /* W dark blue */
+ 0, 0, 48, /* J blue */
+ 16, 16, 48, /* j light blue */
+ 32, 32, 48, /* ( very light blue */
+ 18, 18, 30, /* ) weak blue */
+ 8, 0, 16, /* x very dark purple */
+ 16, 0, 32, /* X dark purple */
+ 24, 0, 48, /* K purple */
+ 32, 16, 48, /* k light purple */
+ 40, 32, 48, /* [ very light purple */
+ 24, 18, 30, /* ] weak purple */
+ 16, 0, 16, /* y very dark magenta */
+ 32, 0, 32, /* Y dark magenta */
+ 48, 0, 48, /* L magenta */
+ 48, 16, 48, /* l light magenta */
+ 48, 32, 48, /* { very light magenta */
+ 30, 18, 30, /* } weak magenta */
+ 16, 0, 8, /* z very dark magenta-red */
+ 32, 0, 16, /* Z dark magenta-red */
+ 48, 0, 24, /* M magenta-red */
+ 48, 16, 32, /* m light magenta-red */
+ 48, 32, 40, /* ^ very light magenta-red */
+ 30, 18, 24, /* = weak magenta-red */
+ };
+
+/*
+ * palnum(d) - return palette number, or 0 if unrecognized.
+ *
+ * returns +1 ... +6 for "c1" through "c6"
+ * returns +1 for &null
+ * returns -2 ... -256 for "g2" through "g256"
+ * returns 0 for unrecognized palette name
+ * returns -1 for non-string argument
+ */
+int palnum(d)
+dptr d;
+ {
+ tended char *s;
+ char c, x;
+ int n;
+
+ if (is:null(*d))
+ return 1;
+ if (!cnv:C_string(*d, s))
+ return -1;
+ if (sscanf(s, "%c%d%c", &c, &n, &x) != 2)
+ return 0;
+ if (c == 'c' && n >= 1 && n <= 6)
+ return n;
+ if (c == 'g' && n >= 2 && n <= 256)
+ return -n;
+ return 0;
+ }
+
+
+struct palentry *palsetup_palette; /* current palette */
+
+/*
+ * palsetup(p) - set up palette for specified palette.
+ */
+struct palentry *palsetup(p)
+int p;
+ {
+ int r, g, b, i, n, c;
+ unsigned int rr, gg, bb;
+ unsigned char *s = NULL, *t;
+ double m;
+ struct palentry *e;
+ static int palnumber; /* current palette number */
+
+ if (palnumber == p)
+ return palsetup_palette;
+ if (palsetup_palette == NULL) {
+ palsetup_palette =
+ (struct palentry *)malloc(256 * sizeof(struct palentry));
+ if (palsetup_palette == NULL)
+ return NULL;
+ }
+ palnumber = p;
+
+ for (i = 0; i < 256; i++)
+ palsetup_palette[i].valid = palsetup_palette[i].transpt = 0;
+ palsetup_palette[TCH1].transpt = 1;
+ palsetup_palette[TCH2].transpt = 1;
+
+ if (p < 0) { /* grayscale palette */
+ n = -p;
+ if (n <= 64)
+ s = (unsigned char *)c4list;
+ else
+ s = allchars;
+ m = 1.0 / (n - 1);
+
+ for (i = 0; i < n; i++) {
+ e = &palsetup_palette[*s++];
+ gg = 65535 * m * i;
+ e->clr.red = e->clr.green = e->clr.blue = gg;
+ e->valid = 1;
+ e->transpt = 0;
+ }
+ return palsetup_palette;
+ }
+
+ if (p == 1) { /* special c1 palette */
+ s = (unsigned char *)c1list;
+ t = c1rgb;
+ while ((c = *s++) != 0) {
+ e = &palsetup_palette[c];
+ e->clr.red = 65535 * (((int)*t++) / 48.0);
+ e->clr.green = 65535 * (((int)*t++) / 48.0);
+ e->clr.blue = 65535 * (((int)*t++) / 48.0);
+ e->valid = 1;
+ e->transpt = 0;
+ }
+ return palsetup_palette;
+ }
+
+ switch (p) { /* color cube plus extra grays */
+ case 2: s = (unsigned char *)c2list; break; /* c2 */
+ case 3: s = (unsigned char *)c3list; break; /* c3 */
+ case 4: s = (unsigned char *)c4list; break; /* c4 */
+ case 5: s = allchars; break; /* c5 */
+ case 6: s = allchars; break; /* c6 */
+ }
+ m = 1.0 / (p - 1);
+ for (r = 0; r < p; r++) {
+ rr = 65535 * m * r;
+ for (g = 0; g < p; g++) {
+ gg = 65535 * m * g;
+ for (b = 0; b < p; b++) {
+ bb = 65535 * m * b;
+ e = &palsetup_palette[*s++];
+ e->clr.red = rr;
+ e->clr.green = gg;
+ e->clr.blue = bb;
+ e->valid = 1;
+ e->transpt = 0;
+ }
+ }
+ }
+ m = 1.0 / (p * (p - 1));
+ for (g = 0; g < p * (p - 1); g++)
+ if (g % p != 0) {
+ gg = 65535 * m * g;
+ e = &palsetup_palette[*s++];
+ e->clr.red = e->clr.green = e->clr.blue = gg;
+ e->valid = 1;
+ e->transpt = 0;
+ }
+ return palsetup_palette;
+ }
+
+/*
+ * rgbkey(p,r,g,b) - return pointer to key of closest color in palette number p.
+ *
+ * In color cubes, finds "extra" grays only if r == g == b.
+ */
+char *rgbkey(p, r, g, b)
+int p;
+double r, g, b;
+ {
+ int n, i;
+ double m;
+ char *s;
+
+ if (p > 0) { /* color */
+ if (r == g && g == b) {
+ if (p == 1)
+ m = 6;
+ else
+ m = p * (p - 1);
+ return cgrays[p - 1] + (int)(0.501 + m * g);
+ }
+ else {
+ if (p == 1)
+ n = C1Side;
+ else
+ n = p;
+ m = n - 1;
+ i = (int)(0.501 + m * r);
+ i = n * i + (int)(0.501 + m * g);
+ i = n * i + (int)(0.501 + m * b);
+ switch(p) {
+ case 1: return c1cube + i; /* c1 */
+ case 2: return c2list + i; /* c2 */
+ case 3: return c3list + i; /* c3 */
+ case 4: return c4list + i; /* c4 */
+ case 5: return (char *)allchars + i; /* c5 */
+ case 6: return (char *)allchars + i; /* c6 */
+ }
+ }
+ }
+ else { /* grayscale */
+ if (p < -64)
+ s = (char *)allchars;
+ else
+ s = c4list;
+ return s + (int)(0.5 + (0.299 * r + 0.587 * g + 0.114 * b) * (-p - 1));
+ }
+
+ /*NOTREACHED*/
+ return 0; /* avoid gcc warning */
+ }
+
+#else /* Graphics */
+
+/*
+ * Stubs to prevent dynamic loader from rejecting cfunc library of IPL.
+ */
+int palnum(dptr *d) { return 0; }
+char *rgbkey(int p, double r, double g, double b) { return 0; }
+
+#endif /* Graphics */