- Rewritten NtGdiEllipse with improved and optimized algorithm. Now it works also for non-circles, but unfortuently it still looks a bit choppy.

svn path=/trunk/; revision=8030
This commit is contained in:
Filip Navara 2004-02-04 22:10:00 +00:00
parent 75a008acf6
commit f599776b65

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: fillshap.c,v 1.38 2003/12/13 13:05:30 weiden Exp $ */ /* $Id: fillshap.c,v 1.39 2004/02/04 22:10:00 navaraf Exp $ */
#undef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
@ -205,164 +205,192 @@ NtGdiChord(HDC hDC,
UNIMPLEMENTED; UNIMPLEMENTED;
} }
BOOL /*
STDCALL * NtGdiEllipse
NtGdiEllipse(HDC hDC, *
int Left, * Author
int Top, * Filip Navara
int Right, *
int Bottom) * Remarks
{ * This function uses optimized Bresenham's ellipse algorithm. It draws
PDC dc; * four lines of the ellipse in one pass.
int X, X18, X27, X36, X45; *
int Y, Y14, Y23, Y58, Y67; * Todo
int d, Radius; * Make it look like a Windows ellipse.
RECTL RectBounds; */
PSURFOBJ SurfObj;
BRUSHOBJ PenBrushObj;
PBRUSHOBJ FillBrushObj;
BOOL Even;
BOOL ret = TRUE;
if (Right <= Left || Bottom <= Top) BOOL STDCALL
NtGdiEllipse(
HDC hDC,
int nLeftRect,
int nTopRect,
int nRightRect,
int nBottomRect)
{
int ix, iy;
int A, B, C, D;
int da, db;
int NewA, NewB, NewC, NewD;
int nx, ny;
int CenterX, CenterY;
int RadiusX, RadiusY;
int Temp;
BRUSHOBJ PenBrush;
PBRUSHOBJ FillBrush;
PSURFOBJ SurfObj;
RECTL RectBounds;
PDC dc;
BOOL ret = TRUE, Cond1, Cond2;
/*
* Check the parameters.
*/
if (nRightRect <= nLeftRect || nBottomRect <= nTopRect)
{ {
SetLastWin32Error(ERROR_INVALID_PARAMETER); SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
if (Right - Left != Bottom - Top) /*
{ * Get pointers to all necessary GDI objects.
UNIMPLEMENTED; */
}
dc = DC_LockDc ( hDC ); dc = DC_LockDc(hDC);
if (NULL == dc) if (dc == NULL)
{ {
SetLastWin32Error(ERROR_INVALID_HANDLE); SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE; return FALSE;
} }
FillBrushObj = BRUSHOBJ_LockBrush(dc->w.hBrush); FillBrush = BRUSHOBJ_LockBrush(dc->w.hBrush);
if (NULL == FillBrushObj) if (NULL == FillBrush)
{ {
DC_UnlockDc(hDC); DC_UnlockDc(hDC);
SetLastWin32Error(ERROR_INTERNAL_ERROR); SetLastWin32Error(ERROR_INTERNAL_ERROR);
return FALSE; return FALSE;
} }
Even = (0 == (Right - Left) % 2); SurfObj = (PSURFOBJ)AccessUserObject((ULONG)dc->Surface);
HPenToBrushObj(&PenBrush, dc->w.hPen);
Left += dc->w.DCOrgX; nLeftRect += dc->w.DCOrgX;
Right += dc->w.DCOrgX - 1; nRightRect += dc->w.DCOrgX;
Top += dc->w.DCOrgY; nTopRect += dc->w.DCOrgY;
Bottom += dc->w.DCOrgY - 1; nBottomRect += dc->w.DCOrgY;
RectBounds.left = Left; RadiusX = max((nRightRect - nLeftRect) >> 1, 1);
RectBounds.right = Right; RadiusY = max((nBottomRect - nTopRect) >> 1, 1);
RectBounds.top = Top; CenterX = nLeftRect + RadiusX;
RectBounds.bottom = Bottom; CenterY = nTopRect + RadiusY;
SurfObj = (PSURFOBJ) AccessUserObject((ULONG)dc->Surface); RectBounds.left = nLeftRect;
HPenToBrushObj(&PenBrushObj, dc->w.hPen); RectBounds.right = nRightRect;
RectBounds.top = nTopRect;
RectBounds.bottom = nBottomRect;
if (Left == Right) if (RadiusX > RadiusY)
{ {
PUTPIXEL(Left, Top, &PenBrushObj); nx = RadiusX;
BRUSHOBJ_UnlockBrush(dc->w.hBrush); ny = RadiusY;
DC_UnlockDc(hDC);
return ret;
}
Radius = (Right - Left) / 2;
if (Even)
{
X = 0;
Y = Radius;
d = 2 - Radius;
X18 = Right;
X27 = (Left + Right) / 2 + 1;
X36 = (Left + Right) / 2;
X45 = Left;
Y14 = Top + Radius;
Y23 = Top;
Y58 = Top + Radius + 1;
Y67 = Top + (Right - Left);
PUTLINE(X45 + 1, Y14, X18, Y14, FillBrushObj);
PUTLINE(X45 + 1, Y58, X18, Y58, FillBrushObj);
PUTPIXEL(X27, Y23, &PenBrushObj);
PUTPIXEL(X36, Y23, &PenBrushObj);
PUTPIXEL(X18, Y14, &PenBrushObj);
PUTPIXEL(X45, Y14, &PenBrushObj);
PUTPIXEL(X18, Y58, &PenBrushObj);
PUTPIXEL(X45, Y58, &PenBrushObj);
PUTPIXEL(X27, Y67, &PenBrushObj);
PUTPIXEL(X36, Y67, &PenBrushObj);
} }
else else
{ {
X = 0; nx = RadiusY;
Y = Radius; ny = RadiusX;
d = 1 - Radius;
X18 = Right;
X27 = (Left + Right) / 2;
X36 = (Left + Right) / 2;
X45 = Left;
Y14 = Top + Radius;
Y23 = Top;
Y58 = Top + Radius;
Y67 = Top + (Right - Left);
PUTLINE(X45 + 1, Y14, X18, Y58, FillBrushObj);
PUTPIXEL(X27, Y23, &PenBrushObj);
PUTPIXEL(X45, Y14, &PenBrushObj);
PUTPIXEL(X18, Y58, &PenBrushObj);
PUTPIXEL(X27, Y67, &PenBrushObj);
} }
while (X < Y) da = -1;
{ db = 0xFFFF;
if (d < 0) ix = 0;
{ iy = nx * 64;
d += 2 * X + (Even ? 4 : 3); NewA = 0;
NewB = (iy + 32) >> 6;
NewC = 0;
NewD = (NewB * ny) / nx;
X27++; do {
X36--; A = NewA;
Y14--; B = NewB;
Y58++; C = NewC;
D = NewD;
ix += iy / nx;
iy -= ix / nx;
NewA = (ix + 32) >> 6;
NewB = (iy + 32) >> 6;
NewC = (NewA * ny) / nx;
NewD = (NewB * ny) / nx;
if (RadiusX > RadiusY)
{
Temp = A; A = C; C = Temp;
Temp = B; B = D; D = Temp;
Cond1 = ((C != NewA) || (B != NewD)) && (NewC <= NewD);
Cond2 = ((D != NewB) || (A != NewC)) && (NewC <= B);
} }
else else
{ {
d += 2 * (X - Y) + 5; Cond1 = ((C != NewC) || (B != NewB)) && (NewA <= NewB);
Y--; Cond2 = ((D != NewD) || (A != NewA)) && (NewA <= B);
Y23++;
Y67--;
X18--;
X45++;
X27++;
X36--;
Y14--;
Y58++;
PUTLINE(X36 + 1, Y23, X27, Y23, FillBrushObj);
PUTLINE(X36 + 1, Y67, X27, Y67, FillBrushObj);
} }
X++;
if (Y23 < Y14) /*
* Draw the lines going from inner to outer (+ mirrored).
*/
if ((A > da) && (A < db))
{ {
PUTLINE(X45 + 1, Y14, X18, Y14, FillBrushObj); PUTLINE(CenterX - D, CenterY + A, CenterX + D, CenterY + A, FillBrush);
PUTLINE(X45 + 1, Y58, X18, Y58, FillBrushObj); if (A)
{
PUTLINE(CenterX - D, CenterY - A, CenterX + D, CenterY - A, FillBrush);
} }
PUTPIXEL(X27, Y23, &PenBrushObj); da = A;
PUTPIXEL(X36, Y23, &PenBrushObj);
PUTPIXEL(X18, Y14, &PenBrushObj);
PUTPIXEL(X45, Y14, &PenBrushObj);
PUTPIXEL(X18, Y58, &PenBrushObj);
PUTPIXEL(X45, Y58, &PenBrushObj);
PUTPIXEL(X27, Y67, &PenBrushObj);
PUTPIXEL(X36, Y67, &PenBrushObj);
} }
/*
* Draw the lines going from outer to inner (+ mirrored).
*/
if ((B < db) && (B > da))
{
PUTLINE(CenterX - C, CenterY + B, CenterX + C, CenterY + B, FillBrush);
PUTLINE(CenterX - C, CenterY - B, CenterX + C, CenterY - B, FillBrush);
db = B;
}
/*
* Draw the pixels on the margin.
*/
if (Cond1)
{
PUTPIXEL(CenterX + C, CenterY + B, &PenBrush);
if (C)
PUTPIXEL(CenterX - C, CenterY + B, &PenBrush);
if (B)
{
PUTPIXEL(CenterX + C, CenterY - B, &PenBrush);
if (C)
PUTPIXEL(CenterX - C, CenterY - B, &PenBrush);
}
}
if (Cond2)
{
PUTPIXEL(CenterX + D, CenterY + A, &PenBrush);
if (D)
PUTPIXEL(CenterX - D, CenterY + A, &PenBrush);
if (A)
{
PUTPIXEL(CenterX + D, CenterY - A, &PenBrush);
if (D)
PUTPIXEL(CenterX - D, CenterY - A, &PenBrush);
}
}
} while (B > A);
BRUSHOBJ_UnlockBrush(dc->w.hBrush); BRUSHOBJ_UnlockBrush(dc->w.hBrush);
DC_UnlockDc(hDC); DC_UnlockDc(hDC);