Code:
void XFillPolygonByPixmap(Display *disp, Drawable d, GC gc,
XPoint *polygon, int len,
Pixmap pixmap, Pixmap mask)
{
const unsigned short MAX_PIXMAP_WHC = 50;
char data[MAX_PIXMAP_WHC*MAX_PIXMAP_WHC];
unsigned short indData = 0;
unsigned short currColor = 0;
char colorHex[6];
unsigned short ind;
static signed short noneColor = -1;
XpmImage xpmImage; // xpm color of line
unsigned short indBuf = 0;
unsigned char buf = 0;
static Pixmap currBitmap[MAX_PIXMAP_WHC];
static Pixmap prevPixmap = NULL;
static unsigned short indBitmap = 0;
static unsigned long colorLong[MAX_PIXMAP_WHC];
static unsigned int ncolor = 0;
// Using tile if no mask in *.xpm
if (!mask)
{
XSetFillStyle(disp, gc, FillTiled);
XSetTile(disp, gc, pixmap);
XFillPolygon(disp, d, gc, polygon, len, Complex, CoordModeOrigin);
return;
}
// Generate new data. Else - use previous
if (pixmap != prevPixmap)
{
prevPixmap = pixmap;
noneColor = -1;
XpmCreateXpmImageFromPixmap(disp, pixmap, mask, &xpmImage, NULL);
ncolor = xpmImage.ncolors;
// Take all colors
for (ind = 0; ind < ncolor; ind++)
{
// for look and understand format of c_color use:
// printf("%s\n", xpmImage.colorTable[ind].c_color);
colorHex[0] = xpmImage.colorTable[ind].c_color[1];
colorHex[1] = xpmImage.colorTable[ind].c_color[2];
colorHex[2] = xpmImage.colorTable[ind].c_color[5];
colorHex[3] = xpmImage.colorTable[ind].c_color[6];
colorHex[4] = xpmImage.colorTable[ind].c_color[9];
colorHex[5] = xpmImage.colorTable[ind].c_color[10];
// Get index of None color in colorTable
if (xpmImage.colorTable[ind].c_color[0] == 'N'
&& xpmImage.colorTable[ind].c_color[1] == 'o'
&& xpmImage.colorTable[ind].c_color[2] == 'n'
&& xpmImage.colorTable[ind].c_color[3] == 'e')
noneColor = ind;
// Save all colors
colorLong[ind] = strtol(colorHex, NULL, 16);
}
for (ind = 0; ind < indBitmap; ind++)
XFreePixmap(disp, currBitmap[ind]);
// Create bitmaps for each color
for (currColor = 0, indBitmap = 0;
currColor < ncolor; currColor++)
{
if (currColor == noneColor)
continue;
// Filter all array on current color
for (ind = 0, buf = 0, indBuf = 0, indData = 0;
ind < xpmImage.width*xpmImage.height; ind++)
{
// If current pixel is equal current color - set high bit
// else - bit is zero
if (xpmImage.data[ind] == currColor)
buf |= 0x80;
// if index is equal width - shift right on width-indBuf bits
bool flagWidth = ((ind+1)%xpmImage.width == 0);
// If num of bits is 8 or flag is set, save data
if (indBuf == 7 || flagWidth)
{
if (flagWidth)
{
while(indBuf < 7)
{
buf = buf >> 1;
indBuf++;
}
}
data[indData++] = buf;
indBuf = 0;
buf = 0;
}
else
{
indBuf++;
buf = buf >> 1;
}
}
// Create bitmaps for each color
currBitmap[indBitmap++] = XCreateBitmapFromData(disp, d, data,
xpmImage.width, xpmImage.height);
}
}
// For each color set stipple by bitmap and fill polygon
for (currColor = 0, ind = 0;
currColor < ncolor, ind < indBitmap; currColor++)
{
if (currColor == noneColor)
continue;
XSetFillStyle(disp, gc, FillStippled);
XSetForeground(disp, gc, colorLong[currColor]);
XSetStipple(disp, gc, currBitmap[ind++]);
XFillPolygon(disp, d, gc, polygon, len, Complex, CoordModeOrigin);
}
return;
}