mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 15:16:36 +00:00
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. svn path=/trunk/; revision=34169
This commit is contained in:
parent
87f7930820
commit
4d7d62eded
3 changed files with 952 additions and 95 deletions
|
@ -25,6 +25,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
|
||||
FASTCALL
|
||||
|
@ -41,10 +43,11 @@ IntArc( DC *dc,
|
|||
{
|
||||
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 @@ IntArc( DC *dc,
|
|||
0|___________________|
|
||||
0 bottom +
|
||||
*/
|
||||
if (Right <= Left || Top <= Bottom)
|
||||
if (Right < Left)
|
||||
{
|
||||
DPRINT1("Arc Fail 1\n");
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
INT tmp = Right; Right = Left; Left = tmp;
|
||||
}
|
||||
/*
|
||||
if (Right - Left != Bottom - Top)
|
||||
if (Bottom < Top)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
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");
|
||||
SetLastWin32Error(ERROR_INTERNAL_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
|
||||
if (NULL == PenBrushObj)
|
||||
{
|
||||
DPRINT1("Arc Fail 3\n");
|
||||
BRUSHOBJ_UnlockBrush(FillBrushObj);
|
||||
DPRINT1("Arc Fail 1\n");
|
||||
SetLastWin32Error(ERROR_INTERNAL_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
|
||||
if (NULL == BitmapObj)
|
||||
PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x;
|
||||
if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0;
|
||||
|
||||
if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME)
|
||||
{
|
||||
DPRINT1("Arc Fail 4\n");
|
||||
BRUSHOBJ_UnlockBrush(FillBrushObj);
|
||||
PENOBJ_UnlockPen(PenBrushObj);
|
||||
SetLastWin32Error(ERROR_INTERNAL_ERROR);
|
||||
return FALSE;
|
||||
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;
|
||||
}
|
||||
|
||||
IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
|
||||
IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
|
||||
if (!PenWidth) PenWidth = 1;
|
||||
PenBrushObj->ptPenWidth.x = PenWidth;
|
||||
|
||||
Left += dc->ptlDCOrig.x;
|
||||
Right += dc->ptlDCOrig.x;
|
||||
|
@ -125,56 +136,103 @@ IntArc( DC *dc,
|
|||
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);
|
||||
|
||||
if ((arctype == GdiTypePie) || (arctype == GdiTypeChord))
|
||||
{
|
||||
FLOAT AngS = AngleStart, Factor = 1;
|
||||
int x,y, ox = 0, oy = 0;
|
||||
|
||||
if (arctype == GdiTypePie)
|
||||
{
|
||||
PUTLINE(SfCx + CenterX, SfCy + CenterY, CenterX, CenterY, PenBrushInst);
|
||||
}
|
||||
|
||||
for(; AngS < AngleEnd; AngS += Factor)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (arctype == GdiTypePie)
|
||||
PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst);
|
||||
|
||||
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;
|
||||
BOOL Start = TRUE;
|
||||
|
||||
if (dc->DcLevel.flPath & DCPATH_CLOCKWISE)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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 == 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 @@ IntGdiArcInternal(
|
|||
{
|
||||
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 @@ IntGdiArcInternal(
|
|||
|
||||
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);
|
||||
|
@ -245,6 +288,7 @@ IntGdiArcInternal(
|
|||
// IntLPtoDP(dc, (LPPOINT)&rc, 2);
|
||||
// IntLPtoDP(dc, (LPPOINT)&rc1, 2);
|
||||
|
||||
|
||||
Ret = IntArc( dc,
|
||||
rc.left,
|
||||
rc.top,
|
||||
|
@ -258,9 +302,11 @@ IntGdiArcInternal(
|
|||
|
||||
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 @@ IntGdiAngleArc( PDC pDC,
|
|||
result = IntGdiArcInternal( GdiTypeArcTo,
|
||||
pDC,
|
||||
x-dwRadius,
|
||||
y+dwRadius,
|
||||
x+dwRadius,
|
||||
y-dwRadius,
|
||||
x+dwRadius,
|
||||
y+dwRadius,
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
|
@ -304,7 +350,7 @@ IntGdiAngleArc( PDC pDC,
|
|||
|
||||
if (result)
|
||||
{
|
||||
IntGdiMoveToEx(pDC, x2, y2, NULL);
|
||||
IntGdiMoveToEx(pDC, x2, y2, NULL); // Dont forget Path.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
810
reactos/subsystems/win32/win32k/objects/drawing.c
Executable file
810
reactos/subsystems/win32/win32k/objects/drawing.c
Executable file
|
@ -0,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;
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue