Done.
For calculate lines used Bresenham's algorithm.
Code:
#include <math.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <stdlib.h>
void XDrawLineFillXpm(XPoint start, XPoint end,
Display *disp, Drawable d, GC gc, Pixmap pmap, Pixmap mask)
{
signed char dir[2]; // direction of the line ([0]:x; [1]:y)
unsigned short delta[2]; // dx; dy
unsigned char base = 0; // base coord (that changed faster)
short error; // sum error
short pos[2][2]; // curr & end positions
static Pixmap currPmap = NULL; // color of line
static XpmImage xpmImage; // xpm color of line
unsigned short currColor = 0;
unsigned short currLine = 0;
static unsigned short currXInd = 0;
char colorHex[6];
static unsigned long *colorLong = NULL;
unsigned int prevIndex = 0;
unsigned short startCoord = 0;
unsigned short val = 0;
static XPoint prevEndPoint = {-1,-1};
if (prevEndPoint.x != start.x
|| prevEndPoint.y != start.y)
prevIndex = 0;
else
prevIndex = currXInd;
// New pixmap? -> Read color & xpm
if (currPmap != pmap)
{
currPmap = pmap;
XpmCreateXpmImageFromPixmap(disp, pmap, mask, &xpmImage, NULL);
if (colorLong != NULL)
free(colorLong);
colorLong = (unsigned long*)malloc(xpmImage.ncolors);
for (currXInd = 0; currXInd < xpmImage.ncolors; currXInd++)
{
colorHex[0] = xpmImage.colorTable[currXInd].c_color[1];
colorHex[1] = xpmImage.colorTable[currXInd].c_color[2];
colorHex[2] = xpmImage.colorTable[currXInd].c_color[5];
colorHex[3] = xpmImage.colorTable[currXInd].c_color[6];
colorHex[4] = xpmImage.colorTable[currXInd].c_color[9];
colorHex[5] = xpmImage.colorTable[currXInd].c_color[10];
colorLong[currXInd] = strtol(colorHex, NULL, 16);
}
currXInd = 0;
}
// take direction
delta[0] = (end.x > start.x ? (dir[0] = 1, end.x - start.x)
: (dir[0] = -1, start.x - end.x)) << 1; //*2
delta[1] = (end.y > start.y ? (dir[1] = 1, end.y - start.y)
: (dir[1] = -1, start.y - end.y)) << 1;
// If 'y' changed faster than 'x'
if (delta[1] > delta[0])
base = 1;
XSetFillStyle(disp, gc, FillSolid);
// Num of lines = Height
for (currLine = 0; currLine < xpmImage.height; currLine++)
{
if (xpmImage.height > 1)
startCoord = (xpmImage.height >> 1) - currLine;
else
startCoord = 0;
// Fill all colors for each line
for (currColor = 0; currColor < xpmImage.ncolors; currColor++)
{
pos[0][0] = start.x;
pos[0][1] = start.y;
pos[1][0] = end.x;
pos[1][1] = end.y;
// Recalculate start & end points
if (base) // y is base coord
{
val = startCoord*dir[base];
pos[0][1-base] += val;
pos[1][1-base] += val;
}
else // x is base coord
{
val = startCoord*dir[base]*(-1);
pos[0][1-base] += val;
pos[1][1-base] += val;
}
// Set new color for points
XSetForeground(disp, gc, colorLong[currColor]);
currXInd = prevIndex; // load previous index for each color
if (xpmImage.data[currLine*xpmImage.width + currXInd++] ==
currColor)
XDrawPoint(disp, d, gc, pos[0][0], pos[0][1]);
if (currXInd >= xpmImage.width)
currXInd = 0;
error = delta[1-base] - (delta[base] >> 1);
while(pos[0][base] != pos[1][base])
{
if (error >= 0)
{
if (error || dir[base] > 0)
{
pos[0][1-base] += dir[1-base]; //change pos by no-base
error -=delta[base];
}
}
pos[0][base] += dir[base]; // change pos by base coord
error += delta[1-base];
if (xpmImage.data[currLine*xpmImage.width + currXInd++] == currColor)
XDrawPoint(disp, d, gc, pos[0][0], pos[0][1]);
if (currXInd >= xpmImage.width)
currXInd = 0;
}
}
}
prevEndPoint = end;
}