[GDI+ implementation: 8/8] GdipDrawCurve2
Evan Stade
estade at gmail.com
Tue Jun 12 13:02:40 CDT 2007
Hi
This uses GDI Bezier curves to implemented GDI+ cardinal splines.
Changelog:
*implemented GdipDrawCurve2
dlls/gdiplus/gdiplus.spec | 2 +
dlls/gdiplus/graphics.c | 87 ++++++++++++++++++++++++++++++++++++++++++++-
include/gdiplusflat.h | 4 ++
include/gdiplustypes.h | 56 +++++++++++++++++++++++++++++
4 files changed, 147 insertions(+), 2 deletions(-)
-Evan Stade
-------------- next part --------------
diff --git a/dlls/gdiplus/gdiplus.spec b/dlls/gdiplus/gdiplus.spec
index 40a8c19..7206a65 100644
--- a/dlls/gdiplus/gdiplus.spec
+++ b/dlls/gdiplus/gdiplus.spec
@@ -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
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index bd968ad..e0aa64a 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -27,12 +27,17 @@ #include "gdiplus.h"
#include "gdiplus_private.h"
#include "wine/debug.h"
+WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
+
+/* looks-right constant */
+#define TENSION_CONST (0.3)
+
static inline REAL deg2rad(REAL degrees)
{
return (M_PI*2.0) * degrees / 360.0;
}
-static INT roundr(REAL x)
+static inline INT roundr(REAL x)
{
return (INT) floor(x+0.5);
}
@@ -226,3 +231,83 @@ GpStatus WINGDIPAPI GdipDrawBezier(GpGra
return Ok;
}
+
+/* GdipDrawCurve helper function.
+ * Calculates Bezier points from cardinal spline endpoints. */
+static void CalcCurveBezierEndp(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);
+}
+
+/* GdipDrawCurve helper function.
+ * Calculates Bezier points from cardinal spline points. */
+static void CalcCurveBezier(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;
+}
+
+/* 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;
+
+ CalcCurveBezierEndp(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++){
+ CalcCurveBezier(&(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);
+ }
+
+ CalcCurveBezierEndp(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;
+}
diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h
index c7cbfa7..0c5b749 100644
--- a/include/gdiplusflat.h
+++ b/include/gdiplusflat.h
@@ -21,6 +21,8 @@ #define _FLATAPI_H
#define WINGDIPAPI __stdcall
+#define GDIPCONST const
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -38,6 +40,8 @@ GpStatus WINGDIPAPI GdipDrawPie(GpGraphi
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 GdipCreateSolidFill(ARGB,GpSolidFill**);
GpStatus WINGDIPAPI GdipGetBrushType(GpBrush*,GpBrushType*);
diff --git a/include/gdiplustypes.h b/include/gdiplustypes.h
index f4b389d..ab9a69d 100644
--- a/include/gdiplustypes.h
+++ b/include/gdiplustypes.h
@@ -97,6 +97,56 @@ public:
INT Y;
};
+class PointF
+{
+public:
+ PointF()
+ {
+ X = Y = 0.0f;
+ }
+
+ PointF(IN const PointF &point)
+ {
+ X = point.X;
+ Y = point.Y;
+ }
+
+ PointF(IN const SizeF &size)
+ {
+ X = size.Width;
+ Y = size.Height;
+ }
+
+ PointF(IN REAL x,
+ IN REAL y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ PointF operator+(IN const PointF& point) const
+ {
+ return PointF(X + point.X,
+ Y + point.Y);
+ }
+
+ PointF operator-(IN const PointF& point) const
+ {
+ return PointF(X - point.X,
+ Y - point.Y);
+ }
+
+ BOOL Equals(IN const PointF& point)
+ {
+ return (X == point.X) && (Y == point.Y);
+ }
+
+public:
+
+ REAL X;
+ REAL Y;
+};
+
#else /* end of c++ typedefs */
typedef struct Point
@@ -105,6 +155,12 @@ typedef struct Point
INT Y;
} Point;
+typedef struct PointF
+{
+ REAL X;
+ REAL Y;
+} PointF;
+
typedef enum Status Status;
#endif /* end of c typedefs */
--
1.4.1
More information about the wine-patches
mailing list