1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
/* This file contains device-specific color database access routines.
These routines are called by various FigPlotter methods. */
#include "sys-defines.h"
#include "plot.h"
#include "extern.h"
#define ONEBYTE 0xff
/* by setting this undocumented variable, user may request quantization of
colors (no user-defined colors, only native xfig ones). */
int _libplotfig_use_pseudocolor = 0;
/* FIG_COLOR returns the index of the Fig color corresponding to specified
a 48-bit RGB value. This has (or may have) a side effect. If the Fig
color is not standard, it will be added to the database of user-defined
colors, and a Fig `color pseudo-object' will be output later.
We do not call this function whenever the user calls pencolor() or
fillcolor(), since we don't want to fill up the database with colors
that the user may not actually use. Instead, we call it just before we
write a colored object to the output buffer (lazy evaluation), by
evaluating the f_set_pen_color() and f_set_fill_color() functions below.
If the external variable use_pseudocolor is nonzero, we don't actually
maintain a database of user-defined colors. Instead we just quantize to
one of xfig's native 32 colors. (They provide a [rather strange]
partition of the color cube; see colordb.h.) */
/* forward references */
static int _fig_color __P((int red, int green, int blue));
static int _fig_pseudocolor __P((int red, int green, int blue));
static int
#ifdef _HAVE_PROTOS
_fig_color(int red, int green, int blue)
#else
_fig_color(red, green, blue)
int red, green, blue;
#endif
{
int fig_fgcolor_red, fig_fgcolor_green, fig_fgcolor_blue;
long int fig_fgcolor_rgb;
int i;
/* xfig supports only 24-bit color */
fig_fgcolor_red = (red >> 8) & ONEBYTE;
fig_fgcolor_green = (green >> 8) & ONEBYTE;
fig_fgcolor_blue = (blue >> 8) & ONEBYTE;
if (_libplotfig_use_pseudocolor) /* quantize */
return _fig_pseudocolor (fig_fgcolor_red, fig_fgcolor_green,
fig_fgcolor_blue);
for (i=0; i<FIG_NUM_STD_COLORS; i++) /* search list of standard colors */
{
if ((_fig_stdcolors[i].red == fig_fgcolor_red)
&& (_fig_stdcolors[i].green == fig_fgcolor_green)
&& (_fig_stdcolors[i].blue == fig_fgcolor_blue))
return FIG_STD_COLOR_MIN + i;
}
/* This is the 24-bit (i.e. 3-byte) integer used internally by xfig.
We assume our long ints are wide enough to handle 3 bytes. */
fig_fgcolor_rgb = (fig_fgcolor_red << 16) + (fig_fgcolor_green << 8)
+ (fig_fgcolor_blue);
for (i=0; i<_plotter->fig_num_usercolors; i++) /* search list of user-defined colors */
{
if (_plotter->fig_usercolors[i] == fig_fgcolor_rgb)
return FIG_USER_COLOR_MIN + i;
}
/* wasn't found, need to define it */
if (_plotter->fig_num_usercolors == FIG_MAX_NUM_USER_COLORS)
{
_plotter->warning ("supply of user-defined colors is exhausted");
return -1;
}
/* create new user-defined color, will emit it in closepl.c */
_plotter->fig_usercolors[_plotter->fig_num_usercolors] = fig_fgcolor_rgb;
_plotter->fig_num_usercolors++;
return FIG_USER_COLOR_MIN + _plotter->fig_num_usercolors - 1;
}
/* find closest known point within the RGB color cube, using Euclidean
distance as our metric */
static int
#ifdef _HAVE_PROTOS
_fig_pseudocolor (int red, int green, int blue)
#else
_fig_pseudocolor (red, green, blue)
int red, green, blue;
#endif
{
unsigned long int difference = MAXINT;
int i;
int best = 0;
/* xfig supports only 24-bit color */
red = (red >> 8) & ONEBYTE;
green = (green >> 8) & ONEBYTE;
blue = (blue >> 8) & ONEBYTE;
for (i = 0; i < FIG_NUM_STD_COLORS; i++)
{
unsigned long int newdifference;
if (_fig_stdcolors[i].red == 0xff
&& _fig_stdcolors[i].green == 0xff
&& _fig_stdcolors[i].blue == 0xff)
/* white is a possible quantization only for white itself (our
convention) */
{
if (red == 0xff && green == 0xff && blue == 0xff)
{
difference = 0;
best = i;
}
continue;
}
newdifference = (((_fig_stdcolors[i].red - red)
* (_fig_stdcolors[i].red - red))
+ ((_fig_stdcolors[i].green - green)
* (_fig_stdcolors[i].green - green))
+ ((_fig_stdcolors[i].blue - blue)
* (_fig_stdcolors[i].blue - blue)));
if (newdifference < difference)
{
difference = newdifference;
best = i;
}
}
return FIG_STD_COLOR_MIN + best;
}
/* we call this routine to evaluate _plotter->drawstate->fig_fgcolor
lazily, i.e. only when needed (just before an object is written to the
output buffer) */
void
#ifdef _HAVE_PROTOS
_f_set_pen_color(void)
#else
_f_set_pen_color()
#endif
{
/* OOB switches to default color */
if (((_plotter->drawstate->fgcolor).red > 0xffff)
|| ((_plotter->drawstate->fgcolor).green > 0xffff)
|| ((_plotter->drawstate->fgcolor).blue > 0xffff))
_plotter->drawstate->fig_fgcolor =
_plotter->default_drawstate->fig_fgcolor;
else
_plotter->drawstate->fig_fgcolor =
_fig_color ((_plotter->drawstate->fgcolor).red,
(_plotter->drawstate->fgcolor).green,
(_plotter->drawstate->fgcolor).blue);
return;
}
/* we call this routine to evaluate _plotter->drawstate->fig_fillcolor and
_plotter->drawstate->fig_fill_level lazily, i.e. only when needed (just
before an object is written to the output buffer) */
/* Note that fill_level, if nonzero, specifies the extent to which the
nominal fill color should be desaturated. 1 means no desaturation,
0xffff means complete desaturation (white). */
void
#ifdef _HAVE_PROTOS
_f_set_fill_color(void)
#else
_f_set_fill_color()
#endif
{
double fill_level;
/* OOB switches to default color */
if (((_plotter->drawstate->fillcolor).red > 0xffff)
|| ((_plotter->drawstate->fillcolor).green > 0xffff)
|| ((_plotter->drawstate->fillcolor).blue > 0xffff))
_plotter->drawstate->fig_fillcolor =
_plotter->default_drawstate->fig_fillcolor;
else
_plotter->drawstate->fig_fillcolor =
_fig_color ((_plotter->drawstate->fillcolor).red,
(_plotter->drawstate->fillcolor).green,
(_plotter->drawstate->fillcolor).blue);
/* Now that we know _drawstate->fig_fillcolor, we can compute the fig
fill level that will match the user's requested fill level. Fig fill
level is interpreted in a color dependent way, as follows. The value
-1 is special; means no fill at all (objects will be transparent).
For other values, this is the interpretation:
Color = black or default:
fill = 0 -> white
fill = 1 -> very light grey
.
.
fill = 19 -> very dark grey
fill = 20 -> black
Color = all colors other than black or default, including white
fill = 0 -> black
fill = 1 -> color, very faint intensity
.
.
fill = 19 -> color, very bright intensity
fill = 20 -> color, full intensity
So 1->20 give increasingly intense "shades" of the
color, with 20 giving the color itself. Values 20->40
are increasingly desaturated "tints" of the color,
ranging from the color itself (20) to white (40). A
tint is defined as the color mixed with white. (Values
21->40 are not used when the color is black or default,
or white itself.) */
fill_level = ((double)_plotter->drawstate->fill_level - 1.)/0xFFFE;
/* OOB sets fill level to a non-OOB default value */
if (fill_level > 1.)
fill_level = ((double)_plotter->default_drawstate->fill_level - 1.)/0xFFFE;
/* level = 0 turns off filling (objects will be transparent) */
else if (fill_level < 0.)
fill_level = -1.0;
if (fill_level == -1.0)
_plotter->drawstate->fig_fill_level = -1;
else
{
switch (_plotter->drawstate->fig_fillcolor)
{
case C_WHITE: /* can't desaturate white */
_plotter->drawstate->fig_fill_level = 20;
break;
case C_BLACK:
_plotter->drawstate->fig_fill_level = IROUND(20.0 - 20.0 * fill_level);
break;
default: /* interpret fill level as a saturation */
_plotter->drawstate->fig_fill_level = IROUND(20.0 + 20.0 * fill_level);
break;
}
}
return;
}
|