Huw Davies : gdi32: Add a directional bias for the case when the Bresenham error term is zero.

Alexandre Julliard julliard at winehq.org
Wed Apr 20 11:05:19 CDT 2011


Module: wine
Branch: master
Commit: a9675b35093aa3226814c37dd8b2c36270056293
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=a9675b35093aa3226814c37dd8b2c36270056293

Author: Huw Davies <huw at codeweavers.com>
Date:   Wed Apr 20 12:52:06 2011 +0100

gdi32: Add a directional bias for the case when the Bresenham error term is zero.

---

 dlls/gdi32/dibdrv/objects.c |   83 +++++++++++++++++++++++++++++++++++++++++-
 dlls/gdi32/tests/dib.c      |   21 +++++++++++
 2 files changed, 102 insertions(+), 2 deletions(-)

diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c
index c8fb7fe..a2411c3 100644
--- a/dlls/gdi32/dibdrv/objects.c
+++ b/dlls/gdi32/dibdrv/objects.c
@@ -106,7 +106,31 @@ static inline BOOL pt_in_rect( const RECT *rect, const POINT *pt )
             (pt->y >= rect->top) && (pt->y < rect->bottom));
 }
 
-static void WINAPI solid_pen_line_callback(INT x, INT y, LPARAM lparam)
+/**********************************************************************
+ *                  get_octant_number
+ *
+ * Return the octant number starting clockwise from the +ve x-axis.
+ */
+static inline int get_octant_number(int dx, int dy)
+{
+    if(dy > 0)
+        if(dx > 0)
+            return ( dx >  dy) ? 1 : 2;
+        else
+            return (-dx >  dy) ? 4 : 3;
+    else
+        if(dx < 0)
+            return (-dx > -dy) ? 5 : 6;
+        else
+            return ( dx > -dy) ? 8 : 7;
+}
+
+static inline DWORD get_octant_mask(int dx, int dy)
+{
+    return 1 << (get_octant_number(dx, dy) - 1);
+}
+
+static void solid_pen_line_callback(INT x, INT y, LPARAM lparam)
 {
     dibdrv_physdev *pdev = (dibdrv_physdev *)lparam;
     RECT rect;
@@ -119,6 +143,61 @@ static void WINAPI solid_pen_line_callback(INT x, INT y, LPARAM lparam)
     return;
 }
 
+static void bres_line_with_bias(INT x1, INT y1, INT x2, INT y2, void (* callback)(INT,INT,LPARAM), LPARAM lParam)
+{
+    INT xadd = 1, yadd = 1;
+    INT err, erradd;
+    INT cnt;
+    INT dx = x2 - x1;
+    INT dy = y2 - y1;
+    DWORD octant = get_octant_mask(dx, dy);
+    INT bias = 0;
+
+    /* Octants 3, 5, 6 and 8 take a bias */
+    if(octant & 0xb4) bias = 1;
+
+    if (dx < 0)
+    {
+        dx = -dx;
+        xadd = -1;
+    }
+    if (dy < 0)
+    {
+        dy = -dy;
+        yadd = -1;
+    }
+    if (dx > dy)  /* line is "more horizontal" */
+    {
+        err = 2*dy - dx; erradd = 2*dy - 2*dx;
+        for(cnt = 0; cnt < dx; cnt++)
+        {
+            callback(x1, y1, lParam);
+            if (err + bias > 0)
+            {
+                y1 += yadd;
+                err += erradd;
+            }
+            else err += 2*dy;
+            x1 += xadd;
+        }
+    }
+    else   /* line is "more vertical" */
+    {
+        err = 2*dx - dy; erradd = 2*dx - 2*dy;
+        for(cnt = 0; cnt < dy; cnt++)
+        {
+            callback(x1, y1, lParam);
+            if (err + bias > 0)
+            {
+                x1 += xadd;
+                err += erradd;
+            }
+            else err += 2*dx;
+            y1 += yadd;
+        }
+    }
+}
+
 static BOOL solid_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end)
 {
     const WINEREGION *clip = get_wine_region(pdev->clip);
@@ -188,7 +267,7 @@ static BOOL solid_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end)
         if(clip->numRects == 1 && pt_in_rect(&clip->extents, start) && pt_in_rect(&clip->extents, end))
             /* FIXME: Optimize by moving Bresenham algorithm to the primitive functions,
                or at least cache adjacent points in the callback */
-            LineDDA(start->x, start->y, end->x, end->y, solid_pen_line_callback, (LPARAM)pdev);
+            bres_line_with_bias(start->x, start->y, end->x, end->y, solid_pen_line_callback, (LPARAM)pdev);
         else if(clip->numRects >= 1)
             ret = FALSE;
     }
diff --git a/dlls/gdi32/tests/dib.c b/dlls/gdi32/tests/dib.c
index 784d8d5..3046799 100644
--- a/dlls/gdi32/tests/dib.c
+++ b/dlls/gdi32/tests/dib.c
@@ -78,6 +78,7 @@ static const char *sha1_graphics_a8r8g8b8[] =
     "a3cadd34d95d3d5cc23344f69aab1c2e55935fcf",
     "2426172d9e8fec27d9228088f382ef3c93717da9",
     "9e8f27ca952cdba01dbf25d07c34e86a7820c012",
+    "664fac17803859a4015c6ae29e5538e314d5c827",
     "17b2c177bdce5e94433574a928bda5c94a8cdfa5",
     "fe6cc678fb13a3ead67839481bf22348adc69f52",
     "d51bd330cec510cdccf5394328bd8e5411901e9e",
@@ -150,6 +151,18 @@ static void compare_hash(BITMAPINFO *bmi, BYTE *bits, const char ***sha1, const
     HeapFree(GetProcessHeap(), 0, hash);
 }
 
+static const RECT bias_check[] =
+{
+    {100, 100, 200, 150},
+    {100, 100, 150, 200},
+    {100, 100,  50, 200},
+    {100, 100,   0, 150},
+    {100, 100,   0,  50},
+    {100, 100,  50,   0},
+    {100, 100, 150,   0},
+    {100, 100, 200,  50}
+};
+
 static const RECT hline_clips[] =
 {
     {120, 120, 140, 120}, /* unclipped */
@@ -251,6 +264,14 @@ static void draw_graphics(HDC hdc, BITMAPINFO *bmi, BYTE *bits, const char ***sh
     compare_hash(bmi, bits, sha1, "diagonal solid lines");
     memset(bits, 0xcc, dib_size);
 
+    for(i = 0; i < sizeof(bias_check) / sizeof(bias_check[0]); i++)
+    {
+        MoveToEx(hdc, bias_check[i].left, bias_check[i].top, NULL);
+        LineTo(hdc, bias_check[i].right, bias_check[i].bottom);
+    }
+    compare_hash(bmi, bits, sha1, "more diagonal solid lines");
+    memset(bits, 0xcc, dib_size);
+
     /* solid brush PatBlt */
     solid_brush = CreateSolidBrush(RGB(0x33, 0xaa, 0xff));
     orig_brush = SelectObject(hdc, solid_brush);




More information about the wine-cvs mailing list