From 743b37df3d09bedc4521cf01549a190000b89368 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 4 Dec 2011 17:10:30 +0100 Subject: [PATCH] gdi32: Implement triangular gradients in the DIB engine. --- dlls/gdi32/dibdrv/bitblt.c | 189 +++++++++++++----- dlls/gdi32/dibdrv/dibdrv.h | 11 +- dlls/gdi32/dibdrv/primitives.c | 343 ++++++++++++++++++++++++++------- 3 files changed, 427 insertions(+), 116 deletions(-) diff --git a/dlls/gdi32/dibdrv/bitblt.c b/dlls/gdi32/dibdrv/bitblt.c index 6581ae48492..7c327192d67 100644 --- a/dlls/gdi32/dibdrv/bitblt.c +++ b/dlls/gdi32/dibdrv/bitblt.c @@ -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; } diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index 5e983cf8f41..e3782df604a 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -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); diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c index 5938a1b6f85..47ba0e1a40b 100644 --- a/dlls/gdi32/dibdrv/primitives.c +++ b/dlls/gdi32/dibdrv/primitives.c @@ -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 )