gdiplus: Implemented GdipDrawCurve2.

This commit is contained in:
Evan Stade 2007-06-19 19:31:28 -07:00 committed by Alexandre Julliard
parent c42f8794a1
commit 5c8b83c524
5 changed files with 139 additions and 2 deletions

View File

@ -153,7 +153,7 @@
@ stub GdipDrawClosedCurve2I
@ stub GdipDrawClosedCurve
@ stub GdipDrawClosedCurveI
@ stub GdipDrawCurve2
@ stdcall GdipDrawCurve2(ptr ptr ptr long long)
@ stub GdipDrawCurve2I
@ stub GdipDrawCurve3
@ stub GdipDrawCurve3I

View File

@ -27,6 +27,9 @@
#include "gdiplus_private.h"
#include "wine/debug.h"
/* looks-right constant */
#define TENSION_CONST (0.3)
static inline INT roundr(REAL x)
{
return (INT) floor(x+0.5);
@ -77,6 +80,34 @@ static GpStatus draw_pie(GpGraphics *graphics, HBRUSH gdibrush, HPEN gdipen,
return Ok;
}
/* GdipDrawCurve helper function.
* Calculates Bezier points from cardinal spline points. */
static void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
REAL *y1, REAL *x2, REAL *y2)
{
REAL xdiff, ydiff;
/* calculate tangent */
xdiff = pts[2].X - pts[0].X;
ydiff = pts[2].Y - pts[0].Y;
/* apply tangent to get control points */
*x1 = pts[1].X - tension * xdiff;
*y1 = pts[1].Y - tension * ydiff;
*x2 = pts[1].X + tension * xdiff;
*y2 = pts[1].Y + tension * ydiff;
}
/* GdipDrawCurve helper function.
* Calculates Bezier points from cardinal spline endpoints. */
static void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
REAL tension, REAL *x, REAL *y)
{
/* tangent at endpoints is the line from the endpoint to the adjacent point */
*x = roundr(tension * (xadj - xend) + xend);
*y = roundr(tension * (yadj - yend) + yend);
}
GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
{
if(hdc == NULL)
@ -160,6 +191,58 @@ GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics *graphics, GpPen *pen, REAL x1,
return Ok;
}
/* Approximates cardinal spline with Bezier curves. */
GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen,
GDIPCONST GpPointF *points, INT count, REAL tension)
{
HGDIOBJ old_pen;
/* PolyBezier expects count*3-2 points. */
int i, len_pt = count*3-2;
POINT pt[len_pt];
REAL x1, x2, y1, y2;
if(!graphics || !pen)
return InvalidParameter;
tension = tension * TENSION_CONST;
calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
tension, &x1, &y1);
pt[0].x = roundr(points[0].X);
pt[0].y = roundr(points[0].Y);
pt[1].x = roundr(x1);
pt[1].y = roundr(y1);
for(i = 0; i < count-2; i++){
calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2);
pt[3*i+2].x = roundr(x1);
pt[3*i+2].y = roundr(y1);
pt[3*i+3].x = roundr(points[i+1].X);
pt[3*i+3].y = roundr(points[i+1].Y);
pt[3*i+4].x = roundr(x2);
pt[3*i+4].y = roundr(y2);
}
calc_curve_bezier_endp(points[count-1].X, points[count-1].Y,
points[count-2].X, points[count-2].Y, tension, &x1, &y1);
pt[len_pt-2].x = x1;
pt[len_pt-2].y = y1;
pt[len_pt-1].x = roundr(points[count-1].X);
pt[len_pt-1].y = roundr(points[count-1].Y);
old_pen = SelectObject(graphics->hdc, pen->gdipen);
PolyBezier(graphics->hdc, pt, len_pt);
SelectObject(graphics->hdc, old_pen);
return Ok;
}
GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1,
INT y1, INT x2, INT y2)
{

View File

@ -21,6 +21,8 @@
#define WINGDIPAPI __stdcall
#define GDIPCONST const
#ifdef __cplusplus
extern "C" {
#endif
@ -34,6 +36,7 @@ GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *);
GpStatus WINGDIPAPI GdipDrawArc(GpGraphics*,GpPen*,REAL,REAL,REAL,REAL,REAL,REAL);
GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics*,GpPen*,REAL,REAL,REAL,REAL,REAL,
REAL,REAL,REAL);
GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics*,GpPen*,GDIPCONST GpPointF*,INT,REAL);
GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics*,GpPen*,INT,INT,INT,INT);
GpStatus WINGDIPAPI GdipDrawPie(GpGraphics*,GpPen*,REAL,REAL,REAL,REAL,REAL,REAL);
GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics*,GpPen*,INT,INT,INT,INT);

View File

@ -38,5 +38,6 @@ typedef struct GpSolidFill GpSolidFill;
typedef Status GpStatus;
typedef Unit GpUnit;
typedef BrushType GpBrushType;
typedef PointF GpPointF;
#endif

View File

@ -45,7 +45,57 @@ enum Status{
PropertyNotSupported = 20
};
#ifndef __cplusplus
#ifdef __cplusplus
class PointF
{
public:
PointF()
{
X = Y = 0.0f;
}
PointF(IN const PointF &pt)
{
X = pt.X;
Y = pt.Y;
}
/* FIXME: missing constructor that takes a SizeF */
PointF(IN REAL x, IN REAL y)
{
X = x;
Y = y;
}
PointF operator+(IN const PointF& pt) const
{
return PointF(X + pt.X, Y + pt.Y);
}
PointF operator-(IN const PointF& pt) const
{
return PointF(X - pt.X, Y - pt.Y);
}
BOOL Equals(IN const PointF& pt)
{
return (X == pt.X) && (Y == pt.Y);
}
public:
REAL X;
REAL Y;
};
#else /* end of c++ typedefs */
typedef struct PointF
{
REAL X;
REAL Y;
} PointF;
typedef enum Status Status;