📄 fillshap.c
字号:
/*
* ReactOS W32 Subsystem
* 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.
*/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
/*
* a couple macros to fill a single pixel or a line
*/
#define PUTPIXEL(x,y,BrushInst) \
ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
dc->CombinedClip, \
&BrushInst.BrushObject, \
x, y, (x)+1, y, \
&RectBounds, \
ROP2_TO_MIX(dc->Dc_Attr.jROP2));
#define PUTLINE(x1,y1,x2,y2,BrushInst) \
ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
dc->CombinedClip, \
&BrushInst.BrushObject, \
x1, y1, x2, y2, \
&RectBounds, \
ROP2_TO_MIX(dc->Dc_Attr.jROP2));
BOOL FASTCALL
IntGdiPolygon(PDC dc,
PPOINT UnsafePoints,
int Count)
{
BITMAPOBJ *BitmapObj;
PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
GDIBRUSHINST PenBrushInst, FillBrushInst;
BOOL ret = FALSE; // default to failure
RECTL DestRect;
int CurrentPoint;
ASSERT(dc); // caller's responsibility to pass a valid dc
if ( NULL == UnsafePoints || Count < 2 )
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
/* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
ASSERT(BitmapObj);
/* Convert to screen coordinates */
IntLPtoDP(dc, UnsafePoints, Count);
for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
{
UnsafePoints[CurrentPoint].x += dc->w.DCOrgX;
UnsafePoints[CurrentPoint].y += dc->w.DCOrgY;
}
if (PATH_IsPathOpen(dc->w.path))
ret = PATH_Polygon(dc, UnsafePoints, Count );
else
{
DestRect.left = UnsafePoints[0].x;
DestRect.right = UnsafePoints[0].x;
DestRect.top = UnsafePoints[0].y;
DestRect.bottom = UnsafePoints[0].y;
for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
{
DestRect.left = min(DestRect.left, UnsafePoints[CurrentPoint].x);
DestRect.right = max(DestRect.right, UnsafePoints[CurrentPoint].x);
DestRect.top = min(DestRect.top, UnsafePoints[CurrentPoint].y);
DestRect.bottom = max(DestRect.bottom, UnsafePoints[CurrentPoint].y);
}
/* Now fill the polygon with the current brush. */
FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
if (FillBrushObj && !(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
{
IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
ret = FillPolygon ( dc, BitmapObj, &FillBrushInst.BrushObject, ROP2_TO_MIX(dc->Dc_Attr.jROP2), UnsafePoints, Count, DestRect );
}
BRUSHOBJ_UnlockBrush(FillBrushObj);
/* get BRUSHOBJ from current pen. */
PenBrushObj = PENOBJ_LockPen(dc->Dc_Attr.hpen);
// Draw the Polygon Edges with the current pen ( if not a NULL pen )
if (PenBrushObj && !(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
{
IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
while(Count-- >1)
{
// DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
// UnsafePoints[0].x, UnsafePoints[0].y,
// UnsafePoints[1].x, UnsafePoints[1].y );
ret = IntEngLineTo(&BitmapObj->SurfObj,
dc->CombinedClip,
&PenBrushInst.BrushObject,
UnsafePoints[0].x, /* From */
UnsafePoints[0].y,
UnsafePoints[1].x, /* To */
UnsafePoints[1].y,
&DestRect,
ROP2_TO_MIX(dc->Dc_Attr.jROP2)); /* MIX */
if(!ret) break;
UnsafePoints++;
}
}
PENOBJ_UnlockPen(PenBrushObj);
}
BITMAPOBJ_UnlockBitmap(BitmapObj);
return ret;
}
BOOL FASTCALL
IntGdiPolyPolygon(DC *dc,
LPPOINT Points,
LPINT PolyCounts,
int Count)
{
while(--Count >=0)
{
if(!IntGdiPolygon ( dc, Points, *PolyCounts )) return FALSE;
Points+=*PolyCounts++;
}
return TRUE;
}
/******************************************************************************/
/*
* NtGdiEllipse
*
* Author
* Filip Navara
*
* Remarks
* This function uses optimized Bresenham's ellipse algorithm. It draws
* four lines of the ellipse in one pass.
*
* Todo
* Make it look like a Windows ellipse.
*/
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;
PGDIBRUSHOBJ FillBrush, PenBrush;
GDIBRUSHINST FillBrushInst, PenBrushInst;
BITMAPOBJ *BitmapObj;
RECTL RectBounds;
PDC dc;
BOOL ret = TRUE, Cond1, Cond2;
/*
* Check the parameters.
*/
if (nRightRect <= nLeftRect || nBottomRect <= nTopRect)
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
/*
* Get pointers to all necessary GDI objects.
*/
dc = DC_LockDc(hDC);
if (dc == NULL)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE;
}
if (dc->IsIC)
{
DC_UnlockDc(dc);
/* Yes, Windows really returns TRUE in this case */
return TRUE;
}
FillBrush = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
if (NULL == FillBrush)
{
DC_UnlockDc(dc);
SetLastWin32Error(ERROR_INTERNAL_ERROR);
return FALSE;
}
PenBrush = PENOBJ_LockPen(dc->Dc_Attr.hpen);
if (NULL == PenBrush)
{
BRUSHOBJ_UnlockBrush(FillBrush);
DC_UnlockDc(dc);
SetLastWin32Error(ERROR_INTERNAL_ERROR);
return FALSE;
}
BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
if (NULL == BitmapObj)
{
BRUSHOBJ_UnlockBrush(FillBrush);
PENOBJ_UnlockPen(PenBrush);
DC_UnlockDc(dc);
SetLastWin32Error(ERROR_INTERNAL_ERROR);
return FALSE;
}
IntGdiInitBrushInstance(&FillBrushInst, FillBrush, dc->XlateBrush);
IntGdiInitBrushInstance(&PenBrushInst, PenBrush, dc->XlatePen);
RectBounds.left = nLeftRect;
RectBounds.right = nRightRect;
RectBounds.top = nTopRect;
RectBounds.bottom = nBottomRect;
IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
RectBounds.left += dc->w.DCOrgX;
RectBounds.right += dc->w.DCOrgX;
RectBounds.top += dc->w.DCOrgY;
RectBounds.bottom += dc->w.DCOrgY;
RadiusX = max((RectBounds.right - RectBounds.left) >> 1, 1);
RadiusY = max((RectBounds.bottom - RectBounds.top) >> 1, 1);
CenterX = RectBounds.left + RadiusX;
CenterY = RectBounds.top + RadiusY;
if (RadiusX > RadiusY)
{
nx = RadiusX;
ny = RadiusY;
}
else
{
nx = RadiusY;
ny = RadiusX;
}
da = -1;
db = 0xFFFF;
ix = 0;
iy = nx * 64;
NewA = 0;
NewB = (iy + 32) >> 6;
NewC = 0;
NewD = (NewB * ny) / nx;
do {
A = NewA;
B = NewB;
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
{
Cond1 = ((C != NewC) || (B != NewB)) && (NewA <= NewB);
Cond2 = ((D != NewD) || (A != NewA)) && (NewA <= B);
}
/*
* Draw the lines going from inner to outer (+ mirrored).
*/
if ((A > da) && (A < db))
{
PUTLINE(CenterX - D, CenterY + A, CenterX + D, CenterY + A, FillBrushInst);
if (A)
{
PUTLINE(CenterX - D, CenterY - A, CenterX + D, CenterY - A, FillBrushInst);
}
da = A;
}
/*
* Draw the lines going from outer to inner (+ mirrored).
*/
if ((B < db) && (B > da))
{
PUTLINE(CenterX - C, CenterY + B, CenterX + C, CenterY + B, FillBrushInst);
PUTLINE(CenterX - C, CenterY - B, CenterX + C, CenterY - B, FillBrushInst);
db = B;
}
/*
* Draw the pixels on the margin.
*/
if (Cond1)
{
PUTPIXEL(CenterX + C, CenterY + B, PenBrushInst);
if (C)
PUTPIXEL(CenterX - C, CenterY + B, PenBrushInst);
if (B)
{
PUTPIXEL(CenterX + C, CenterY - B, PenBrushInst);
if (C)
PUTPIXEL(CenterX - C, CenterY - B, PenBrushInst);
}
}
if (Cond2)
{
PUTPIXEL(CenterX + D, CenterY + A, PenBrushInst);
if (D)
PUTPIXEL(CenterX - D, CenterY + A, PenBrushInst);
if (A)
{
PUTPIXEL(CenterX + D, CenterY - A, PenBrushInst);
if (D)
PUTPIXEL(CenterX - D, CenterY - A, PenBrushInst);
}
}
} while (B > A);
BITMAPOBJ_UnlockBitmap(BitmapObj);
BRUSHOBJ_UnlockBrush(FillBrush);
PENOBJ_UnlockPen(PenBrush);
DC_UnlockDc(dc);
return ret;
}
typedef struct tagSHAPEPOINT
{
int X;
int Y;
int Type;
} SHAPEPOINT, *PSHAPEPOINT;
#define SHAPEPOINT_TYPE_CIRCLE 'C'
#define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
#define SHAPEPOINT_TYPE_LINE_LEFT 'L' /* Fill at left side of line */
#define SETPOINT(x, y, type) \
ShapePoints[*PointCount].X = (x); \
ShapePoints[*PointCount].Y = (y); \
ShapePoints[*PointCount].Type = (type); \
(*PointCount)++
#define SETCIRCLEPOINT(x, y) \
SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
#ifdef TODO
STATIC VOID
FASTCALL
CirclePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
int Right, int Bottom)
{
int X, X18, X27, X36, X45;
int Y, Y14, Y23, Y58, Y67;
int d, Radius;
BOOL Even;
Even = (0 == (Right - Left) % 2);
Right--;
Bottom--;
Radius = (Right - Left) >> 1;
if (Even)
{
X = 0;
Y = Radius;
d = 2 - Radius;
X18 = Right;
X27 = ((Left + Right) >> 1) + 1;
X36 = (Left + Right) >> 1;
X45 = Left;
Y14 = Top + Radius;
Y23 = Top;
Y58 = Top + Radius + 1;
Y67 = Top + (Right - Left);
ShapePoints[*PointCount].X = X27;
SETCIRCLEPOINT(X27, Y23);
SETCIRCLEPOINT(X36, Y23);
SETCIRCLEPOINT(X18, Y14);
SETCIRCLEPOINT(X45, Y14);
SETCIRCLEPOINT(X18, Y58);
SETCIRCLEPOINT(X45, Y58);
SETCIRCLEPOINT(X27, Y67);
SETCIRCLEPOINT(X36, Y67);
}
else
{
X = 0;
Y = Radius;
d = 1 - Radius;
X18 = Right;
X27 = (Left + Right) >> 1;
X36 = (Left + Right) >> 1;
X45 = Left;
Y14 = Top + Radius;
Y23 = Top;
Y58 = Top + Radius;
Y67 = Top + (Right - Left);
SETCIRCLEPOINT(X27, Y23);
SETCIRCLEPOINT(X45, Y14);
SETCIRCLEPOINT(X18, Y58);
SETCIRCLEPOINT(X27, Y67);
}
while (X < Y)
{
if (d < 0)
{
d += (X << 1) + (Even ? 4 : 3);
X27++;
X36--;
Y14--;
Y58++;
}
else
{
d += ((X - Y) << 1) + 5;
Y--;
Y23++;
Y67--;
X18--;
X45++;
X27++;
X36--;
Y14--;
Y58++;
}
X++;
SETCIRCLEPOINT(X27, Y23);
SETCIRCLEPOINT(X36, Y23);
SETCIRCLEPOINT(X18, Y14);
SETCIRCLEPOINT(X45, Y14);
SETCIRCLEPOINT(X18, Y58);
SETCIRCLEPOINT(X45, Y58);
SETCIRCLEPOINT(X27, Y67);
SETCIRCLEPOINT(X36, Y67);
}
}
STATIC VOID
LinePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
int Right, int Bottom, int XTo, int YTo, BOOL Start)
{
LONG x, y, deltax, deltay, i, xchange, ychange, error;
int Type;
x = (Right + Left) >> 1;
y = (Bottom + Top) >> 1;
deltax = XTo - x;
deltay = YTo - y;
if (deltax < 0)
{
xchange = -1;
deltax = - deltax;
x--;
}
else
{
xchange = 1;
}
if (deltay < 0)
{
ychange = -1;
deltay = - deltay;
y--;
Type = (Start ? SHAPEPOINT_TYPE_LINE_LEFT : SHAPEPOINT_TYPE_LINE_RIGHT);
}
else
{
ychange = 1;
Type = (Start ? SHAPEPOINT_TYPE_LINE_RIGHT : SHAPEPOINT_TYPE_LINE_LEFT);
}
if (y == YTo)
{
for (i = x; i <= XTo; i++)
{
SETPOINT(i, y, Type);
}
}
else if (x == XTo)
{
for (i = y; i <= YTo; i++)
{
SETPOINT(x, i, Type);
}
}
else
{
error = 0;
if (deltax < deltay)
{
for (i = 0; i < deltay; i++)
{
SETPOINT(x, y, Type);
y = y + ychange;
error = error + deltax;
if (deltay <= error)
{
x = x + xchange;
error = error - deltay;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -