//----------------------------------------------------------------------------- void D2DDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { if (renderTarget == 0) return; D2DGraphicsPath* d2dPath = dynamic_cast<D2DGraphicsPath*> (_path); if (d2dPath == 0) return; ID2D1PathGeometry* path = d2dPath->getPath (evenOdd ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING); if (path) { D2DApplyClip ac (this); ID2D1Geometry* geometry = 0; if (t) { ID2D1TransformedGeometry* tg = 0; D2D1_MATRIX_3X2_F matrix; matrix._11 = (FLOAT)t->m11; matrix._12 = (FLOAT)t->m12; matrix._21 = (FLOAT)t->m21; matrix._22 = (FLOAT)t->m22; matrix._31 = (FLOAT)t->dx; matrix._32 = (FLOAT)t->dy; getD2DFactory ()->CreateTransformedGeometry (path, matrix, &tg); geometry = tg; } else { geometry = path; geometry->AddRef (); } ID2D1GradientStopCollection* collection = 0; D2D1_GRADIENT_STOP gradientStops[2]; gradientStops[0].position = (FLOAT)gradient.getColor1Start (); gradientStops[1].position = (FLOAT)gradient.getColor2Start (); gradientStops[0].color = D2D1::ColorF (gradient.getColor1 ().red/255.f, gradient.getColor1 ().green/255.f, gradient.getColor1 ().blue/255.f, gradient.getColor1 ().alpha/255.f * currentState.globalAlpha); gradientStops[1].color = D2D1::ColorF (gradient.getColor2 ().red/255.f, gradient.getColor2 ().green/255.f, gradient.getColor2 ().blue/255.f, gradient.getColor2 ().alpha/255.f * currentState.globalAlpha); if (SUCCEEDED (getRenderTarget ()->CreateGradientStopCollection (gradientStops, 2, &collection))) { ID2D1LinearGradientBrush* brush = 0; D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES properties; properties.startPoint = makeD2DPoint (startPoint); properties.endPoint = makeD2DPoint (endPoint); if (SUCCEEDED (getRenderTarget ()->CreateLinearGradientBrush (properties, collection, &brush))) { getRenderTarget ()->SetTransform (D2D1::Matrix3x2F::Translation ((FLOAT)getOffset ().x, (FLOAT)getOffset ().y)); getRenderTarget ()->FillGeometry (geometry, brush); getRenderTarget ()->SetTransform (D2D1::Matrix3x2F::Identity ()); brush->Release (); } collection->Release (); } geometry->Release (); } }
//----------------------------------------------------------------------------- void D2DDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { if (renderTarget == 0) return; bool halfPointOffset = currentState.drawMode.integralMode () ? ((((int32_t)currentState.frameWidth) % 2) != 0) : false; D2DApplyClip ac (this, halfPointOffset); if (ac.isEmpty ()) return; D2DGraphicsPath* d2dPath = dynamic_cast<D2DGraphicsPath*> (_path); if (d2dPath == 0) return; ID2D1Geometry* path = d2dPath->createPath (evenOdd ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING, this, t); if (path) { ID2D1GradientStopCollection* collection = createGradientStopCollection (gradient); if (collection) { ID2D1LinearGradientBrush* brush = 0; D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES properties; properties.startPoint = makeD2DPoint (startPoint); properties.endPoint = makeD2DPoint (endPoint); if (SUCCEEDED (getRenderTarget ()->CreateLinearGradientBrush (properties, collection, &brush))) { getRenderTarget ()->FillGeometry (path, brush); brush->Release (); } collection->Release (); } path->Release (); } }
//----------------------------------------------------------------------------- void D2DDrawContext::fillRadialGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& center, CCoord radius, const CPoint& originOffset, bool evenOdd, CGraphicsTransform* t) { if (renderTarget == 0) return; D2DApplyClip ac (this); if (ac.isEmpty ()) return; D2DGraphicsPath* d2dPath = dynamic_cast<D2DGraphicsPath*> (_path); if (d2dPath == 0) return; ID2D1Geometry* path = d2dPath->createPath (evenOdd ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING); if (path) { ID2D1Geometry* geometry = 0; if (t) { ID2D1TransformedGeometry* tg = 0; getD2DFactory ()->CreateTransformedGeometry (path, convert (*t), &tg); geometry = tg; } else { geometry = path; geometry->AddRef (); } ID2D1GradientStopCollection* collection = createGradientStopCollection (gradient); if (collection) { // brush properties ID2D1RadialGradientBrush* brush = 0; D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES properties; properties.center = makeD2DPoint (center); properties.gradientOriginOffset = makeD2DPoint (originOffset); properties.radiusX = (FLOAT)radius; properties.radiusY = (FLOAT)radius; if (SUCCEEDED (getRenderTarget ()->CreateRadialGradientBrush (properties, collection, &brush))) { getRenderTarget ()->FillGeometry (geometry, brush); brush->Release (); } collection->Release (); } geometry->Release (); path->Release (); } }
//----------------------------------------------------------------------------- void D2DDrawContext::drawEllipse (const CRect &_rect, const CDrawStyle drawStyle) { if (renderTarget == 0) return; D2DApplyClip ac (this); if (ac.isEmpty ()) return; CRect rect (_rect); if (currentState.drawMode.integralMode ()) pixelAllign (rect); CPoint center (rect.getTopLeft ()); center.offset (rect.getWidth () / 2., rect.getHeight () / 2.); D2D1_ELLIPSE ellipse; ellipse.point = makeD2DPoint (center); ellipse.radiusX = (FLOAT)(rect.getWidth () / 2.); ellipse.radiusY = (FLOAT)(rect.getHeight () / 2.); if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) { renderTarget->FillEllipse (ellipse, fillBrush); } if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) { renderTarget->DrawEllipse (ellipse, strokeBrush, (FLOAT)currentState.frameWidth, strokeStyle); } }
//----------------------------------------------------------------------------- void D2DDrawContext::lineTo (const CPoint &point) { CPoint penLocation (currentState.penLoc); CPoint p (point); p.offset (currentState.offset.x, currentState.offset.y); if (currentState.drawMode.integralMode ()) { p.makeIntegral (); penLocation.makeIntegral (); } if (renderTarget) { D2DApplyClip clip (this); if ((((int32_t)currentState.frameWidth) % 2)) renderTarget->SetTransform (D2D1::Matrix3x2F::Translation (0.5f, 0.5f)); renderTarget->DrawLine (makeD2DPoint (penLocation), makeD2DPoint (p), strokeBrush, (FLOAT)currentState.frameWidth, strokeStyle); renderTarget->SetTransform (D2D1::Matrix3x2F::Identity ()); } currentState.penLoc = p; }
//----------------------------------------------------------------------------- void D2DDrawContext::drawLine (const LinePair& line) { if (renderTarget == 0) return; D2DApplyClip ac (this, (((int32_t)currentState.frameWidth) % 2) != 0); if (ac.isEmpty ()) return; if (renderTarget) { CPoint start (line.first); CPoint end (line.second); if (currentState.drawMode.integralMode ()) { pixelAllign (start); pixelAllign (end); } renderTarget->DrawLine (makeD2DPoint (start), makeD2DPoint (end), strokeBrush, (FLOAT)currentState.frameWidth, strokeStyle); } }
//----------------------------------------------------------------------------- bool D2DGraphicsPath::hitTest (const CPoint& p, bool evenOddFilled, CGraphicsTransform* transform) { ID2D1PathGeometry* _path = getPath (evenOddFilled ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING); if (_path) { D2D1::Matrix3x2F matrix = D2D1::Matrix3x2F::Identity (); if (transform) { matrix._11 = (FLOAT)transform->m11; matrix._12 = (FLOAT)transform->m12; matrix._21 = (FLOAT)transform->m21; matrix._22 = (FLOAT)transform->m22; matrix._31 = (FLOAT)transform->dx; matrix._32 = (FLOAT)transform->dy; } BOOL result; if (SUCCEEDED (_path->FillContainsPoint (makeD2DPoint (p), matrix, &result))) { return result ? true : false; } } return false; }
//----------------------------------------------------------------------------- void D2DDrawContext::drawEllipse (const CRect &_rect, const CDrawStyle drawStyle) { if (renderTarget) { CRect rect (_rect); rect.offset (currentState.offset.x, currentState.offset.y); rect.normalize (); D2DApplyClip clip (this); CPoint center (rect.getTopLeft ()); center.offset (rect.getWidth () / 2., rect.getHeight () / 2.); D2D1_ELLIPSE ellipse; ellipse.point = makeD2DPoint (center); ellipse.radiusX = (FLOAT)(rect.getWidth () / 2.); ellipse.radiusY = (FLOAT)(rect.getHeight () / 2.); if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) { renderTarget->FillEllipse (ellipse, fillBrush); } if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) { renderTarget->DrawEllipse (ellipse, strokeBrush, (FLOAT)currentState.frameWidth, strokeStyle); } } }
//----------------------------------------------------------------------------- ID2D1PathGeometry* D2DGraphicsPath::getPath (int32_t fillMode) { if (path == 0 || fillMode != currentPathFillMode) { dirty (); if (!SUCCEEDED (getD2DFactory ()->CreatePathGeometry (&path))) return 0; if (fillMode == -1) fillMode = 0; currentPathFillMode = fillMode; ID2D1GeometrySink* sink = 0; if (!SUCCEEDED (path->Open (&sink))) { path->Release (); path = 0; return 0; } sink->SetFillMode ((D2D1_FILL_MODE)fillMode); bool figureOpen = false; CPoint lastPos; for (ElementList::const_iterator it = elements.begin (); it != elements.end (); it++) { Element e = (*it); switch (e.type) { case Element::kArc: { bool clockwise = e.instruction.arc.clockwise; double startAngle = e.instruction.arc.startAngle; double endAngle = e.instruction.arc.endAngle; CRect o_r (e.instruction.arc.rect.left, e.instruction.arc.rect.top, e.instruction.arc.rect.right, e.instruction.arc.rect.bottom); CRect r (o_r); o_r.originize (); CPoint center = o_r.getCenter (); CPoint start; start.x = r.left + center.x + center.x * cos (radians (startAngle)); start.y = r.top + center.y + center.y * sin (radians (startAngle)); if (!figureOpen) { sink->BeginFigure (makeD2DPoint (start), D2D1_FIGURE_BEGIN_FILLED); figureOpen = true; } else if (lastPos != start) { sink->AddLine (makeD2DPoint (start)); } double sweepangle = endAngle - startAngle; if (clockwise) { // sweepangle positive while (sweepangle < 0.0) sweepangle += 360.0; while (sweepangle > 360.0) sweepangle -= 360.0; } else { // sweepangle negative while (sweepangle > 0.0) sweepangle -= 360.0; while (sweepangle < -360.0) sweepangle += 360.0; } CPoint endPoint; endPoint.x = r.left + center.x + center.x * cos (radians (endAngle)); endPoint.y = r.top + center.y + center.y * sin (radians (endAngle)); D2D1_ARC_SEGMENT arc; arc.size = makeD2DSize (r.getWidth ()/2., r.getHeight ()/2.); arc.rotationAngle = 0; arc.sweepDirection = clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE; arc.point = makeD2DPoint (endPoint); arc.arcSize = fabs(sweepangle) <= 180. ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE; sink->AddArc (arc); lastPos = endPoint; break; } case Element::kEllipse: { CRect r (e.instruction.rect.left, e.instruction.rect.top, e.instruction.rect.right, e.instruction.rect.bottom); CPoint top (r.getTopLeft ()); top.x += r.getWidth () / 2.; CPoint bottom (r.getBottomLeft ()); bottom.x += r.getWidth () / 2.; if (figureOpen && lastPos != CPoint (e.instruction.rect.left, e.instruction.rect.top)) { sink->EndFigure (D2D1_FIGURE_END_OPEN); figureOpen = false; } if (!figureOpen) { sink->BeginFigure (makeD2DPoint (top), D2D1_FIGURE_BEGIN_FILLED); figureOpen = true; } D2D1_ARC_SEGMENT arc = D2D1::ArcSegment (makeD2DPoint (bottom), D2D1::SizeF ((FLOAT)r.getWidth ()/2.f, (FLOAT)r.getHeight ()/2.f), 180.f, D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_SMALL); sink->AddArc (arc); arc.point = makeD2DPoint (top); sink->AddArc (arc); lastPos = top; break; } case Element::kRect: { D2D1_POINT_2F points[4] = { {(FLOAT)e.instruction.rect.right, (FLOAT)e.instruction.rect.top}, {(FLOAT)e.instruction.rect.right, (FLOAT)e.instruction.rect.bottom}, {(FLOAT)e.instruction.rect.left, (FLOAT)e.instruction.rect.bottom}, {(FLOAT)e.instruction.rect.left, (FLOAT)e.instruction.rect.top} }; if (figureOpen && lastPos != CPoint (e.instruction.rect.left, e.instruction.rect.top)) { sink->EndFigure (D2D1_FIGURE_END_OPEN); figureOpen = false; } if (figureOpen == false) { sink->BeginFigure (points[3], D2D1_FIGURE_BEGIN_FILLED); figureOpen = true; } sink->AddLine (points[0]); sink->AddLine (points[1]); sink->AddLine (points[2]); sink->AddLine (points[3]); lastPos = CPoint (e.instruction.rect.left, e.instruction.rect.top); break; } case Element::kLine: { if (figureOpen) { D2D1_POINT_2F end = {(FLOAT)e.instruction.point.x, (FLOAT)e.instruction.point.y}; sink->AddLine (end); lastPos = CPoint (e.instruction.point.x, e.instruction.point.y); } break; } case Element::kBezierCurve: { if (figureOpen) { D2D1_POINT_2F control1 = {(FLOAT)e.instruction.curve.control1.x, (FLOAT)e.instruction.curve.control1.y}; D2D1_POINT_2F control2 = {(FLOAT)e.instruction.curve.control2.x, (FLOAT)e.instruction.curve.control2.y}; D2D1_POINT_2F end = {(FLOAT)e.instruction.curve.end.x, (FLOAT)e.instruction.curve.end.y}; D2D1_BEZIER_SEGMENT bezier = D2D1::BezierSegment (control1, control2, end); sink->AddBezier (bezier); lastPos = CPoint (e.instruction.curve.end.x, e.instruction.curve.end.y); } break; } case Element::kBeginSubpath: { if (figureOpen) sink->EndFigure (D2D1_FIGURE_END_OPEN); D2D1_POINT_2F start = {(FLOAT)e.instruction.point.x, (FLOAT)e.instruction.point.y}; sink->BeginFigure (start, D2D1_FIGURE_BEGIN_FILLED); figureOpen = true; lastPos = CPoint (e.instruction.point.x, e.instruction.point.y); break; } case Element::kCloseSubpath: { if (figureOpen) { sink->EndFigure (D2D1_FIGURE_END_CLOSED); figureOpen = false; } break; } } } if (figureOpen) sink->EndFigure (D2D1_FIGURE_END_OPEN); HRESULT res = sink->Close (); if (!SUCCEEDED (res)) { path->Release (); path = 0; } sink->Release (); } return path; }