mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 04:39:45 +00:00
gdi32: Implement triangular gradients in the DIB engine.
This commit is contained in:
parent
e97c454637
commit
743b37df3d
@ -601,15 +601,105 @@ static DWORD blend_rect( dib_info *dst, const RECT *dst_rect, const dib_info *sr
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static void gradient_rect( dib_info *dib, TRIVERTEX *v, int mode, HRGN clip )
|
||||
/* compute y-ordered, device coords vertices for a horizontal rectangle gradient */
|
||||
static void get_gradient_hrect_vertices( const GRADIENT_RECT *rect, const TRIVERTEX *vert,
|
||||
const POINT *dev_pts, TRIVERTEX v[2] )
|
||||
{
|
||||
int v0 = rect->UpperLeft;
|
||||
int v1 = rect->LowerRight;
|
||||
|
||||
if (dev_pts[v1].x < dev_pts[v0].x) /* swap the colors */
|
||||
{
|
||||
v0 = rect->LowerRight;
|
||||
v1 = rect->UpperLeft;
|
||||
}
|
||||
v[0] = vert[v0];
|
||||
v[1] = vert[v1];
|
||||
v[0].x = dev_pts[v0].x;
|
||||
v[1].x = dev_pts[v1].x;
|
||||
v[0].y = min( dev_pts[v0].y, dev_pts[v1].y );
|
||||
v[1].y = max( dev_pts[v0].y, dev_pts[v1].y );
|
||||
}
|
||||
|
||||
/* compute y-ordered, device coords vertices for a vertical rectangle gradient */
|
||||
static void get_gradient_vrect_vertices( const GRADIENT_RECT *rect, const TRIVERTEX *vert,
|
||||
const POINT *dev_pts, TRIVERTEX v[2] )
|
||||
{
|
||||
int v0 = rect->UpperLeft;
|
||||
int v1 = rect->LowerRight;
|
||||
|
||||
if (dev_pts[v1].y < dev_pts[v0].y) /* swap the colors */
|
||||
{
|
||||
v0 = rect->LowerRight;
|
||||
v1 = rect->UpperLeft;
|
||||
}
|
||||
v[0] = vert[v0];
|
||||
v[1] = vert[v1];
|
||||
v[0].x = min( dev_pts[v0].x, dev_pts[v1].x );
|
||||
v[1].x = max( dev_pts[v0].x, dev_pts[v1].x );
|
||||
v[0].y = dev_pts[v0].y;
|
||||
v[1].y = dev_pts[v1].y;
|
||||
}
|
||||
|
||||
/* compute y-ordered, device coords vertices for a triangle gradient */
|
||||
static void get_gradient_triangle_vertices( const GRADIENT_TRIANGLE *tri, const TRIVERTEX *vert,
|
||||
const POINT *dev_pts, TRIVERTEX v[3] )
|
||||
{
|
||||
int v0, v1, v2;
|
||||
|
||||
if (dev_pts[tri->Vertex1].y > dev_pts[tri->Vertex2].y)
|
||||
{
|
||||
if (dev_pts[tri->Vertex3].y < dev_pts[tri->Vertex2].y)
|
||||
{ v0 = tri->Vertex3; v1 = tri->Vertex2; v2 = tri->Vertex1; }
|
||||
else if (dev_pts[tri->Vertex3].y < dev_pts[tri->Vertex1].y)
|
||||
{ v0 = tri->Vertex2; v1 = tri->Vertex3; v2 = tri->Vertex1; }
|
||||
else
|
||||
{ v0 = tri->Vertex2; v1 = tri->Vertex1; v2 = tri->Vertex3; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dev_pts[tri->Vertex3].y < dev_pts[tri->Vertex1].y)
|
||||
{ v0 = tri->Vertex3; v1 = tri->Vertex1; v2 = tri->Vertex2; }
|
||||
else if (dev_pts[tri->Vertex3].y < dev_pts[tri->Vertex2].y)
|
||||
{ v0 = tri->Vertex1; v1 = tri->Vertex3; v2 = tri->Vertex2; }
|
||||
else
|
||||
{ v0 = tri->Vertex1; v1 = tri->Vertex2; v2 = tri->Vertex3; }
|
||||
}
|
||||
v[0] = vert[v0];
|
||||
v[1] = vert[v1];
|
||||
v[2] = vert[v2];
|
||||
v[0].x = dev_pts[v0].x;
|
||||
v[0].y = dev_pts[v0].y;
|
||||
v[1].y = dev_pts[v1].y;
|
||||
v[1].x = dev_pts[v1].x;
|
||||
v[2].x = dev_pts[v2].x;
|
||||
v[2].y = dev_pts[v2].y;
|
||||
}
|
||||
|
||||
static BOOL gradient_rect( dib_info *dib, TRIVERTEX *v, int mode, HRGN clip )
|
||||
{
|
||||
int i;
|
||||
RECT rect, clipped_rect;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
rect.left = max( v[0].x, 0 );
|
||||
rect.top = max( v[0].y, 0 );
|
||||
rect.right = min( v[1].x, dib->width );
|
||||
rect.bottom = min( v[1].y, dib->height );
|
||||
if (mode == GRADIENT_FILL_TRIANGLE)
|
||||
{
|
||||
rect.left = min( v[0].x, min( v[1].x, v[2].x ));
|
||||
rect.top = v[0].y;
|
||||
rect.right = max( v[0].x, max( v[1].x, v[2].x ));
|
||||
rect.bottom = v[2].y;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.left = v[0].x;
|
||||
rect.top = v[0].y;
|
||||
rect.right = v[1].x;
|
||||
rect.bottom = v[1].y;
|
||||
}
|
||||
rect.left = max( rect.left, 0 );
|
||||
rect.top = max( rect.top, 0 );
|
||||
rect.right = min( rect.right, dib->width );
|
||||
rect.bottom = min( rect.bottom, dib->height );
|
||||
|
||||
if (clip)
|
||||
{
|
||||
@ -618,11 +708,15 @@ static void gradient_rect( dib_info *dib, TRIVERTEX *v, int mode, HRGN clip )
|
||||
for (i = 0; i < clip_data->numRects; i++)
|
||||
{
|
||||
if (intersect_rect( &clipped_rect, &rect, clip_data->rects + i ))
|
||||
dib->funcs->gradient_rect( dib, &clipped_rect, v, mode );
|
||||
{
|
||||
if (!(ret = dib->funcs->gradient_rect( dib, &clipped_rect, v, mode ))) break;
|
||||
}
|
||||
}
|
||||
release_wine_region( clip );
|
||||
}
|
||||
else dib->funcs->gradient_rect( dib, &rect, v, mode );
|
||||
else if (!is_rect_empty( &rect )) ret = dib->funcs->gradient_rect( dib, &rect, v, mode );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD copy_src_bits( dib_info *src, RECT *src_rect )
|
||||
@ -1245,7 +1339,7 @@ DWORD gradient_bitmapinfo( const BITMAPINFO *info, void *bits, TRIVERTEX *v, int
|
||||
dib_info dib;
|
||||
|
||||
if (!init_dib_info_from_bitmapinfo( &dib, info, bits, 0 )) return ERROR_BAD_FORMAT;
|
||||
gradient_rect( &dib, v, mode, 0 );
|
||||
if (!gradient_rect( &dib, v, mode, 0 )) return ERROR_INVALID_PARAMETER;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1292,50 +1386,57 @@ BOOL dibdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
|
||||
void *grad_array, ULONG ngrad, ULONG mode )
|
||||
{
|
||||
dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
|
||||
const GRADIENT_TRIANGLE *tri = grad_array;
|
||||
const GRADIENT_RECT *rect = grad_array;
|
||||
unsigned int i;
|
||||
POINT *pts;
|
||||
TRIVERTEX vert[3];
|
||||
BOOL ret = TRUE;
|
||||
|
||||
if (mode == GRADIENT_FILL_RECT_H || mode == GRADIENT_FILL_RECT_V)
|
||||
if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
|
||||
for (i = 0; i < nvert; i++)
|
||||
{
|
||||
const GRADIENT_RECT *rect = grad_array;
|
||||
TRIVERTEX v[2];
|
||||
POINT pt[2];
|
||||
pts[i].x = vert_array[i].x;
|
||||
pts[i].y = vert_array[i].y;
|
||||
}
|
||||
LPtoDP( dev->hdc, pts, nvert );
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case GRADIENT_FILL_RECT_H:
|
||||
for (i = 0; i < ngrad; i++, rect++)
|
||||
{
|
||||
v[0] = vert_array[rect->UpperLeft];
|
||||
v[1] = vert_array[rect->LowerRight];
|
||||
pt[0].x = v[0].x;
|
||||
pt[0].y = v[0].y;
|
||||
pt[1].x = v[1].x;
|
||||
pt[1].y = v[1].y;
|
||||
LPtoDP( dev->hdc, pt, 2 );
|
||||
if (mode == GRADIENT_FILL_RECT_H)
|
||||
{
|
||||
if (pt[1].x < pt[0].x) /* swap the colors */
|
||||
{
|
||||
v[0] = vert_array[rect->LowerRight];
|
||||
v[1] = vert_array[rect->UpperLeft];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pt[1].y < pt[0].y) /* swap the colors */
|
||||
{
|
||||
v[0] = vert_array[rect->LowerRight];
|
||||
v[1] = vert_array[rect->UpperLeft];
|
||||
}
|
||||
}
|
||||
v[0].x = min( pt[0].x, pt[1].x );
|
||||
v[0].y = min( pt[0].y, pt[1].y );
|
||||
v[1].x = max( pt[0].x, pt[1].x );
|
||||
v[1].y = max( pt[0].y, pt[1].y );
|
||||
get_gradient_hrect_vertices( rect, vert_array, pts, vert );
|
||||
/* Windows bug: no alpha on a8r8g8b8 created with bitfields */
|
||||
if (pdev->dib.funcs == &funcs_8888 && pdev->dib.compression == BI_BITFIELDS)
|
||||
v[0].Alpha = v[1].Alpha = 0; /* Windows bug: no alpha on a8r8g8b8 created with bitfields */
|
||||
gradient_rect( &pdev->dib, v, mode, pdev->clip );
|
||||
vert[0].Alpha = vert[1].Alpha = 0;
|
||||
gradient_rect( &pdev->dib, vert, mode, pdev->clip );
|
||||
}
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_RECT_V:
|
||||
for (i = 0; i < ngrad; i++, rect++)
|
||||
{
|
||||
get_gradient_vrect_vertices( rect, vert_array, pts, vert );
|
||||
/* Windows bug: no alpha on a8r8g8b8 created with bitfields */
|
||||
if (pdev->dib.funcs == &funcs_8888 && pdev->dib.compression == BI_BITFIELDS)
|
||||
vert[0].Alpha = vert[1].Alpha = 0;
|
||||
gradient_rect( &pdev->dib, vert, mode, pdev->clip );
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
for (i = 0; i < ngrad; i++, tri++)
|
||||
{
|
||||
get_gradient_triangle_vertices( tri, vert_array, pts, vert );
|
||||
/* Windows bug: no alpha on a8r8g8b8 created with bitfields */
|
||||
if (pdev->dib.funcs == &funcs_8888 && pdev->dib.compression == BI_BITFIELDS)
|
||||
vert[0].Alpha = vert[1].Alpha = vert[2].Alpha = 0;
|
||||
if (!gradient_rect( &pdev->dib, vert, mode, pdev->clip )) ret = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dev = GET_NEXT_PHYSDEV( dev, pGradientFill );
|
||||
return dev->funcs->pGradientFill( dev, vert_array, nvert, grad_array, ngrad, mode );
|
||||
HeapFree( GetProcessHeap(), 0, pts );
|
||||
return ret;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ typedef struct primitive_funcs
|
||||
const POINT *origin, int rop2, int overlap);
|
||||
void (* blend_rect)(const dib_info *dst, const RECT *rc, const dib_info *src,
|
||||
const POINT *origin, BLENDFUNCTION blend);
|
||||
void (* gradient_rect)(const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode);
|
||||
BOOL (* gradient_rect)(const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode);
|
||||
void (* draw_glyph)(const dib_info *dst, const RECT *rc, const dib_info *glyph,
|
||||
const POINT *origin, DWORD text_pixel, const struct intensity_range *ranges);
|
||||
DWORD (* get_pixel)(const dib_info *dib, const POINT *pt);
|
||||
@ -245,6 +245,15 @@ extern int clip_line(const POINT *start, const POINT *end, const RECT *clip,
|
||||
const bres_params *params, POINT *pt1, POINT *pt2) DECLSPEC_HIDDEN;
|
||||
extern void update_aa_ranges( dibdrv_physdev *pdev ) DECLSPEC_HIDDEN;
|
||||
|
||||
/* compute the x coordinate corresponding to y on the specified edge */
|
||||
static inline int edge_coord( int y, int x1, int y1, int x2, int y2 )
|
||||
{
|
||||
if (x2 > x1) /* always follow the edge from right to left to get correct rounding */
|
||||
return x2 + (y - y2) * (x2 - x1) / (y2 - y1);
|
||||
else
|
||||
return x1 + (y - y1) * (x2 - x1) / (y2 - y1);
|
||||
}
|
||||
|
||||
static inline BOOL defer_pen(dibdrv_physdev *pdev)
|
||||
{
|
||||
return pdev->defer & (DEFER_FORMAT | DEFER_PEN);
|
||||
|
@ -27,6 +27,36 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dib);
|
||||
|
||||
/* Bayer matrices for dithering */
|
||||
|
||||
static const BYTE bayer_4x4[4][4] =
|
||||
{
|
||||
{ 0, 8, 2, 10 },
|
||||
{ 12, 4, 14, 6 },
|
||||
{ 3, 11, 1, 9 },
|
||||
{ 15, 7, 13, 5 }
|
||||
};
|
||||
|
||||
static const BYTE bayer_16x16[16][16] =
|
||||
{
|
||||
{ 0, 128, 32, 160, 8, 136, 40, 168, 2, 130, 34, 162, 10, 138, 42, 170 },
|
||||
{ 192, 64, 224, 96, 200, 72, 232, 104, 194, 66, 226, 98, 202, 74, 234, 106 },
|
||||
{ 48, 176, 16, 144, 56, 184, 24, 152, 50, 178, 18, 146, 58, 186, 26, 154 },
|
||||
{ 240, 112, 208, 80, 248, 120, 216, 88, 242, 114, 210, 82, 250, 122, 218, 90 },
|
||||
{ 12, 140, 44, 172, 4, 132, 36, 164, 14, 142, 46, 174, 6, 134, 38, 166 },
|
||||
{ 204, 76, 236, 108, 196, 68, 228, 100, 206, 78, 238, 110, 198, 70, 230, 102 },
|
||||
{ 60, 188, 28, 156, 52, 180, 20, 148, 62, 190, 30, 158, 54, 182, 22, 150 },
|
||||
{ 252, 124, 220, 92, 244, 116, 212, 84, 254, 126, 222, 94, 246, 118, 214, 86 },
|
||||
{ 3, 131, 35, 163, 11, 139, 43, 171, 1, 129, 33, 161, 9, 137, 41, 169 },
|
||||
{ 195, 67, 227, 99, 203, 75, 235, 107, 193, 65, 225, 97, 201, 73, 233, 105 },
|
||||
{ 51, 179, 19, 147, 59, 187, 27, 155, 49, 177, 17, 145, 57, 185, 25, 153 },
|
||||
{ 243, 115, 211, 83, 251, 123, 219, 91, 241, 113, 209, 81, 249, 121, 217, 89 },
|
||||
{ 15, 143, 47, 175, 7, 135, 39, 167, 13, 141, 45, 173, 5, 133, 37, 165 },
|
||||
{ 207, 79, 239, 111, 199, 71, 231, 103, 205, 77, 237, 109, 197, 69, 229, 101 },
|
||||
{ 63, 191, 31, 159, 55, 183, 23, 151, 61, 189, 29, 157, 53, 181, 21, 149 },
|
||||
{ 255, 127, 223, 95, 247, 119, 215, 87, 253, 125, 221, 93, 245, 117, 213, 85 },
|
||||
};
|
||||
|
||||
static inline DWORD *get_pixel_ptr_32(const dib_info *dib, int x, int y)
|
||||
{
|
||||
return (DWORD *)((BYTE*)dib->bits.ptr + y * dib->stride + x * 4);
|
||||
@ -3999,16 +4029,9 @@ static inline DWORD gradient_rgb_24( const TRIVERTEX *v, unsigned int pos, unsig
|
||||
static inline WORD gradient_rgb_555( const TRIVERTEX *v, unsigned int pos, unsigned int len,
|
||||
unsigned int x, unsigned int y )
|
||||
{
|
||||
static const BYTE matrix[4][4] =
|
||||
{
|
||||
{ 0, 8, 2, 10 },
|
||||
{ 12, 4, 14, 6 },
|
||||
{ 3, 11, 1, 9 },
|
||||
{ 15, 7, 13, 5 }
|
||||
};
|
||||
int r = (v[0].Red * (len - pos) + v[1].Red * pos) / len / 128 + matrix[y % 4][x % 4];
|
||||
int g = (v[0].Green * (len - pos) + v[1].Green * pos) / len / 128 + matrix[y % 4][x % 4];
|
||||
int b = (v[0].Blue * (len - pos) + v[1].Blue * pos) / len / 128 + matrix[y % 4][x % 4];
|
||||
int r = (v[0].Red * (len - pos) + v[1].Red * pos) / len / 128 + bayer_4x4[y % 4][x % 4];
|
||||
int g = (v[0].Green * (len - pos) + v[1].Green * pos) / len / 128 + bayer_4x4[y % 4][x % 4];
|
||||
int b = (v[0].Blue * (len - pos) + v[1].Blue * pos) / len / 128 + bayer_4x4[y % 4][x % 4];
|
||||
r = min( 31, max( 0, r / 16 ));
|
||||
g = min( 31, max( 0, g / 16 ));
|
||||
b = min( 31, max( 0, b / 16 ));
|
||||
@ -4018,70 +4041,139 @@ static inline WORD gradient_rgb_555( const TRIVERTEX *v, unsigned int pos, unsig
|
||||
static inline BYTE gradient_rgb_8( const dib_info *dib, const TRIVERTEX *v,
|
||||
unsigned int pos, unsigned int len, unsigned int x, unsigned int y )
|
||||
{
|
||||
static const BYTE matrix[16][16] =
|
||||
{
|
||||
{ 0, 128, 32, 160, 8, 136, 40, 168, 2, 130, 34, 162, 10, 138, 42, 170 },
|
||||
{ 192, 64, 224, 96, 200, 72, 232, 104, 194, 66, 226, 98, 202, 74, 234, 106 },
|
||||
{ 48, 176, 16, 144, 56, 184, 24, 152, 50, 178, 18, 146, 58, 186, 26, 154 },
|
||||
{ 240, 112, 208, 80, 248, 120, 216, 88, 242, 114, 210, 82, 250, 122, 218, 90 },
|
||||
{ 12, 140, 44, 172, 4, 132, 36, 164, 14, 142, 46, 174, 6, 134, 38, 166 },
|
||||
{ 204, 76, 236, 108, 196, 68, 228, 100, 206, 78, 238, 110, 198, 70, 230, 102 },
|
||||
{ 60, 188, 28, 156, 52, 180, 20, 148, 62, 190, 30, 158, 54, 182, 22, 150 },
|
||||
{ 252, 124, 220, 92, 244, 116, 212, 84, 254, 126, 222, 94, 246, 118, 214, 86 },
|
||||
{ 3, 131, 35, 163, 11, 139, 43, 171, 1, 129, 33, 161, 9, 137, 41, 169 },
|
||||
{ 195, 67, 227, 99, 203, 75, 235, 107, 193, 65, 225, 97, 201, 73, 233, 105 },
|
||||
{ 51, 179, 19, 147, 59, 187, 27, 155, 49, 177, 17, 145, 57, 185, 25, 153 },
|
||||
{ 243, 115, 211, 83, 251, 123, 219, 91, 241, 113, 209, 81, 249, 121, 217, 89 },
|
||||
{ 15, 143, 47, 175, 7, 135, 39, 167, 13, 141, 45, 173, 5, 133, 37, 165 },
|
||||
{ 207, 79, 239, 111, 199, 71, 231, 103, 205, 77, 237, 109, 197, 69, 229, 101 },
|
||||
{ 63, 191, 31, 159, 55, 183, 23, 151, 61, 189, 29, 157, 53, 181, 21, 149 },
|
||||
{ 255, 127, 223, 95, 247, 119, 215, 87, 253, 125, 221, 93, 245, 117, 213, 85 },
|
||||
};
|
||||
BYTE r = ((v[0].Red * (len - pos) + v[1].Red * pos) / len / 128 + matrix[y % 16][x % 16]) / 256;
|
||||
BYTE g = ((v[0].Green * (len - pos) + v[1].Green * pos) / len / 128 + matrix[y % 16][x % 16]) / 256;
|
||||
BYTE b = ((v[0].Blue * (len - pos) + v[1].Blue * pos) / len / 128 + matrix[y % 16][x % 16]) / 256;
|
||||
BYTE r = ((v[0].Red * (len - pos) + v[1].Red * pos) / len / 128 + bayer_16x16[y % 16][x % 16]) / 256;
|
||||
BYTE g = ((v[0].Green * (len - pos) + v[1].Green * pos) / len / 128 + bayer_16x16[y % 16][x % 16]) / 256;
|
||||
BYTE b = ((v[0].Blue * (len - pos) + v[1].Blue * pos) / len / 128 + bayer_16x16[y % 16][x % 16]) / 256;
|
||||
return rgb_to_pixel_colortable( dib, r * 127, g * 127, b * 127 );
|
||||
}
|
||||
|
||||
static void gradient_rect_8888( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
/* compute the left/right triangle limit for row y */
|
||||
static inline void triangle_coords( const TRIVERTEX *v, const RECT *rc, int y, int *left, int *right )
|
||||
{
|
||||
DWORD *ptr = get_pixel_ptr_32( dib, rc->left, rc->top );
|
||||
int x, y;
|
||||
int x1, x2;
|
||||
|
||||
if (y < v[1].y) x1 = edge_coord( y, v[0].x, v[0].y, v[1].x, v[1].y );
|
||||
else x1 = edge_coord( y, v[1].x, v[1].y, v[2].x, v[2].y );
|
||||
|
||||
x2 = edge_coord( y, v[0].x, v[0].y, v[2].x, v[2].y );
|
||||
|
||||
*left = max( rc->left, min( x1, x2 ) );
|
||||
*right = min( rc->right, max( x1, x2 ) );
|
||||
}
|
||||
|
||||
/* compute the matrix determinant for triangular barycentric coordinates (constant across the triangle) */
|
||||
static inline int triangle_det( const TRIVERTEX *v )
|
||||
{
|
||||
return (v[2].y - v[1].y) * (v[2].x - v[0].x) - (v[2].x - v[1].x) * (v[2].y - v[0].y);
|
||||
}
|
||||
|
||||
/* compute the barycentric weights for a given point inside the triangle */
|
||||
static inline void triangle_weights( const TRIVERTEX *v, int x, int y, INT64 *l1, INT64 *l2 )
|
||||
{
|
||||
*l1 = (v[1].y - v[2].y) * (x - v[2].x) - (v[1].x - v[2].x) * (y - v[2].y);
|
||||
*l2 = (v[2].y - v[0].y) * (x - v[2].x) - (v[2].x - v[0].x) * (y - v[2].y);
|
||||
}
|
||||
|
||||
static inline DWORD gradient_triangle_8888( const TRIVERTEX *v, int x, int y, int det )
|
||||
{
|
||||
INT64 l1, l2;
|
||||
BYTE r, g, b, a;
|
||||
|
||||
triangle_weights( v, x, y, &l1, &l2 );
|
||||
r = (v[0].Red * l1 + v[1].Red * l2 + v[2].Red * (det - l1 - l2)) / det / 256;
|
||||
g = (v[0].Green * l1 + v[1].Green * l2 + v[2].Green * (det - l1 - l2)) / det / 256;
|
||||
b = (v[0].Blue * l1 + v[1].Blue * l2 + v[2].Blue * (det - l1 - l2)) / det / 256;
|
||||
a = (v[0].Alpha * l1 + v[1].Alpha * l2 + v[2].Alpha * (det - l1 - l2)) / det / 256;
|
||||
return a << 24 | r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
static inline DWORD gradient_triangle_24( const TRIVERTEX *v, int x, int y, int det )
|
||||
{
|
||||
INT64 l1, l2;
|
||||
BYTE r, g, b;
|
||||
|
||||
triangle_weights( v, x, y, &l1, &l2 );
|
||||
r = (v[0].Red * l1 + v[1].Red * l2 + v[2].Red * (det - l1 - l2)) / det / 256;
|
||||
g = (v[0].Green * l1 + v[1].Green * l2 + v[2].Green * (det - l1 - l2)) / det / 256;
|
||||
b = (v[0].Blue * l1 + v[1].Blue * l2 + v[2].Blue * (det - l1 - l2)) / det / 256;
|
||||
return r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
static inline DWORD gradient_triangle_555( const TRIVERTEX *v, int x, int y, int det )
|
||||
{
|
||||
INT64 l1, l2;
|
||||
int r, g, b;
|
||||
|
||||
triangle_weights( v, x, y, &l1, &l2 );
|
||||
r = (v[0].Red * l1 + v[1].Red * l2 + v[2].Red * (det - l1 - l2)) / det / 128 + bayer_4x4[y % 4][x % 4];
|
||||
g = (v[0].Green * l1 + v[1].Green * l2 + v[2].Green * (det - l1 - l2)) / det / 128 + bayer_4x4[y % 4][x % 4];
|
||||
b = (v[0].Blue * l1 + v[1].Blue * l2 + v[2].Blue * (det - l1 - l2)) / det / 128 + bayer_4x4[y % 4][x % 4];
|
||||
r = min( 31, max( 0, r / 16 ));
|
||||
g = min( 31, max( 0, g / 16 ));
|
||||
b = min( 31, max( 0, b / 16 ));
|
||||
return (r << 10) | (g << 5) | b;
|
||||
}
|
||||
|
||||
static inline DWORD gradient_triangle_8( const dib_info *dib, const TRIVERTEX *v, int x, int y, int det )
|
||||
{
|
||||
INT64 l1, l2;
|
||||
BYTE r, g, b;
|
||||
|
||||
triangle_weights( v, x, y, &l1, &l2 );
|
||||
r = ((v[0].Red * l1 + v[1].Red * l2 + v[2].Red * (det - l1 - l2)) / det / 128 + bayer_16x16[y % 16][x % 16]) / 256;
|
||||
g = ((v[0].Green * l1 + v[1].Green * l2 + v[2].Green * (det - l1 - l2)) / det / 128 + bayer_16x16[y % 16][x % 16]) / 256;
|
||||
b = ((v[0].Blue * l1 + v[1].Blue * l2 + v[2].Blue * (det - l1 - l2)) / det / 128 + bayer_16x16[y % 16][x % 16]) / 256;
|
||||
return rgb_to_pixel_colortable( dib, r * 127, g * 127, b * 127 );
|
||||
}
|
||||
|
||||
static BOOL gradient_rect_8888( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
DWORD *ptr = get_pixel_ptr_32( dib, 0, rc->top );
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case GRADIENT_FILL_RECT_H:
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
ptr[x] = gradient_rgb_8888( v, x + rc->left - v[0].x, v[1].x - v[0].x );
|
||||
for (x = rc->left; x < rc->right; x++)
|
||||
ptr[x] = gradient_rgb_8888( v, x - v[0].x, v[1].x - v[0].x );
|
||||
|
||||
for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride / 4)
|
||||
for (y = rc->top + 1, ptr += rc->left; y < rc->bottom; y++, ptr += dib->stride / 4)
|
||||
memcpy( ptr + dib->stride / 4, ptr, (rc->right - rc->left) * 4 );
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_RECT_V:
|
||||
for (y = rc->top; y < rc->bottom; y++)
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride / 4)
|
||||
{
|
||||
DWORD val = gradient_rgb_8888( v, y - v[0].y, v[1].y - v[0].y );
|
||||
for (x = 0; x < rc->right - rc->left; x++) ptr[x] = val;
|
||||
ptr += dib->stride / 4;
|
||||
for (x = rc->left; x < rc->right; x++) ptr[x] = val;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride / 4)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
for (x = left; x < right; x++) ptr[x] = gradient_triangle_8888( v, x, y, det );
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_32( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_32( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
DWORD *ptr = get_pixel_ptr_32( dib, rc->left, rc->top );
|
||||
int x, y;
|
||||
DWORD *ptr = get_pixel_ptr_32( dib, 0, rc->top );
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case GRADIENT_FILL_RECT_H:
|
||||
if (dib->red_len == 8 && dib->green_len == 8 && dib->blue_len == 8)
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
for (x = rc->left; x < rc->right; x++)
|
||||
{
|
||||
DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x );
|
||||
DWORD val = gradient_rgb_24( v, x - v[0].x, v[1].x - v[0].x );
|
||||
ptr[x] = ((( val & 0xff) << dib->blue_shift) |
|
||||
(((val >> 8) & 0xff) << dib->green_shift) |
|
||||
(((val >> 16) & 0xff) << dib->red_shift));
|
||||
@ -4089,16 +4181,16 @@ static void gradient_rect_32( const dib_info *dib, const RECT *rc, const TRIVERT
|
||||
}
|
||||
else
|
||||
{
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
for (x = rc->left; x < rc->right; x++)
|
||||
{
|
||||
DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x );
|
||||
DWORD val = gradient_rgb_24( v, x - v[0].x, v[1].x - v[0].x );
|
||||
ptr[x] = (put_field( val >> 16, dib->red_shift, dib->red_len ) |
|
||||
put_field( val >> 8, dib->green_shift, dib->green_len ) |
|
||||
put_field( val, dib->blue_shift, dib->blue_len ));
|
||||
}
|
||||
}
|
||||
|
||||
for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride / 4)
|
||||
for (y = rc->top + 1, ptr += rc->left; y < rc->bottom; y++, ptr += dib->stride / 4)
|
||||
memcpy( ptr + dib->stride / 4, ptr, (rc->right - rc->left) * 4 );
|
||||
break;
|
||||
|
||||
@ -4115,53 +4207,94 @@ static void gradient_rect_32( const dib_info *dib, const RECT *rc, const TRIVERT
|
||||
put_field( val >> 8, dib->green_shift, dib->green_len ) |
|
||||
put_field( val, dib->blue_shift, dib->blue_len ));
|
||||
|
||||
for (x = 0; x < rc->right - rc->left; x++) ptr[x] = val;
|
||||
for (x = rc->left; x < rc->right; x++) ptr[x] = val;
|
||||
ptr += dib->stride / 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride / 4)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
|
||||
if (dib->red_len == 8 && dib->green_len == 8 && dib->blue_len == 8)
|
||||
for (x = left; x < right; x++)
|
||||
{
|
||||
DWORD val = gradient_triangle_24( v, x, y, det );
|
||||
ptr[x] = ((( val & 0xff) << dib->blue_shift) |
|
||||
(((val >> 8) & 0xff) << dib->green_shift) |
|
||||
(((val >> 16) & 0xff) << dib->red_shift));
|
||||
}
|
||||
else
|
||||
for (x = left; x < right; x++)
|
||||
{
|
||||
DWORD val = gradient_triangle_24( v, x, y, det );
|
||||
ptr[x] = (put_field( val >> 16, dib->red_shift, dib->red_len ) |
|
||||
put_field( val >> 8, dib->green_shift, dib->green_len ) |
|
||||
put_field( val, dib->blue_shift, dib->blue_len ));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_24( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_24( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
BYTE *ptr = get_pixel_ptr_24( dib, rc->left, rc->top );
|
||||
int x, y;
|
||||
BYTE *ptr = get_pixel_ptr_24( dib, 0, rc->top );
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case GRADIENT_FILL_RECT_H:
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
for (x = rc->left; x < rc->right; x++)
|
||||
{
|
||||
DWORD val = gradient_rgb_24( v, x + rc->left - v[0].x, v[1].x - v[0].x );
|
||||
DWORD val = gradient_rgb_24( v, x - v[0].x, v[1].x - v[0].x );
|
||||
ptr[x * 3] = val;
|
||||
ptr[x * 3 + 1] = val >> 8;
|
||||
ptr[x * 3 + 2] = val >> 16;
|
||||
}
|
||||
|
||||
for (y = rc->top + 1; y < rc->bottom; y++, ptr += dib->stride)
|
||||
for (y = rc->top + 1, ptr += rc->left * 3; y < rc->bottom; y++, ptr += dib->stride)
|
||||
memcpy( ptr + dib->stride, ptr, (rc->right - rc->left) * 3 );
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_RECT_V:
|
||||
for (y = rc->top; y < rc->bottom; y++)
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride)
|
||||
{
|
||||
DWORD val = gradient_rgb_24( v, y - v[0].y, v[1].y - v[0].y );
|
||||
for (x = 0; x < rc->right - rc->left; x++)
|
||||
for (x = rc->left; x < rc->right; x++)
|
||||
{
|
||||
ptr[x * 3] = val;
|
||||
ptr[x * 3 + 1] = val >> 8;
|
||||
ptr[x * 3 + 2] = val >> 16;
|
||||
}
|
||||
ptr += dib->stride;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
for (x = left; x < right; x++)
|
||||
{
|
||||
DWORD val = gradient_triangle_24( v, x, y, det );
|
||||
ptr[x * 3] = val;
|
||||
ptr[x * 3 + 1] = val >> 8;
|
||||
ptr[x * 3 + 2] = val >> 16;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_555( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_555( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
WORD *ptr = get_pixel_ptr_16( dib, 0, rc->top );
|
||||
int x, y;
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
@ -4181,13 +4314,23 @@ static void gradient_rect_555( const dib_info *dib, const RECT *rc, const TRIVER
|
||||
for (x = rc->left; x < rc->right; x++) ptr[x] = values[x % 4];
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride / 2)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
for (x = left; x < right; x++) ptr[x] = gradient_triangle_555( v, x, y, det );
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_16( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_16( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
WORD *ptr = get_pixel_ptr_16( dib, 0, rc->top );
|
||||
int x, y;
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
@ -4199,7 +4342,6 @@ static void gradient_rect_16( const dib_info *dib, const RECT *rc, const TRIVERT
|
||||
ptr[x] = (put_field(((val >> 7) & 0xf8) | ((val >> 12) & 0x07), dib->red_shift, dib->red_len) |
|
||||
put_field(((val >> 2) & 0xf8) | ((val >> 7) & 0x07), dib->green_shift, dib->green_len) |
|
||||
put_field(((val << 3) & 0xf8) | ((val >> 2) & 0x07), dib->blue_shift, dib->blue_len));
|
||||
|
||||
}
|
||||
for (ptr += rc->left; y < rc->bottom; y++, ptr += dib->stride / 2)
|
||||
memcpy( ptr, ptr - dib->stride * 2, (rc->right - rc->left) * 2 );
|
||||
@ -4219,13 +4361,29 @@ static void gradient_rect_16( const dib_info *dib, const RECT *rc, const TRIVERT
|
||||
for (x = rc->left; x < rc->right; x++) ptr[x] = values[x % 4];
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride / 2)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
for (x = left; x < right; x++)
|
||||
{
|
||||
WORD val = gradient_triangle_555( v, x, y, det );
|
||||
ptr[x] = (put_field(((val >> 7) & 0xf8) | ((val >> 12) & 0x07), dib->red_shift, dib->red_len) |
|
||||
put_field(((val >> 2) & 0xf8) | ((val >> 7) & 0x07), dib->green_shift, dib->green_len) |
|
||||
put_field(((val << 3) & 0xf8) | ((val >> 2) & 0x07), dib->blue_shift, dib->blue_len));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_8( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_8( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
BYTE *ptr = get_pixel_ptr_8( dib, 0, rc->top );
|
||||
int x, y;
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
@ -4246,13 +4404,23 @@ static void gradient_rect_8( const dib_info *dib, const RECT *rc, const TRIVERTE
|
||||
for (x = rc->left; x < rc->right; x++) ptr[x] = values[x % 16];
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
for (x = left; x < right; x++) ptr[x] = gradient_triangle_8( dib, v, x, y, det );
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_4( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_4( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
BYTE *ptr = get_pixel_ptr_4( dib, 0, rc->top );
|
||||
int x, y;
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
@ -4295,13 +4463,30 @@ static void gradient_rect_4( const dib_info *dib, const RECT *rc, const TRIVERTE
|
||||
ptr[x / 2] = (values[x % 16] << 4) | (ptr[x / 2] & 0x0f);
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
for (x = left; x < right; x++)
|
||||
{
|
||||
BYTE val = gradient_triangle_8( dib, v, x, y, det );
|
||||
if (x & 1)
|
||||
ptr[x / 2] = val | (ptr[x / 2] & 0xf0);
|
||||
else
|
||||
ptr[x / 2] = (val << 4) | (ptr[x / 2] & 0x0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_1( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_1( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
BYTE *ptr = get_pixel_ptr_1( dib, 0, rc->top );
|
||||
int x, y;
|
||||
int x, y, left, right, det;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
@ -4329,11 +4514,27 @@ static void gradient_rect_1( const dib_info *dib, const RECT *rc, const TRIVERTE
|
||||
ptr += dib->stride;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRADIENT_FILL_TRIANGLE:
|
||||
if (!(det = triangle_det( v ))) return FALSE;
|
||||
for (y = rc->top; y < rc->bottom; y++, ptr += dib->stride)
|
||||
{
|
||||
triangle_coords( v, rc, y, &left, &right );
|
||||
for (x = left; x < right; x++)
|
||||
{
|
||||
DWORD val = gradient_triangle_24( v, x, y, det );
|
||||
val = rgb_to_pixel_colortable( dib, val >> 16, val >> 8, val ) ? 0xff : 0;
|
||||
ptr[x / 8] = (ptr[x / 8] & ~pixel_masks_1[x % 8]) | (val & pixel_masks_1[x % 8]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void gradient_rect_null( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
static BOOL gradient_rect_null( const dib_info *dib, const RECT *rc, const TRIVERTEX *v, int mode )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BYTE aa_color( BYTE dst, BYTE text, BYTE min_comp, BYTE max_comp )
|
||||
|
Loading…
Reference in New Issue
Block a user