aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/libui/windows/drawpath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl/libui/windows/drawpath.cpp')
-rw-r--r--src/libui_sdl/libui/windows/drawpath.cpp246
1 files changed, 0 insertions, 246 deletions
diff --git a/src/libui_sdl/libui/windows/drawpath.cpp b/src/libui_sdl/libui/windows/drawpath.cpp
deleted file mode 100644
index 49855be..0000000
--- a/src/libui_sdl/libui/windows/drawpath.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-// 7 september 2015
-#include "uipriv_windows.hpp"
-#include "draw.hpp"
-
-// TODO
-// - write a test for transform followed by clip and clip followed by transform to make sure they work the same as on gtk+ and cocoa
-// - write a test for nested transforms for gtk+
-
-struct uiDrawPath {
- ID2D1PathGeometry *path;
- ID2D1GeometrySink *sink;
- BOOL inFigure;
-};
-
-uiDrawPath *uiDrawNewPath(uiDrawFillMode fillmode)
-{
- uiDrawPath *p;
- HRESULT hr;
-
- p = uiNew(uiDrawPath);
- hr = d2dfactory->CreatePathGeometry(&(p->path));
- if (hr != S_OK)
- logHRESULT(L"error creating path", hr);
- hr = p->path->Open(&(p->sink));
- if (hr != S_OK)
- logHRESULT(L"error opening path", hr);
- switch (fillmode) {
- case uiDrawFillModeWinding:
- p->sink->SetFillMode(D2D1_FILL_MODE_WINDING);
- break;
- case uiDrawFillModeAlternate:
- p->sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
- break;
- }
- return p;
-}
-
-void uiDrawFreePath(uiDrawPath *p)
-{
- if (p->inFigure)
- p->sink->EndFigure(D2D1_FIGURE_END_OPEN);
- if (p->sink != NULL)
- // TODO close sink first?
- p->sink->Release();
- p->path->Release();
- uiFree(p);
-}
-
-void uiDrawPathNewFigure(uiDrawPath *p, double x, double y)
-{
- D2D1_POINT_2F pt;
-
- if (p->inFigure)
- p->sink->EndFigure(D2D1_FIGURE_END_OPEN);
- pt.x = x;
- pt.y = y;
- p->sink->BeginFigure(pt, D2D1_FIGURE_BEGIN_FILLED);
- p->inFigure = TRUE;
-}
-
-// Direct2D arcs require a little explanation.
-// An arc in Direct2D is defined by the chord between the endpoints.
-// There are four possible arcs with the same two endpoints that you can draw this way.
-// See https://www.youtube.com/watch?v=ATS0ANW1UxQ for a demonstration.
-// There is a property rotationAngle which deals with the rotation /of the entire ellipse that forms an ellpitical arc/ - it's effectively a transformation on the arc.
-// That is to say, it's NOT THE SWEEP.
-// The sweep is defined by the start and end points and whether the arc is "large".
-// As a result, this design does not allow for full circles or ellipses with a single arc; they have to be simulated with two.
-
-struct arc {
- double xCenter;
- double yCenter;
- double radius;
- double startAngle;
- double sweep;
- int negative;
-};
-
-// this is used for the comparison below
-// if it falls apart it can be changed later
-#define aerMax 6 * DBL_EPSILON
-
-static void drawArc(uiDrawPath *p, struct arc *a, void (*startFunction)(uiDrawPath *, double, double))
-{
- double sinx, cosx;
- double startX, startY;
- double endX, endY;
- D2D1_ARC_SEGMENT as;
- BOOL fullCircle;
- double absSweep;
-
- // as above, we can't do a full circle with one arc
- // simulate it with two half-circles
- // of course, we have a dragon: equality on floating-point values!
- // I've chosen to do the AlmostEqualRelative() technique in https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
- fullCircle = FALSE;
- // use the absolute value to tackle both ≥2π and ≤-2π at the same time
- absSweep = fabs(a->sweep);
- if (absSweep > (2 * uiPi)) // this part is easy
- fullCircle = TRUE;
- else {
- double aerDiff;
-
- aerDiff = fabs(absSweep - (2 * uiPi));
- // if we got here then we know a->sweep is larger (or the same!)
- fullCircle = aerDiff <= absSweep * aerMax;
- }
- // TODO make sure this works right for the negative direction
- if (fullCircle) {
- a->sweep = uiPi;
- drawArc(p, a, startFunction);
- a->startAngle += uiPi;
- drawArc(p, a, NULL);
- return;
- }
-
- // first, figure out the arc's endpoints
- // unfortunately D2D1SinCos() is only defined on Windows 8 and newer
- // the MSDN page doesn't say this, but says it requires d2d1_1.h, which is listed as only supported on Windows 8 and newer elsewhere on MSDN
- // so we must use sin() and cos() and hope it's right...
- sinx = sin(a->startAngle);
- cosx = cos(a->startAngle);
- startX = a->xCenter + a->radius * cosx;
- startY = a->yCenter + a->radius * sinx;
- sinx = sin(a->startAngle + a->sweep);
- cosx = cos(a->startAngle + a->sweep);
- endX = a->xCenter + a->radius * cosx;
- endY = a->yCenter + a->radius * sinx;
-
- // now do the initial step to get the current point to be the start point
- // this is either creating a new figure, drawing a line, or (in the case of our full circle code above) doing nothing
- if (startFunction != NULL)
- (*startFunction)(p, startX, startY);
-
- // now we can draw the arc
- as.point.x = endX;
- as.point.y = endY;
- as.size.width = a->radius;
- as.size.height = a->radius;
- as.rotationAngle = 0; // as above, not relevant for circles
- if (a->negative)
- as.sweepDirection = D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE;
- else
- as.sweepDirection = D2D1_SWEEP_DIRECTION_CLOCKWISE;
- // TODO explain the outer if
- if (!a->negative)
- if (a->sweep > uiPi)
- as.arcSize = D2D1_ARC_SIZE_LARGE;
- else
- as.arcSize = D2D1_ARC_SIZE_SMALL;
- else
- // TODO especially this part
- if (a->sweep > uiPi)
- as.arcSize = D2D1_ARC_SIZE_SMALL;
- else
- as.arcSize = D2D1_ARC_SIZE_LARGE;
- p->sink->AddArc(&as);
-}
-
-void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative)
-{
- struct arc a;
-
- a.xCenter = xCenter;
- a.yCenter = yCenter;
- a.radius = radius;
- a.startAngle = startAngle;
- a.sweep = sweep;
- a.negative = negative;
- drawArc(p, &a, uiDrawPathNewFigure);
-}
-
-void uiDrawPathLineTo(uiDrawPath *p, double x, double y)
-{
- D2D1_POINT_2F pt;
-
- pt.x = x;
- pt.y = y;
- p->sink->AddLine(pt);
-}
-
-void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative)
-{
- struct arc a;
-
- a.xCenter = xCenter;
- a.yCenter = yCenter;
- a.radius = radius;
- a.startAngle = startAngle;
- a.sweep = sweep;
- a.negative = negative;
- drawArc(p, &a, uiDrawPathLineTo);
-}
-
-void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, double c2y, double endX, double endY)
-{
- D2D1_BEZIER_SEGMENT s;
-
- s.point1.x = c1x;
- s.point1.y = c1y;
- s.point2.x = c2x;
- s.point2.y = c2y;
- s.point3.x = endX;
- s.point3.y = endY;
- p->sink->AddBezier(&s);
-}
-
-void uiDrawPathCloseFigure(uiDrawPath *p)
-{
- p->sink->EndFigure(D2D1_FIGURE_END_CLOSED);
- p->inFigure = FALSE;
-}
-
-void uiDrawPathAddRectangle(uiDrawPath *p, double x, double y, double width, double height)
-{
- // this is the same algorithm used by cairo and Core Graphics, according to their documentations
- uiDrawPathNewFigure(p, x, y);
- uiDrawPathLineTo(p, x + width, y);
- uiDrawPathLineTo(p, x + width, y + height);
- uiDrawPathLineTo(p, x, y + height);
- uiDrawPathCloseFigure(p);
-}
-
-void uiDrawPathEnd(uiDrawPath *p)
-{
- HRESULT hr;
-
- if (p->inFigure) {
- p->sink->EndFigure(D2D1_FIGURE_END_OPEN);
- // needed for uiDrawFreePath()
- p->inFigure = FALSE;
- }
- hr = p->sink->Close();
- if (hr != S_OK)
- logHRESULT(L"error closing path", hr);
- p->sink->Release();
- // also needed for uiDrawFreePath()
- p->sink = NULL;
-}
-
-ID2D1PathGeometry *pathGeometry(uiDrawPath *p)
-{
- if (p->sink != NULL)
- userbug("You cannot draw with a uiDrawPath that was not ended. (path: %p)", p);
- return p->path;
-}