update for HEAD-2003091401
[reactos.git] / drivers / dd / vga / display / objects / lineto.c
index 6fceab6..7e83ecb 100644 (file)
@@ -1,9 +1,297 @@
+/*
+ *  ReactOS VGA driver
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
 #include "../vgaddi.h"
 #include "../vgavideo/vgavideo.h"
 
+/*
+ * Draw a line from top-left to bottom-right
+ */
+static void FASTCALL
+vgaNWtoSE(PCLIPOBJ Clip, PBRUSHOBJ Brush, LONG x, LONG y, LONG deltax, LONG deltay)
+{
+  int i;
+  int error;
+  BOOLEAN EnumMore;
+  PRECTL ClipRect;
+  RECT_ENUM RectEnum;
+  ULONG Pixel = Brush->iSolidColor;
+  LONG delta;
+
+  CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, ENUM_RECT_LIMIT);
+  EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+  ClipRect = RectEnum.arcl;
+  delta = max(deltax, deltay);
+  i = 0;
+  error = delta/2;
+  while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
+    {
+      while ((ClipRect < RectEnum.arcl + RectEnum.c /* there's still a current clip rect */
+              && (ClipRect->bottom <= y             /* but it's above us */
+                  || (ClipRect->top <= y && ClipRect->right <= x))) /* or to the left of us */
+             || EnumMore)                           /* no current clip rect, but rects left */
+       {
+         /* Skip to the next clip rect */
+         if (RectEnum.arcl + RectEnum.c <= ClipRect)
+           {
+             EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+             ClipRect = RectEnum.arcl;
+           }
+         else
+           {
+             ClipRect++;
+           }
+       }
+      if ( ClipRect < RectEnum.arcl + RectEnum.c ) /* If there's no current clip rect we're done */
+       {
+         if (ClipRect->left <= x && ClipRect->top <= y)
+           {
+             vgaPutPixel ( x, y, Pixel );
+           }
+         if ( deltax < deltay )
+           {
+             y++;
+             error += deltax;
+             if ( error >= deltay )
+               {
+                 x++;
+                 error -= deltay;
+               }
+           }
+         else
+           {
+             x++;
+             error += deltay;
+             if ( error >= deltax )
+               {
+                 y++;
+                 error -= deltax;
+               }
+           }
+         i++;
+       }
+    }
+}
+
+static void FASTCALL
+vgaSWtoNE(PCLIPOBJ Clip, PBRUSHOBJ Brush, LONG x, LONG y, LONG deltax, LONG deltay)
+{
+  int i;
+  int error;
+  BOOLEAN EnumMore;
+  PRECTL ClipRect;
+  RECT_ENUM RectEnum;
+  ULONG Pixel = Brush->iSolidColor;
+  LONG delta;
 
+  CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTUP, ENUM_RECT_LIMIT);
+  EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+  ClipRect = RectEnum.arcl;
+  delta = max(deltax, deltay);
+  i = 0;
+  error = delta/2;
+  while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
+    {
+      while ((ClipRect < RectEnum.arcl + RectEnum.c
+              && (y < ClipRect->top
+                  || (y < ClipRect->bottom && ClipRect->right <= x)))
+             || EnumMore)
+       {
+         if (RectEnum.arcl + RectEnum.c <= ClipRect)
+           {
+             EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+             ClipRect = RectEnum.arcl;
+           }
+         else
+           {
+             ClipRect++;
+           }
+       }
+      if (ClipRect < RectEnum.arcl + RectEnum.c)
+       {
+         if (ClipRect->left <= x && y < ClipRect->bottom)
+           {
+             vgaPutPixel(x, y, Pixel);
+           }
+         if (deltax < deltay)
+           {
+             y--;
+             error = error + deltax;
+             if (deltay <= error)
+               {
+                 x++;
+                 error = error - deltay;
+               }
+           }
+         else
+           {
+             x++;
+             error = error + deltay;
+             if (deltax <= error)
+               {
+                 y--;
+                 error = error - deltax;
+               }
+           }
+         i++;
+       }
+    }
+}
+
+static void FASTCALL
+vgaNEtoSW(PCLIPOBJ Clip, PBRUSHOBJ Brush, LONG x, LONG y, LONG deltax, LONG deltay)
+{
+  int i;
+  int error;
+  BOOLEAN EnumMore;
+  PRECTL ClipRect;
+  RECT_ENUM RectEnum;
+  ULONG Pixel = Brush->iSolidColor;
+  LONG delta;
+
+  CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTDOWN, ENUM_RECT_LIMIT);
+  EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+  ClipRect = RectEnum.arcl;
+  delta = max(deltax, deltay);
+  i = 0;
+  error = delta/2;
+  while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
+    {
+      while ((ClipRect < RectEnum.arcl + RectEnum.c
+              && (ClipRect->bottom <= y
+                  || (ClipRect->top <= y && x < ClipRect->left)))
+             || EnumMore)
+       {
+         if (RectEnum.arcl + RectEnum.c <= ClipRect)
+           {
+             EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+             ClipRect = RectEnum.arcl;
+           }
+         else
+           {
+             ClipRect++;
+           }
+       }
+      if (ClipRect < RectEnum.arcl + RectEnum.c)
+       {
+         if (x < ClipRect->right && ClipRect->top <= y)
+           {
+             vgaPutPixel(x, y, Pixel);
+           }
+         if (deltax < deltay)
+           {
+             y++;
+             error = error + deltax;
+             if (deltay <= error)
+               {
+                 x--;
+                 error = error - deltay;
+               }
+           }
+         else
+           {
+             x--;
+             error = error + deltay;
+             if (deltax <= error)
+               {
+                 y++;
+                 error = error - deltax;
+               }
+           }
+         i++;
+       }
+    }
+}
+
+static void FASTCALL
+vgaSEtoNW(PCLIPOBJ Clip, PBRUSHOBJ Brush, LONG x, LONG y, LONG deltax, LONG deltay)
+{
+  int i;
+  int error;
+  BOOLEAN EnumMore;
+  PRECTL ClipRect;
+  RECT_ENUM RectEnum;
+  ULONG Pixel = Brush->iSolidColor;
+  LONG delta;
+
+  CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTUP, ENUM_RECT_LIMIT);
+  EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+  ClipRect = RectEnum.arcl;
+  delta = max(deltax, deltay);
+  i = 0;
+  error = delta/2;
+  while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
+    {
+      while ((ClipRect < RectEnum.arcl + RectEnum.c
+              && (y < ClipRect->top
+                  || (y < ClipRect->bottom && x < ClipRect->left)))
+             || EnumMore)
+       {
+         if (RectEnum.arcl + RectEnum.c <= ClipRect)
+           {
+             EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+             ClipRect = RectEnum.arcl;
+           }
+         else
+           {
+             ClipRect++;
+           }
+       }
+      if (ClipRect < RectEnum.arcl + RectEnum.c)
+       {
+         if (x < ClipRect->right && y < ClipRect->bottom)
+           {
+             vgaPutPixel(x, y, Pixel);
+           }
+         if (deltax < deltay)
+           {
+             y--;
+             error = error + deltax;
+             if (deltay <= error)
+               {
+                 x--;
+                 error = error - deltay;
+               }
+           }
+         else
+           {
+             x--;
+             error = error + deltay;
+             if (deltax <= error)
+               {
+                 y--;
+                 error = error - deltax;
+               }
+           }
+         i++;
+       }
+    }
+}
+
+/*
+ * FIXME: Use Mix to perform ROPs
+ * FIXME: Non-solid Brush
+ */
 BOOL STDCALL
-DrvLineTo(SURFOBJ *Surface,
+DrvLineTo(SURFOBJ *DestObj,
          CLIPOBJ *Clip,
          BRUSHOBJ *Brush,
          LONG x1,
@@ -12,16 +300,12 @@ DrvLineTo(SURFOBJ *Surface,
          LONG y2,
          RECTL *RectBounds,
          MIX mix)
-
-// FIXME: Use ClipObj and RectBounds to clip the line where required
-// FIXME: Use Mix to perform ROPs
-
 {
-  LONG deltax, deltay, x, y, d, i, xchange, ychange, error, iSolidColor, hx, vy;
-
-  iSolidColor = Brush->iSolidColor; // FIXME: Brush Realization...
-
-  // FIXME: Implement clipping
+  LONG x, y, deltax, deltay, i, xchange, ychange, hx, vy;
+  ULONG Pixel = Brush->iSolidColor;
+  RECTL DestRect;
+  RECT_ENUM RectEnum;
+  BOOL EnumMore;
 
   x = x1;
   y = y1;
@@ -30,73 +314,101 @@ DrvLineTo(SURFOBJ *Surface,
 
   if (deltax < 0)
     {
-    xchange = -1;
-    deltax = - deltax;
-    hx = x2;
-    x--;
+      xchange = -1;
+      deltax = - deltax;
+      hx = x2+1;
+      //x--;
     }
   else
     {
-    xchange = 1;
-    hx = x1;
+      xchange = 1;
+      hx = x1;
     }
 
   if (deltay < 0)
     {
-    ychange = -1;
-    deltay = - deltay;
-    vy = y2;
-    y--;
+      ychange = -1;
+      deltay = - deltay;
+      vy = y2+1;
+      //y--;
     }
   else
     {
-    ychange = 1;
-    vy = y1;
-    };
+      ychange = 1;
+      vy = y1;
+    }
 
   if (y1 == y2)
     {
-    return vgaHLine(hx, y1, deltax, iSolidColor);
+      CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, ENUM_RECT_LIMIT);
+      do
+       {
+         EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+         for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= y1; i++)
+           {
+             if (y1 < RectEnum.arcl[i].bottom &&
+                 RectEnum.arcl[i].left <= hx + deltax &&
+                 hx < RectEnum.arcl[i].right)
+               {
+
+                 vgaHLine(max(hx, RectEnum.arcl[i].left), y1,
+                          min(hx + deltax, RectEnum.arcl[i].right)
+                          -max(hx, RectEnum.arcl[i].left), Pixel);
+               }
+           }
+       }
+      while (EnumMore);
     }
-  if (x1 == x2)
+  else if (x1 == x2)
     {
-    return vgaVLine(x1, vy, deltay, iSolidColor);
+      CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, ENUM_RECT_LIMIT);
+      do
+       {
+         EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+         for (i = 0; i < RectEnum.c; i++)
+           {
+             if (RectEnum.arcl[i].left <= x1 &&
+                  x1 < RectEnum.arcl[i].right &&
+                 RectEnum.arcl[i].top <= vy + deltay &&
+                 vy < RectEnum.arcl[i].bottom)
+               {
+                 vgaVLine(x1,
+                          max(vy, RectEnum.arcl[i].top),
+                          min(vy + deltay, RectEnum.arcl[i].bottom)
+                          - max(vy, RectEnum.arcl[i].top),
+                          Pixel);
+               }
+           }
+       }
+      while (EnumMore);
     }
-
-  // Using individual pixels to draw a line neither horizontal or vertical
-  // Set up the VGA masking for individual pixels
-
-  error = 0;
-
-  if (deltax < deltay)
+  else
     {
-    for (i = 0; i < deltay; i++)
-      {
-      vgaPutPixel(x, y, iSolidColor);
-      y = y + ychange;
-      error = error + deltax;
-
-      if (deltay <= error)
-        {
-        x = x + xchange;
-        error = error - deltay;
-        }
-      }
+      if (0 < xchange)
+       {
+         if (0 < ychange)
+           {
+             vgaNWtoSE(Clip, Brush, x, y, deltax, deltay);
+           }
+         else
+           {
+             vgaSWtoNE(Clip, Brush, x, y, deltax, deltay);
+           }
+       }
+      else
+       {
+         if (0 < ychange)
+           {
+             vgaNEtoSW(Clip, Brush, x, y, deltax, deltay);
+           }
+         else
+           {
+             vgaSEtoNW(Clip, Brush, x, y, deltax, deltay);
+           }
+       }
     }
-   else
-    {
-    for (i = 0; i < deltax; i++)
-      {
-      vgaPutPixel(x, y, iSolidColor);
-      x = x + xchange;
-      error = error + deltay;
-      if (deltax <= error)
-        {
-        y = y + ychange;
-        error = error - deltax;
-        }
-      }
-   }
-
-   return TRUE;
+
+  return TRUE;
 }
+
+/* EOF */