[ros-diffs] [jimtabor] 34169: Arc: - Ported GraphApp draw arc fill algorithm. It was faster than X11. Include copyright license in header. - Now we can draw pies and arcs and fill them, need to test chord fill.

jimtabor at svn.reactos.org jimtabor at svn.reactos.org
Sun Jun 29 03:19:47 CEST 2008


Author: jimtabor
Date: Sat Jun 28 20:19:46 2008
New Revision: 34169

URL: http://svn.reactos.org/svn/reactos?rev=34169&view=rev
Log:
Arc:
- Ported GraphApp draw arc fill algorithm. It was faster than X11. Include copyright license in header.
- Now we can draw pies and arcs and fill them, need to test chord fill.

Added:
    trunk/reactos/subsystems/win32/win32k/objects/drawing.c   (with props)
Modified:
    trunk/reactos/subsystems/win32/win32k/objects/arc.c
    trunk/reactos/subsystems/win32/win32k/win32k.rbuild

Modified: trunk/reactos/subsystems/win32/win32k/objects/arc.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/objects/arc.c?rev=34169&r1=34168&r2=34169&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/objects/arc.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/objects/arc.c [iso-8859-1] Sat Jun 28 20:19:46 2008
@@ -24,6 +24,8 @@
 
 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
+
+BOOL FASTCALL IntFillArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype);
 
 static
 BOOL
@@ -41,10 +43,11 @@
 {
     PDC_ATTR Dc_Attr;
     RECTL RectBounds;
-    PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
-    GDIBRUSHINST FillBrushInst, PenBrushInst;
+    PGDIBRUSHOBJ PenBrushObj;
+    GDIBRUSHINST PenBrushInst;
     BITMAPOBJ *BitmapObj;
     BOOL ret = TRUE;
+    LONG PenWidth, PenOrigWidth;
     double AngleStart, AngleEnd;
     LONG RadiusX, RadiusY, CenterX, CenterY;
     LONG SfCx, SfCy, EfCx, EfCy;
@@ -60,50 +63,58 @@
           0|___________________|
             0     bottom       +
  */
-    if (Right <= Left || Top <= Bottom)
-    {
-        DPRINT1("Arc Fail 1\n");
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-/*
-    if (Right - Left != Bottom - Top)
-    {
-        UNIMPLEMENTED;
-    }
-*/
+    if (Right < Left)
+    {
+       INT tmp = Right; Right = Left; Left = tmp;
+    }
+    if (Bottom < Top)
+    {
+       INT tmp = Bottom; Bottom = Top; Top = tmp;
+    }
+    if ((Left == Right) ||
+        (Top == Bottom) ||
+        (((arctype != GdiTypeArc) || (arctype != GdiTypeArcTo)) &&
+        ((Right - Left == 1) ||
+        (Bottom - Top == 1))))
+       return TRUE;
+
+    if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
+    { 
+       INT X, Y;
+       X = XRadialStart;
+       Y = YRadialStart;
+       XRadialStart = XRadialEnd;
+       YRadialStart = YRadialEnd;
+       XRadialEnd = X;
+       YRadialEnd = Y;
+    }
+
     Dc_Attr = dc->pDc_Attr;
     if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-    FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
-    if (NULL == FillBrushObj)
-    {
-        DPRINT1("Arc Fail 2\n");
+    PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
+    if (NULL == PenBrushObj)
+    {
+        DPRINT1("Arc Fail 1\n");
         SetLastWin32Error(ERROR_INTERNAL_ERROR);
         return FALSE;
     }
 
-    PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
-    if (NULL == PenBrushObj)
-    {
-        DPRINT1("Arc Fail 3\n");
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
-        return FALSE;
-    }
-
-    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
-    if (NULL == BitmapObj)
-    {
-        DPRINT1("Arc Fail 4\n");
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
-        PENOBJ_UnlockPen(PenBrushObj);
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
-        return FALSE;
-    }
-
-    IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
-    IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
+    PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
+    if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
+
+    if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
+    {
+       if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
+       if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
+       Left   += PenWidth / 2;
+       Right  -= (PenWidth - 1) / 2;
+       Top    += PenWidth / 2;
+       Bottom -= (PenWidth - 1) / 2;
+    }
+
+    if (!PenWidth) PenWidth = 1;
+    PenBrushObj->ptPenWidth.x = PenWidth;  
 
     Left   += dc->ptlDCOrig.x;
     Right  += dc->ptlDCOrig.x;
@@ -125,56 +136,103 @@
     DPRINT1("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
                RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
 
-    if (Left == Right)
-    {
-        DPRINT1("Arc Good Exit\n");
-        PUTPIXEL(Left, Top, PenBrushInst);
-        BITMAPOBJ_UnlockBitmap(BitmapObj);
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
-        PENOBJ_UnlockPen(PenBrushObj);
-        return ret;
-    }
-    RadiusX = (RectBounds.right - RectBounds.left)/2;
-    RadiusY = (RectBounds.bottom - RectBounds.top)/2;
-    CenterX = RectBounds.left + RadiusX;
-    CenterY = RectBounds.top + RadiusY;
-
-    AngleEnd   = atan2(-(YRadialEnd - CenterY), XRadialEnd - CenterX)* (180.0 / M_PI);
-    AngleStart = atan2(-(YRadialStart - CenterY), XRadialStart - CenterX)* (180.0 / M_PI);
+    RadiusX = (RectBounds.right - RectBounds.left) / 2;
+    RadiusY = (RectBounds.bottom - RectBounds.top) / 2;
+    CenterX = (RectBounds.right + RectBounds.left) / 2;
+    CenterY = (RectBounds.bottom + RectBounds.top) / 2;
+    AngleEnd   = atan2((YRadialEnd - CenterY), XRadialEnd - CenterX)*(360.0/(M_PI*2));
+    AngleStart = atan2((YRadialStart - CenterY), XRadialStart - CenterX)*(360.0/(M_PI*2));
 
     SfCx = (Rcos(AngleStart) * RadiusX);
     SfCy = (Rsin(AngleStart) * RadiusY);
-
     EfCx = (Rcos(AngleEnd) * RadiusX);
     EfCy = (Rsin(AngleEnd) * RadiusY);
-    {
-       FLOAT AngS = AngleStart, Factor = 1;
+
+    if ((arctype == GdiTypePie) || (arctype == GdiTypeChord))
+    {
+        ret = IntFillArc( dc,
+             RectBounds.left,
+              RectBounds.top,
+             fabs(RectBounds.right-RectBounds.left), // Width
+             fabs(RectBounds.bottom-RectBounds.top), // Height
+                  AngleStart,
+                    AngleEnd,
+                     arctype);
+    }
+
+    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
+    if (NULL == BitmapObj)
+    {
+        DPRINT1("Arc Fail 2\n");
+        PENOBJ_UnlockPen(PenBrushObj);
+        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        return FALSE;
+    }
+
+    IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
+
+    if (arctype == GdiTypePie)
+    {
+       PUTLINE(CenterX, CenterY, SfCx + CenterX, SfCy + CenterY, PenBrushInst);
+    }
+    {
+       double AngS = AngleStart, AngT = AngleEnd,
+       Factor = fabs(RadiusX) < 25 ? 1.0 : (25/fabs(RadiusX));
        int x,y, ox = 0, oy = 0;
-
-       if (arctype == GdiTypePie)
+       BOOL Start = TRUE;
+
+       if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
        {
-          PUTLINE(SfCx + CenterX, SfCy + CenterY, CenterX, CenterY, PenBrushInst);
+          DPRINT1("Arc CW\n");
+          for (; AngS < AngT; AngS += Factor)
+          {
+              x = (RadiusX * Rcos(AngS));
+              y = (RadiusY * Rsin(AngS));
+
+              DPRINT("Arc CW -> %d, X: %d Y: %d\n",(INT)AngS,x,y);
+              if (Start)
+              {
+                 PUTPIXEL(x + CenterX, y + CenterY, PenBrushInst);
+                 ox = x;
+                 oy = y;
+                 Start = FALSE;
+                 continue;
+              }
+              PUTLINE(ox + CenterX, oy + CenterY, x + CenterX, y + CenterY, PenBrushInst);
+              ox = x;
+              oy = y;      
+          }
        }
-
-       for(; AngS < AngleEnd; AngS += Factor)
+       else
        {
-          x = (Rcos(AngS) * RadiusX);
-          y = (Rsin(AngS) * RadiusY);
-  
-          if (arctype == GdiTypePie)
-             PUTLINE((x + CenterX) - 1, (y + CenterY) - 1, CenterX, CenterY, FillBrushInst);
-
-          PUTPIXEL (x + CenterX, y + CenterY, PenBrushInst);
-          ox = x;
-          oy = y;
+          DPRINT1("Arc CCW\n");
+          for (; AngT < AngS; AngS -= Factor)
+          {
+              x = (RadiusX * Rcos(AngS));
+              y = (RadiusY * Rsin(AngS));
+
+              DPRINT("Arc CCW -> %d, X: %d Y: %d\n",(INT)AngS,x,y);
+              if (Start)
+              {
+                 PUTPIXEL(x + CenterX, y + CenterY, PenBrushInst);
+                 ox = x;
+                 oy = y;
+                 Start = FALSE;
+                 continue;
+              }
+              PUTLINE(ox + CenterX, oy + CenterY, x + CenterX, y + CenterY, PenBrushInst);
+              ox = x;
+              oy = y;
+          }        
        }
-
-       if (arctype == GdiTypePie)
-           PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst);
-
-    }
+    }
+    if (arctype == GdiTypePie)
+       PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst);
+    if (arctype == GdiTypeChord)
+       PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, PenBrushInst);
+
+    PenBrushObj->ptPenWidth.x = PenOrigWidth;
     BITMAPOBJ_UnlockBitmap(BitmapObj);
-    BRUSHOBJ_UnlockBrush(FillBrushObj);
     PENOBJ_UnlockPen(PenBrushObj);
     DPRINT1("IntArc Exit.\n");
     return ret;
@@ -196,9 +254,6 @@
 {
   BOOL Ret;
   RECT rc, rc1;
-  double AngleStart, AngleEnd;
-  LONG RadiusX, RadiusY, CenterX, CenterY, Width, Height;
-  LONG SfCx, SfCy, EfCx = 0, EfCy = 0;
 
   DPRINT1("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
            XStartArc,YStartArc,XEndArc,YEndArc);
@@ -221,22 +276,10 @@
 
   if (arctype == GdiTypeArcTo)
   {
-    Width   = fabs(RightRect - LeftRect);
-    Height  = fabs(BottomRect - TopRect);
-    RadiusX = Width/2;
-    RadiusY = Height/2;
-    CenterX = RightRect > LeftRect ? LeftRect + RadiusX : RightRect + RadiusX;
-    CenterY = BottomRect > TopRect ? TopRect + RadiusY : BottomRect + RadiusY;
-
-    AngleStart = atan2((YStartArc - CenterY)/Height, (XStartArc - CenterX)/Width);
-    AngleEnd   = atan2((YEndArc - CenterY)/Height, (XEndArc - CenterX)/Width);
-
-    EfCx = GDI_ROUND(CenterX+cos(AngleEnd) * RadiusX);
-    EfCy = GDI_ROUND(CenterY+sin(AngleEnd) * RadiusY);
-    SfCx = GDI_ROUND(CenterX+cos(AngleStart) * RadiusX);
-    SfCy = GDI_ROUND(CenterY+sin(AngleStart) * RadiusY);
-
-    IntGdiLineTo(dc, SfCx, SfCy);
+    if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
+       IntGdiLineTo(dc, XEndArc, YEndArc);
+    else
+       IntGdiLineTo(dc, XStartArc, YStartArc);
   }
 
   IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);
@@ -244,6 +287,7 @@
 
 //  IntLPtoDP(dc, (LPPOINT)&rc, 2);
 //  IntLPtoDP(dc, (LPPOINT)&rc1, 2);
+
 
   Ret = IntArc( dc,
            rc.left,
@@ -258,9 +302,11 @@
 
   if (arctype == GdiTypeArcTo)
   {
-     IntGdiMoveToEx(dc, EfCx, EfCy, NULL);
-  }
-
+     if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
+       IntGdiMoveToEx(dc, XStartArc, YStartArc, NULL);
+     else
+       IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);
+  }
   return Ret;
 }
 
@@ -292,9 +338,9 @@
   result = IntGdiArcInternal( GdiTypeArcTo,
                                        pDC,
                                 x-dwRadius,
+                                y-dwRadius,
+                                x+dwRadius,
                                 y+dwRadius,
-                                x+dwRadius,
-                                y-dwRadius,
                                         x1,
                                         y1,
                                         x2,
@@ -304,7 +350,7 @@
 
   if (result)
   {
-     IntGdiMoveToEx(pDC, x2, y2, NULL);
+     IntGdiMoveToEx(pDC, x2, y2, NULL); // Dont forget Path.
   }
   return result;
 }

Added: trunk/reactos/subsystems/win32/win32k/objects/drawing.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/objects/drawing.c?rev=34169&view=auto
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/objects/drawing.c (added)
+++ trunk/reactos/subsystems/win32/win32k/objects/drawing.c [iso-8859-1] Sat Jun 28 20:19:46 2008
@@ -1,0 +1,810 @@
+/*
+App Software Licence
+--------------------
+This package includes software which is copyright (c) L. Patrick.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. You may not sell this software package.
+4. You may include this software in a distribution of other software,
+   and you may charge a nominal fee for the media used.
+5. You may sell derivative programs, providing that such programs
+   simply use this software in a compiled form.
+6. You may sell derivative programs which use a compiled, modified
+   version of this software, provided that you have attempted as
+   best as you can to propagate all modifications made to the source
+   code files of this software package back to the original author(s)
+   of this package.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS AS IS, AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+*/
+/* Copyright (c) L. Patrick
+
+   This file is part of the App cross-platform programming package.
+   You may redistribute it and/or modify it under the terms of the
+   App Software License. See the file LICENSE.TXT for details.
+
+   http://enchantia.com/software/graphapp/
+   http://www.it.usyd.edu.au/~graphapp/
+*/
+/*
+    Modified for ReactOS
+ */
+
+#include <w32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+#define DEGREES_TO_RADIANS(deg) ((deg)*2*M_PI/360)
+
+typedef struct _Rect
+{
+	int x, y;		/* top-left point inside rect */
+	int width, height;	/* width and height of rect */
+} Rect, *PRect;
+
+static
+POINT
+INTERNAL_CALL
+app_new_point(int x, int y)
+{
+	POINT p;	
+	p.x = x;
+	p.y = y;
+	return p;
+}
+#define pt(x,y)       app_new_point((x),(y))
+
+static
+Rect
+INTERNAL_CALL
+rect(int x, int y, int width, int height)
+{
+  Rect r;
+	
+  r.x = x;
+	r.y = y;
+	r.width = width;
+	r.height = height;
+	return r;
+}
+
+
+/*
+ *  app_window_fill_rect:
+ *
+ *  Fill a rectangle with colour, in a window.
+ *
+ *  This function implements client-side clipping, so that
+ *  we never rely on the GDI system to do clipping, except if
+ *  the destination is a window which is partially obscured.
+ *  In that situation we must rely on the GDI system because there
+ *  is no way for the program to know which portions of the
+ *  window are currently obscured.
+ */
+static
+int
+INTERNAL_CALL
+app_fill_rect(DC *dc, Rect r, PGDIBRUSHOBJ BrushObj)
+{
+  RECTL DestRect;
+  BITMAPOBJ *BitmapObj;
+  GDIBRUSHINST BrushInst;
+  POINTL BrushOrigin;
+  BOOL Ret = TRUE;
+
+  ASSERT(BrushObj);
+
+  BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
+  if (BitmapObj == NULL)
+  {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return 0;
+  }
+
+  if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL))
+  {
+
+     /* fix negative spaces */
+     if (r.width < 0)
+     {
+	r.x += r.width;
+	r.width = 0 - r.width;
+     }
+     if (r.height < 0)
+     {
+	r.y += r.height;
+	r.height = 0 - r.height;
+     }
+
+     DestRect.left = r.x;
+     DestRect.right = r.x + r.width;
+
+     DestRect.top = r.y;
+     DestRect.bottom = r.y + r.height;
+
+     BrushOrigin.x = BrushObj->ptOrigin.x;
+     BrushOrigin.y = BrushObj->ptOrigin.y;
+
+     IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);
+
+     Ret = IntEngBitBlt(
+         &BitmapObj->SurfObj,
+         NULL,
+         NULL,
+         dc->CombinedClip,
+         NULL,
+         &DestRect,
+         NULL,
+         NULL,
+         &BrushInst.BrushObject, // use pDC->eboFill
+         &BrushOrigin,
+         ROP3_TO_ROP4(PATCOPY));
+  }
+
+  BITMAPOBJ_UnlockBitmap(BitmapObj);
+  return (int)Ret;
+}
+
+/*
+ *  Draw an arc of an ellipse from start_angle anti-clockwise to
+ *  end_angle. If the angles coincide, draw nothing; if they
+ *  differ by 360 degrees or more, draw a full ellipse.
+ *  The shape is drawn with the current line thickness,
+ *  completely within the bounding rectangle. The shape is also
+ *  axis-aligned, so that the ellipse would be horizontally and
+ *  vertically symmetric is it was complete.
+ *
+ *  The draw_arc algorithm is based on draw_ellipse, but unlike
+ *  that algorithm is not symmetric in the general case, since
+ *  an angular portion is clipped from the shape. 
+ *  This clipping is performed by keeping track of two hypothetical
+ *  lines joining the centre point to the enclosing rectangle,
+ *  at the angles start_angle and end_angle, using a line-intersection
+ *  algorithm. Essentially the algorithm just fills the spaces
+ *  which are within the arc and also between the angles, going
+ *  in an anti-clockwise direction from start_angle to end_angle.
+ *  In the top half of the ellipse, this amounts to drawing
+ *  to the left of the start_angle line and to the right of
+ *  the end_angle line, while in the bottom half of the ellipse,
+ *  it involves drawing to the right of the start_angle and to
+ *  the left of the end_angle.
+ */
+
+/*
+ *  Fill a rectangle within an arc, given the centre point p0,
+ *  and the two end points of the lines corresponding to the
+ *  start_angle and the end_angle. This function takes care of
+ *  the logic needed to swap the fill direction below
+ *  the central point, and also performs the calculations
+ *  needed to intersect the current Y value with each line.
+ */
+static
+int
+FASTCALL
+app_fill_arc_rect(DC *g,
+        Rect r,   // top, left, width, height
+	POINT p0, // Center
+	POINT p1, // Start
+	POINT p2, // End
+	int start_angle,
+	int end_angle,
+	PGDIBRUSHOBJ BrushObj)
+{
+	int x1, x2;
+	int start_above, end_above;
+	long rise1, run1, rise2, run2;
+
+	rise1 = p1.y - p0.y;
+	run1  = p1.x - p0.x;
+	rise2 = p2.y - p0.y;
+	run2  = p2.x - p0.x;
+
+	if (r.y <= p0.y) // 
+        {
+		/* in top half of arc ellipse */
+
+		if (p1.y <= r.y)
+		{
+			/* start_line is in the top half and is */
+			/* intersected by the current Y scan line */
+			if (rise1 == 0)
+				x1 = p1.x;
+			else
+				x1 = p0.x + (r.y-p0.y)*run1/rise1;
+			start_above = 1;
+		}
+		else if ((start_angle >= 0) && (start_angle <= 180))
+		{
+			/* start_line is above middle */
+			x1 = p1.x;
+			start_above = 1;
+		}
+		else
+		{
+			/* start_line is below middle */
+			x1 = r.x + r.width;
+			start_above = 0;
+		}
+		if (x1 < r.x)
+			x1 = r.x;
+		if (x1 > r.x+r.width)
+			x1 = r.x+r.width;
+
+		if (p2.y <= r.y)
+		{
+			/* end_line is in the top half and is */
+			/* intersected by the current Y scan line */
+			if (rise2 == 0)
+				x2 = p2.x;
+			else
+				x2 = p0.x + (r.y-p0.y)*run2/rise2;
+			end_above = 1;
+		}
+		else if ((end_angle >= 0) && (end_angle <= 180))
+		{
+			/* end_line is above middle */
+			x2 = p2.x;
+			end_above = 1;
+		}
+		else
+		{
+			/* end_line is below middle */
+			x2 = r.x;
+			end_above = 0;
+		}
+
+		if (x2 < r.x) x2 = r.x;
+
+		if (x2 > r.x+r.width) x2 = r.x+r.width;
+
+		if (start_above && end_above)
+		{
+			if (start_angle > end_angle)
+			{
+				/* fill outsides of wedge */
+				if (! app_fill_rect(g, rect(r.x, r.y,
+					x1-r.x, r.height), BrushObj))
+					return 0;
+				return app_fill_rect(g, rect(x2, r.y,
+					r.x+r.width-x2, r.height), BrushObj);
+			}
+			else
+			{
+				/* fill inside of wedge */
+				r.width = x1-x2;
+				r.x = x2;
+				return app_fill_rect(g, r, BrushObj);
+			}
+		}
+		else if (start_above)
+		{
+			/* fill to the left of the start_line */
+			r.width = x1-r.x;
+			return app_fill_rect(g, r, BrushObj);
+		}
+		else if (end_above)
+		{
+			/* fill right of end_line */
+			r.width = r.x+r.width-x2;
+			r.x = x2;
+			return app_fill_rect(g, r, BrushObj);
+		}
+		else
+		{
+			if (start_angle > end_angle)
+				return app_fill_rect(g,r, BrushObj);
+			else
+				return 1;
+		}
+	}
+	else
+	{
+		/* in lower half of arc ellipse */
+
+		if (p1.y >= r.y)
+		{
+			/* start_line is in the lower half and is */
+			/* intersected by the current Y scan line */
+			if (rise1 == 0)
+				x1 = p1.x;
+			else
+				x1 = p0.x + (r.y-p0.y)*run1/rise1;
+			start_above = 0;
+		}
+		else if ((start_angle >= 180) && (start_angle <= 360))
+		{
+			/* start_line is below middle */
+			x1 = p1.x;
+			start_above = 0;
+		}
+		else
+		{
+			/* start_line is above middle */
+			x1 = r.x;
+			start_above = 1;
+		}
+		if (x1 < r.x)
+			x1 = r.x;
+		if (x1 > r.x+r.width)
+			x1 = r.x+r.width;
+
+		if (p2.y >= r.y)
+		{
+			/* end_line is in the lower half and is */
+			/* intersected by the current Y scan line */
+			if (rise2 == 0)
+				x2 = p2.x;
+			else
+				x2 = p0.x + (r.y-p0.y)*run2/rise2;
+			end_above = 0;
+		}
+		else if ((end_angle >= 180) && (end_angle <= 360))
+		{
+			/* end_line is below middle */
+			x2 = p2.x;
+			end_above = 0;
+		}
+		else
+		{
+			/* end_line is above middle */
+			x2 = r.x + r.width;
+			end_above = 1;
+		}
+		if (x2 < r.x)
+			x2 = r.x;
+		if (x2 > r.x+r.width)
+			x2 = r.x+r.width;
+
+		if (start_above && end_above)
+		{
+			if (start_angle > end_angle)
+				return app_fill_rect(g,r, BrushObj);
+			else
+				return 1;
+		}
+		else if (start_above)
+		{
+			/* fill to the left of end_line */
+			r.width = x2-r.x;
+			return app_fill_rect(g,r, BrushObj);
+		}
+		else if (end_above)
+		{
+			/* fill right of start_line */
+			r.width = r.x+r.width-x1;
+			r.x = x1;
+			return app_fill_rect(g,r, BrushObj);
+		}
+		else
+		{
+			if (start_angle > end_angle)
+			{
+				/* fill outsides of wedge */
+				if (! app_fill_rect(g, rect(r.x, r.y,
+					x2-r.x, r.height), BrushObj))
+					return 0;
+				return app_fill_rect(g, rect(x1, r.y,
+					r.x+r.width-x1, r.height), BrushObj);
+			}
+			else
+			{
+				/* fill inside of wedge */
+				r.width = x2-x1;
+				r.x = x1;
+				return app_fill_rect(g, r, BrushObj);
+			}
+		}
+	}
+}
+
+/*
+ *  To fill an axis-aligned ellipse, we use a scan-line algorithm.
+ *  We walk downwards from the top Y co-ordinate, calculating
+ *  the width of the ellipse using incremental integer arithmetic.
+ *  To save calculation, we observe that the top and bottom halves
+ *  of the ellipsoid are mirror-images, therefore we can draw the
+ *  top and bottom halves by reflection. As a result, this algorithm
+ *  draws rectangles inwards from the top and bottom edges of the
+ *  bounding rectangle.
+ *
+ *  To save rendering time, draw as few rectangles as possible.
+ *  Other ellipse-drawing algorithms assume we want to draw each
+ *  line, using a draw_pixel operation, or a draw_horizontal_line
+ *  operation. This approach is slower than it needs to be in
+ *  circumstances where a fill_rect operation is more efficient
+ *  (such as in X-Windows, where there is a communication overhead
+ *  to the X-Server). For this reason, the algorithm accumulates
+ *  rectangles on adjacent lines which have the same width into a
+ *  single larger rectangle.
+ *
+ *  This algorithm forms the basis of the later, more complex,
+ *  draw_ellipse algorithm, which renders the rectangular spaces
+ *  between an outer and inner ellipse, and also the draw_arc and
+ *  fill_arc operations which additionally clip drawing between
+ *  a start_angle and an end_angle.
+ *  
+ */
+static
+int
+FASTCALL
+app_fill_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj)
+{
+	/* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
+
+	int a = r.width / 2;
+	int b = r.height / 2;
+	int x = 0;
+	int y = b;
+	long a2 = a*a;
+	long b2 = b*b;
+	long xcrit = (3 * a2 / 4) + 1;
+	long ycrit = (3 * b2 / 4) + 1;
+	long t = b2 + a2 - 2*a2*b;	/* t = e(x+1,y-1) */
+	long dxt = b2*(3+x+x);
+	long dyt = a2*(3-y-y);
+	int d2xt = b2+b2;
+	int d2yt = a2+a2;
+	Rect r1, r2;
+	int result = 1;
+
+//	START_DEBUG();
+
+	if ((r.width <= 2) || (r.height <= 2))
+		return app_fill_rect(g, r, BrushObj);
+
+	r1.x = r.x + a;
+	r1.y = r.y;
+	r1.width = r.width & 1; /* i.e. if width is odd */
+	r1.height = 1;
+
+	r2 = r1;
+	r2.y = r.y + r.height - 1;
+
+	while (y > 0)
+	{
+		if (t + a2*y < xcrit) { /* e(x+1,y-1/2) <= 0 */
+			/* move outwards to encounter edge */
+			x += 1;
+			t += dxt;
+			dxt += d2xt;
+
+			/* move outwards */
+			r1.x -= 1; r1.width += 2;
+			r2.x -= 1; r2.width += 2;
+		}
+		else if (t - b2*x >= ycrit) { /* e(x+1/2,y-1) > 0 */
+			/* drop down one line */
+			y -= 1;
+			t += dyt;
+			dyt += d2yt;
+
+			/* enlarge rectangles */
+			r1.height += 1;
+			r2.height += 1; r2.y -= 1;
+		}
+		else {
+			/* drop diagonally down and out */
+			x += 1;
+			y -= 1;
+			t += dxt + dyt;
+			dxt += d2xt;
+			dyt += d2yt;
+
+			if ((r1.width > 0) && (r1.height > 0))
+			{
+				/* draw rectangles first */
+
+				if (r1.y+r1.height < r2.y) {
+					/* distinct rectangles */
+					result &= app_fill_rect(g, r1, BrushObj);
+					result &= app_fill_rect(g, r2, BrushObj);
+				}
+
+				/* move down */
+				r1.y += r1.height; r1.height = 1;
+				r2.y -= 1;         r2.height = 1;
+			}
+			else {
+				/* skipped pixels on initial diagonal */
+
+				/* enlarge, rather than moving down */
+				r1.height += 1;
+				r2.height += 1; r2.y -= 1;
+			}
+
+			/* move outwards */
+			r1.x -= 1; r1.width += 2;
+			r2.x -= 1; r2.width += 2;
+		}
+	}
+	if (r1.y < r2.y) {
+		/* overlap */
+		r1.x = r.x;
+		r1.width = r.width;
+		r1.height = r2.y+r2.height-r1.y;
+		result &= app_fill_rect(g, r1, BrushObj);
+	}
+	else if (x <= a) {
+		/* crossover, draw final line */
+		r1.x = r.x;
+		r1.width = r.width;
+		r1.height = r1.y+r1.height-r2.y;
+		r1.y = r2.y;
+		result &= app_fill_rect(g, r1, BrushObj);
+	}
+	return result;
+}
+
+static
+FASTCALL
+POINT app_boundary_point(Rect r, int angle)
+{
+	int cx, cy;
+	double tangent;
+
+	cx = r.width;
+	cx /= 2;
+	cx += r.x;
+
+	cy = r.height;
+	cy /= 2;
+	cy += r.y;
+
+	if (angle == 0)
+		return pt(r.x+r.width, cy);
+	else if (angle == 45)
+		return pt(r.x+r.width, r.y);
+	else if (angle == 90)
+		return pt(cx, r.y);
+	else if (angle == 135)
+		return pt(r.x, r.y);
+	else if (angle == 180)
+		return pt(r.x, cy);
+	else if (angle == 225)
+		return pt(r.x, r.y+r.height);
+	else if (angle == 270)
+		return pt(cx, r.y+r.height);
+	else if (angle == 315)
+		return pt(r.x+r.width, r.y+r.height);
+
+	tangent = tan(DEGREES_TO_RADIANS(angle));
+
+	if ((angle > 45) && (angle < 135))
+		return pt((int)(cx+r.height/tangent/2), r.y);
+	else if ((angle > 225) && (angle < 315))
+		return pt((int)(cx-r.height/tangent/2), r.y+r.height);
+	else if ((angle > 135) && (angle < 225))
+		return pt(r.x, (int)(cy+r.width*tangent/2));
+	else
+		return pt(r.x+r.width, (int)(cy-r.width*tangent/2));
+}
+
+int
+FASTCALL
+app_fill_arc(DC *g, Rect r, int start_angle, int end_angle, PGDIBRUSHOBJ BrushObj, BOOL Chord)
+{
+	/* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
+
+	int a = r.width / 2;
+	int b = r.height / 2;
+	int x = 0;
+	int y = b;
+	long a2 = a*a;
+	long b2 = b*b;
+	long xcrit = (3 * a2 / 4) + 1;
+	long ycrit = (3 * b2 / 4) + 1;
+	long t = b2 + a2 - 2*a2*b;	/* t = e(x+1,y-1) */
+	long dxt = b2*(3+x+x);
+	long dyt = a2*(3-y-y);
+	int d2xt = b2+b2;
+	int d2yt = a2+a2;
+	Rect r1, r2;
+	int movedown, moveout;
+	int result = 1;
+
+	/* line descriptions */
+	POINT p0, p1, p2;
+
+//	START_DEBUG();
+
+	/* if angles differ by 360 degrees or more, close the shape */
+	if ((start_angle + 360 <= end_angle) ||
+	    (start_angle - 360 >= end_angle))
+	{
+		return app_fill_ellipse(g, r, BrushObj);
+	}
+
+	/* make start_angle >= 0 and <= 360 */
+	while (start_angle < 0)
+		start_angle += 360;
+	start_angle %= 360;
+
+	/* make end_angle >= 0 and <= 360 */
+	while (end_angle < 0)
+		end_angle += 360;
+	end_angle %= 360;
+
+	/* draw nothing if the angles are equal */
+	if (start_angle == end_angle)
+		return 1;
+
+	/* find arc wedge line end points */
+	p1 = app_boundary_point(r, start_angle);
+	p2 = app_boundary_point(r, end_angle);
+	p0 = pt(r.x + r.width/2, r.y + r.height/2);
+	if (Chord)
+	{
+	 int zx, zy;
+	 zx = (p0.x-p1.x)/2;
+	 zy = (p2.y-p1.y)/2;
+	 p0 = pt(p1.x+zx,p0.y+zy);
+	}
+	/* initialise rectangles to be drawn */
+	r1.x = r.x + a;
+	r1.y = r.y;
+	r1.width = r.width & 1; /* i.e. if width is odd */
+	r1.height = 1;
+
+	r2 = r1;
+	r2.y = r.y + r.height - 1;
+
+	while (y > 0)
+	{
+		moveout = movedown = 0;
+
+		if (t + a2*y < xcrit) { /* e(x+1,y-1/2) <= 0 */
+			/* move outwards to encounter edge */
+			x += 1;
+			t += dxt;
+			dxt += d2xt;
+
+			moveout = 1;
+		}
+		else if (t - b2*x >= ycrit) { /* e(x+1/2,y-1) > 0 */
+			/* drop down one line */
+			y -= 1;
+			t += dyt;
+			dyt += d2yt;
+
+			movedown = 1;
+		}
+		else {
+			/* drop diagonally down and out */
+			x += 1;
+			y -= 1;
+			t += dxt + dyt;
+			dxt += d2xt;
+			dyt += d2yt;
+
+			moveout = 1;
+			movedown = 1;
+		}
+
+		if (movedown) {
+			if (r1.width == 0) {
+				r1.x -= 1; r1.width += 2;
+				r2.x -= 1; r2.width += 2;
+				moveout = 0;
+			}
+
+			if (r1.x < r.x)
+				r1.x = r2.x = r.x;
+			if (r1.width > r.width)
+				r1.width = r2.width = r.width;
+			if (r1.y == r2.y-1) {
+				r1.x = r2.x = r.x;
+				r1.width = r2.width = r.width;
+			}
+
+			if ((r1.width > 0) && (r1.y+r1.height < r2.y)) {
+				/* distinct rectangles */
+				result &= app_fill_arc_rect(g, r1,
+						p0, p1, p2,
+						start_angle, end_angle, BrushObj);
+				result &= app_fill_arc_rect(g, r2,
+						p0, p1, p2,
+						start_angle, end_angle, BrushObj);
+			}
+
+			/* move down */
+			r1.y += 1;
+			r2.y -= 1;
+		}
+
+		if (moveout) {
+			/* move outwards */
+			r1.x -= 1; r1.width += 2;
+			r2.x -= 1; r2.width += 2;
+		}
+	}
+	if (r1.y < r2.y) {
+		/* overlap */
+		r1.x = r.x;
+		r1.width = r.width;
+		r1.height = r2.y+r2.height-r1.y;
+		while (r1.height > 0) {
+			result &= app_fill_arc_rect(g,
+				rect(r1.x, r1.y, r1.width, 1),
+				p0, p1, p2, start_angle, end_angle, BrushObj);
+			r1.y += 1;
+			r1.height -= 1;
+		}
+	}
+	else if (x <= a) {
+		/* crossover, draw final line */
+		r1.x = r.x;
+		r1.width = r.width;
+		r1.height = r1.y+r1.height-r2.y;
+		r1.y = r2.y;
+		while (r1.height > 0) {
+			result &= app_fill_arc_rect(g, 
+				rect(r1.x, r1.y, r1.width, 1),
+				p0, p1, p2, start_angle, end_angle, BrushObj);
+			r1.y += 1;
+			r1.height -= 1;
+		}
+	}
+	return result;
+}
+
+/* ReactOS Interface *********************************************************/
+
+BOOL
+FASTCALL
+IntFillArc( PDC dc,
+            INT XLeft,
+            INT YLeft,
+            INT Width,
+            INT Height,
+            double StartArc,
+            double EndArc,
+            ARCTYPE arctype)
+{
+  PDC_ATTR Dc_Attr;
+  PGDIBRUSHOBJ FillBrushObj;
+  int Start = ceill(StartArc);
+  int End   = ceill(EndArc);
+  Rect r;
+  BOOL Chord = (arctype == GdiTypeChord);
+
+  Dc_Attr = dc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+  FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+  if (NULL == FillBrushObj)   
+  {
+      DPRINT1("FillArc Fail\n");
+      SetLastWin32Error(ERROR_INTERNAL_ERROR);
+      return FALSE;
+  }
+  r.x = XLeft;
+  r.y = YLeft;
+  r.width = Width;
+  r.height = Height;
+  app_fill_arc(dc, r, Start-90, End-90, FillBrushObj, Chord);
+
+  BRUSHOBJ_UnlockBrush(FillBrushObj);    
+  return TRUE;
+}
+

Propchange: trunk/reactos/subsystems/win32/win32k/objects/drawing.c
------------------------------------------------------------------------------
    eol-style = native

Propchange: trunk/reactos/subsystems/win32/win32k/objects/drawing.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/reactos/subsystems/win32/win32k/objects/drawing.c
------------------------------------------------------------------------------
    svn:executable = *

Modified: trunk/reactos/subsystems/win32/win32k/win32k.rbuild
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/win32k.rbuild?rev=34169&r1=34168&r2=34169&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/win32k.rbuild [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/win32k.rbuild [iso-8859-1] Sat Jun 28 20:19:46 2008
@@ -155,6 +155,7 @@
 		<file>dc.c</file>
 		<file>dcutil.c</file>
 		<file>dibobj.c</file>
+		<file>drawing.c</file>
 		<file>fillshap.c</file>
 		<file>gdibatch.c</file>
 		<file>gdiobj.c</file>



More information about the Ros-diffs mailing list