From 8a036abc5cdfc443a34d5f57195a4b0f941f062f Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Thu, 10 Mar 2011 14:42:19 -0600 Subject: [PATCH] gdiplus: Implement software rendering of texture brushes. --- dlls/gdiplus/brush.c | 1 + dlls/gdiplus/gdiplus_private.h | 1 + dlls/gdiplus/graphics.c | 110 +++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/dlls/gdiplus/brush.c b/dlls/gdiplus/brush.c index 6cc78e8bdd3..88958a7e73a 100644 --- a/dlls/gdiplus/brush.c +++ b/dlls/gdiplus/brush.c @@ -1022,6 +1022,7 @@ GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush) GdipDeleteMatrix(((GpTexture*)brush)->transform); GdipDisposeImage(((GpTexture*)brush)->image); GdipDisposeImageAttributes(((GpTexture*)brush)->imageattributes); + GdipFree(((GpTexture*)brush)->bitmap_bits); break; default: break; diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 4575875b895..c0b10e737a2 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -216,6 +216,7 @@ struct GpTexture{ GpMatrix *transform; GpImage *image; GpImageAttributes *imageattributes; + BYTE *bitmap_bits; /* image bits converted to ARGB and run through imageattributes */ }; struct GpPath{ diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index a5a040b2444..8f4e9d0cfa7 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -750,6 +750,7 @@ static INT brush_can_fill_pixels(GpBrush *brush) case BrushTypeSolidColor: case BrushTypeHatchFill: case BrushTypeLinearGradient: + case BrushTypeTextureFill: return 1; default: return 0; @@ -856,6 +857,115 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush, return stat; } + case BrushTypeTextureFill: + { + GpTexture *fill = (GpTexture*)brush; + GpPointF draw_points[3]; + GpStatus stat; + GpMatrix *world_to_texture; + int x, y; + GpBitmap *bitmap; + int src_stride; + GpRect src_area; + + if (fill->image->type != ImageTypeBitmap) + { + FIXME("metafile texture brushes not implemented\n"); + return NotImplemented; + } + + bitmap = (GpBitmap*)fill->image; + src_stride = sizeof(ARGB) * bitmap->width; + + src_area.X = src_area.Y = 0; + src_area.Width = bitmap->width; + src_area.Height = bitmap->height; + + draw_points[0].X = fill_area->X; + draw_points[0].Y = fill_area->Y; + draw_points[1].X = fill_area->X+1; + draw_points[1].Y = fill_area->Y; + draw_points[2].X = fill_area->X; + draw_points[2].Y = fill_area->Y+1; + + /* Transform the points to the co-ordinate space of the bitmap. */ + stat = GdipTransformPoints(graphics, CoordinateSpaceWorld, + CoordinateSpaceDevice, draw_points, 3); + + if (stat == Ok) + { + stat = GdipCloneMatrix(fill->transform, &world_to_texture); + } + + if (stat == Ok) + { + stat = GdipInvertMatrix(world_to_texture); + + if (stat == Ok) + stat = GdipTransformMatrixPoints(world_to_texture, draw_points, 3); + + GdipDeleteMatrix(world_to_texture); + } + + if (stat == Ok && !fill->bitmap_bits) + { + BitmapData lockeddata; + + fill->bitmap_bits = GdipAlloc(sizeof(ARGB) * bitmap->width * bitmap->height); + if (!fill->bitmap_bits) + stat = OutOfMemory; + + if (stat == Ok) + { + lockeddata.Width = bitmap->width; + lockeddata.Height = bitmap->height; + lockeddata.Stride = src_stride; + lockeddata.PixelFormat = PixelFormat32bppARGB; + lockeddata.Scan0 = fill->bitmap_bits; + + stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf, + PixelFormat32bppARGB, &lockeddata); + } + + if (stat == Ok) + stat = GdipBitmapUnlockBits(bitmap, &lockeddata); + + if (stat == Ok) + apply_image_attributes(fill->imageattributes, fill->bitmap_bits, + bitmap->width, bitmap->height, + src_stride, ColorAdjustTypeBitmap); + + if (stat != Ok) + { + GdipFree(fill->bitmap_bits); + fill->bitmap_bits = NULL; + } + } + + if (stat == Ok) + { + REAL x_dx = draw_points[1].X - draw_points[0].X; + REAL x_dy = draw_points[1].Y - draw_points[0].Y; + REAL y_dx = draw_points[2].X - draw_points[0].X; + REAL y_dy = draw_points[2].Y - draw_points[0].Y; + + for (y=0; yHeight; y++) + { + for (x=0; xWidth; x++) + { + GpPointF point; + point.X = draw_points[0].X + x * x_dx + y * y_dx; + point.Y = draw_points[0].Y + y * x_dy + y * y_dy; + + argb_pixels[x + y*cdwStride] = resample_bitmap_pixel( + &src_area, fill->bitmap_bits, bitmap->width, bitmap->height, + &point, fill->imageattributes, graphics->interpolation); + } + } + } + + return stat; + } default: return NotImplemented; }