gdiplus: Properly draw points outside of line gradients.
Theoretically, a line gradient covers the area enclosed by the starting and ending gradient lines, which intersect the start and end points respectively and are perpendicular to a line joining the start and end points.
This commit is contained in:
parent
a6161307cf
commit
966fd5ec09
|
@ -185,6 +185,19 @@ static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
|
||||||
{
|
{
|
||||||
REAL blendfac;
|
REAL blendfac;
|
||||||
|
|
||||||
|
/* clamp to between 0.0 and 1.0, using the wrap mode */
|
||||||
|
if (brush->wrap == WrapModeTile)
|
||||||
|
{
|
||||||
|
position = fmodf(position, 1.0f);
|
||||||
|
if (position < 0.0f) position += 1.0f;
|
||||||
|
}
|
||||||
|
else /* WrapModeFlip* */
|
||||||
|
{
|
||||||
|
position = fmodf(position, 2.0f);
|
||||||
|
if (position < 0.0f) position += 2.0f;
|
||||||
|
if (position > 1.0f) position = 2.0f - position;
|
||||||
|
}
|
||||||
|
|
||||||
if (brush->blendcount == 1)
|
if (brush->blendcount == 1)
|
||||||
blendfac = position;
|
blendfac = position;
|
||||||
else
|
else
|
||||||
|
@ -217,7 +230,6 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
|
||||||
{
|
{
|
||||||
GpLineGradient *line = (GpLineGradient*)brush;
|
GpLineGradient *line = (GpLineGradient*)brush;
|
||||||
RECT rc;
|
RECT rc;
|
||||||
int num_steps = 255;
|
|
||||||
|
|
||||||
SelectClipPath(graphics->hdc, RGN_AND);
|
SelectClipPath(graphics->hdc, RGN_AND);
|
||||||
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
|
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
|
||||||
|
@ -228,9 +240,6 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
|
||||||
|
|
||||||
SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
|
SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
|
||||||
|
|
||||||
/* fill with starting color */
|
|
||||||
FillRect(graphics->hdc, &rc, brush->gdibrush);
|
|
||||||
|
|
||||||
endpointsf[0] = line->startpoint;
|
endpointsf[0] = line->startpoint;
|
||||||
endpointsf[1] = line->endpoint;
|
endpointsf[1] = line->endpoint;
|
||||||
transform_and_round_points(graphics, endpointsi, endpointsf, 2);
|
transform_and_round_points(graphics, endpointsi, endpointsf, 2);
|
||||||
|
@ -238,114 +247,100 @@ static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
|
||||||
if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
|
if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
|
||||||
{
|
{
|
||||||
/* vertical-ish gradient */
|
/* vertical-ish gradient */
|
||||||
int endborderx; /* vertical rectangle boundary near endpoint */
|
|
||||||
int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
|
int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
|
||||||
int startbottomx, endbottomx; /* x co-ordinate of endpoints shifted to intersect the bottom of the visible rectangle */
|
int startbottomx; /* x co-ordinate of start point shifted to intersect the bottom of the visible rectangle */
|
||||||
int width;
|
int width;
|
||||||
COLORREF col;
|
COLORREF col;
|
||||||
HBRUSH hbrush, hprevbrush;
|
HBRUSH hbrush, hprevbrush;
|
||||||
int i;
|
int leftx, rightx; /* x co-ordinates where the leftmost and rightmost gradient lines hit the top of the visible rectangle */
|
||||||
|
int x;
|
||||||
if (endpointsi[1].x > endpointsi[0].x)
|
int tilt; /* horizontal distance covered by a gradient line */
|
||||||
endborderx = rc.right;
|
|
||||||
else
|
|
||||||
endborderx = rc.left;
|
|
||||||
|
|
||||||
startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
|
startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
|
||||||
endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
|
endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
|
||||||
width = endx - startx;
|
width = endx - startx;
|
||||||
startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
|
startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
|
||||||
endbottomx = startbottomx+width;
|
tilt = startx - startbottomx;
|
||||||
|
|
||||||
if (num_steps > abs(width)) num_steps = abs(width);
|
if (startx >= startbottomx)
|
||||||
|
{
|
||||||
|
leftx = rc.left;
|
||||||
|
rightx = rc.right + tilt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
leftx = rc.left + tilt;
|
||||||
|
rightx = rc.right;
|
||||||
|
}
|
||||||
|
|
||||||
poly[0].x = endborderx;
|
poly[0].x = rc.right;
|
||||||
poly[0].y = rc.bottom;
|
poly[0].y = rc.bottom;
|
||||||
poly[1].x = endborderx;
|
poly[1].x = rc.right;
|
||||||
poly[1].y = rc.top;
|
poly[1].y = rc.top;
|
||||||
poly[2].y = rc.top;
|
poly[2].y = rc.top;
|
||||||
poly[3].y = rc.bottom;
|
poly[3].y = rc.bottom;
|
||||||
|
|
||||||
for (i=1; i<num_steps; i++)
|
for (x=leftx; x<=rightx; x++)
|
||||||
{
|
{
|
||||||
ARGB argb = blend_line_gradient(line, i/(REAL)num_steps);
|
ARGB argb = blend_line_gradient(line, (x-startx)/(REAL)width);
|
||||||
int ofs = width * i / num_steps;
|
|
||||||
col = ARGB2COLORREF(argb);
|
col = ARGB2COLORREF(argb);
|
||||||
hbrush = CreateSolidBrush(col);
|
hbrush = CreateSolidBrush(col);
|
||||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
||||||
poly[2].x = startx + ofs;
|
poly[2].x = x;
|
||||||
poly[3].x = startbottomx + ofs;
|
poly[3].x = x - tilt;
|
||||||
Polygon(graphics->hdc, poly, 4);
|
Polygon(graphics->hdc, poly, 4);
|
||||||
SelectObject(graphics->hdc, hprevbrush);
|
SelectObject(graphics->hdc, hprevbrush);
|
||||||
DeleteObject(hbrush);
|
DeleteObject(hbrush);
|
||||||
}
|
}
|
||||||
|
|
||||||
poly[2].x = endx;
|
|
||||||
poly[3].x = endbottomx;
|
|
||||||
|
|
||||||
/* draw the ending color */
|
|
||||||
col = ARGB2COLORREF(line->endcolor);
|
|
||||||
hbrush = CreateSolidBrush(col);
|
|
||||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
|
||||||
Polygon(graphics->hdc, poly, 4);
|
|
||||||
SelectObject(graphics->hdc, hprevbrush);
|
|
||||||
DeleteObject(hbrush);
|
|
||||||
}
|
}
|
||||||
else if (endpointsi[0].y != endpointsi[1].y)
|
else if (endpointsi[0].y != endpointsi[1].y)
|
||||||
{
|
{
|
||||||
/* horizontal-ish gradient */
|
/* horizontal-ish gradient */
|
||||||
int endbordery; /* horizontal rectangle boundary near endpoint */
|
|
||||||
int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
|
int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
|
||||||
int startrighty, endrighty; /* y co-ordinate of endpoints shifted to intersect the right of the visible rectangle */
|
int startrighty; /* y co-ordinate of start point shifted to intersect the right of the visible rectangle */
|
||||||
int height;
|
int height;
|
||||||
COLORREF col;
|
COLORREF col;
|
||||||
HBRUSH hbrush, hprevbrush;
|
HBRUSH hbrush, hprevbrush;
|
||||||
int i;
|
int topy, bottomy; /* y co-ordinates where the topmost and bottommost gradient lines hit the left of the visible rectangle */
|
||||||
|
int y;
|
||||||
if (endpointsi[1].y > endpointsi[0].y)
|
int tilt; /* vertical distance covered by a gradient line */
|
||||||
endbordery = rc.bottom;
|
|
||||||
else
|
|
||||||
endbordery = rc.top;
|
|
||||||
|
|
||||||
starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
|
starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
|
||||||
endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
|
endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
|
||||||
height = endy - starty;
|
height = endy - starty;
|
||||||
startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
|
startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
|
||||||
endrighty = startrighty+height;
|
tilt = starty - startrighty;
|
||||||
|
|
||||||
if (num_steps > abs(height)) num_steps = abs(height);
|
if (starty >= startrighty)
|
||||||
|
{
|
||||||
|
topy = rc.top;
|
||||||
|
bottomy = rc.bottom + tilt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topy = rc.top + tilt;
|
||||||
|
bottomy = rc.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
poly[0].x = rc.right;
|
poly[0].x = rc.right;
|
||||||
poly[0].y = endbordery;
|
poly[0].y = rc.bottom;
|
||||||
poly[1].x = rc.left;
|
poly[1].x = rc.left;
|
||||||
poly[1].y = endbordery;
|
poly[1].y = rc.bottom;
|
||||||
poly[2].x = rc.left;
|
poly[2].x = rc.left;
|
||||||
poly[3].x = rc.right;
|
poly[3].x = rc.right;
|
||||||
|
|
||||||
for (i=1; i<num_steps; i++)
|
for (y=topy; y<=bottomy; y++)
|
||||||
{
|
{
|
||||||
ARGB argb = blend_line_gradient(line, i/(REAL)num_steps);
|
ARGB argb = blend_line_gradient(line, (y-starty)/(REAL)height);
|
||||||
int ofs = height * i / num_steps;
|
|
||||||
col = ARGB2COLORREF(argb);
|
col = ARGB2COLORREF(argb);
|
||||||
hbrush = CreateSolidBrush(col);
|
hbrush = CreateSolidBrush(col);
|
||||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
||||||
poly[2].y = starty + ofs;
|
poly[2].y = y;
|
||||||
poly[3].y = startrighty + ofs;
|
poly[3].y = y - tilt;
|
||||||
Polygon(graphics->hdc, poly, 4);
|
Polygon(graphics->hdc, poly, 4);
|
||||||
SelectObject(graphics->hdc, hprevbrush);
|
SelectObject(graphics->hdc, hprevbrush);
|
||||||
DeleteObject(hbrush);
|
DeleteObject(hbrush);
|
||||||
}
|
}
|
||||||
|
|
||||||
poly[2].y = endy;
|
|
||||||
poly[3].y = endrighty;
|
|
||||||
|
|
||||||
/* draw the ending color */
|
|
||||||
col = ARGB2COLORREF(line->endcolor);
|
|
||||||
hbrush = CreateSolidBrush(col);
|
|
||||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
|
||||||
Polygon(graphics->hdc, poly, 4);
|
|
||||||
SelectObject(graphics->hdc, hprevbrush);
|
|
||||||
DeleteObject(hbrush);
|
|
||||||
}
|
}
|
||||||
/* else startpoint == endpoint */
|
/* else startpoint == endpoint */
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue