From 4f3edd4e0a3c3f19a05057caa19010d77aaf9f75 Mon Sep 17 00:00:00 2001 From: Arne Scheffler Date: Tue, 2 Apr 2024 18:32:30 +0200 Subject: [PATCH] direct2d implementation for drawLinearGradientLine --- .../win32/direct2d/d2dgraphicscontext.cpp | 99 ++++++++++++++++--- .../win32/direct2d/d2dgraphicscontext.h | 8 +- 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp index 67e0093d1..2e4bb4b8a 100644 --- a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp +++ b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp @@ -295,16 +295,15 @@ struct D2DGraphicsDeviceContext::Impl } //----------------------------------------------------------------------------- - void applyLineStyle () + COM::Ptr strokeStyleFromLineStyle (const CLineStyle& s) const { - if (state.strokeStyle) - return; + COM::Ptr result; COM::Ptr factory {}; deviceContext->GetFactory (factory.adoptPtr ()); D2D1_STROKE_STYLE_PROPERTIES properties; - switch (state.lineStyle.getLineCap ()) + switch (s.getLineCap ()) { case CLineStyle::kLineCapButt: properties.startCap = properties.endCap = properties.dashCap = D2D1_CAP_STYLE_FLAT; @@ -317,7 +316,7 @@ struct D2DGraphicsDeviceContext::Impl D2D1_CAP_STYLE_SQUARE; break; } - switch (state.lineStyle.getLineJoin ()) + switch (s.getLineJoin ()) { case CLineStyle::kLineJoinMiter: properties.lineJoin = D2D1_LINE_JOIN_MITER; @@ -329,23 +328,32 @@ struct D2DGraphicsDeviceContext::Impl properties.lineJoin = D2D1_LINE_JOIN_BEVEL; break; } - properties.dashOffset = static_cast (state.lineStyle.getDashPhase ()); + properties.dashOffset = static_cast (s.getDashPhase ()); properties.miterLimit = 10.f; - if (state.lineStyle.getDashCount ()) + if (s.getDashCount ()) { properties.dashStyle = D2D1_DASH_STYLE_CUSTOM; - FLOAT* lengths = new FLOAT[state.lineStyle.getDashCount ()]; - for (uint32_t i = 0; i < state.lineStyle.getDashCount (); i++) - lengths[i] = static_cast (state.lineStyle.getDashLengths ()[i]); - factory->CreateStrokeStyle (properties, lengths, state.lineStyle.getDashCount (), - state.strokeStyle.adoptPtr ()); + FLOAT* lengths = new FLOAT[s.getDashCount ()]; + for (uint32_t i = 0; i < s.getDashCount (); i++) + lengths[i] = static_cast (s.getDashLengths ()[i]); + factory->CreateStrokeStyle (properties, lengths, s.getDashCount (), result.adoptPtr ()); delete[] lengths; } else { properties.dashStyle = D2D1_DASH_STYLE_SOLID; - factory->CreateStrokeStyle (properties, nullptr, 0, state.strokeStyle.adoptPtr ()); + factory->CreateStrokeStyle (properties, nullptr, 0, result.adoptPtr ()); } + return result; + } + + //----------------------------------------------------------------------------- + void applyLineStyle () + { + if (state.strokeStyle) + return; + + state.strokeStyle = strokeStyleFromLineStyle (state.lineStyle); } struct State @@ -819,6 +827,71 @@ bool D2DGraphicsDeviceContext::fillRadialGradient (IPlatformGraphicsPath& path, return true; } +//------------------------------------------------------------------------ +bool D2DGraphicsDeviceContext::drawLinearGradientLine (const PointList& line, + const IPlatformGradient& gradient, + CCoord lineWidth, LineCap lineCap, + LineJoin lineJoin) const +{ + if (line.size () < 2) + return false; + const auto d2dGradient = dynamic_cast (&gradient); + if (d2dGradient == nullptr) + return false; + + COM::Ptr factory {}; + impl->deviceContext->GetFactory (factory.adoptPtr ()); + if (!factory) + return false; + + COM::Ptr path; + if (FAILED (factory->CreatePathGeometry (path.adoptPtr ()))) + return false; + COM::Ptr sink; + if (FAILED (path->Open (sink.adoptPtr ()))) + return false; + sink->BeginFigure (convert (line.front ()), D2D1_FIGURE_BEGIN_FILLED); + for (auto index = 1u; index < line.size (); ++index) + sink->AddLine (convert (line[index])); + sink->EndFigure (D2D1_FIGURE_END_OPEN); + if (FAILED (sink->Close ())) + return false; + sink.reset (); + + COM::Ptr widenPath; + if (FAILED (factory->CreatePathGeometry (widenPath.adoptPtr ()))) + return false; + if (FAILED (widenPath->Open (sink.adoptPtr ()))) + return false; + CLineStyle lineStyle (static_cast (lineCap), + static_cast (lineJoin)); + auto style = impl->strokeStyleFromLineStyle (lineStyle); + if (!style) + return false; + if (FAILED (path->Widen (static_cast (lineWidth), style.get (), nullptr, sink.get ()))) + return false; + if (FAILED (sink->Close ())) + return false; + sink.reset (); + + impl->doInContext ([&] (auto deviceContext) { + auto stopCollection = COM::adopt ( + d2dGradient->create (deviceContext, static_cast (impl->state.globalAlpha))); + if (!stopCollection) + return; + COM::Ptr brush; + D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES properties; + properties.startPoint = convert (line.front ()); + properties.endPoint = convert (line.back ()); + if (SUCCEEDED (deviceContext->CreateLinearGradientBrush (properties, stopCollection.get (), + brush.adoptPtr ()))) + { + deviceContext->FillGeometry (widenPath.get (), brush.get ()); + } + }); + return true; +} + //------------------------------------------------------------------------ void D2DGraphicsDeviceContext::saveGlobalState () const { impl->stateStack.push (impl->state); } diff --git a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.h b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.h index b01373e1d..917c10919 100644 --- a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.h +++ b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.h @@ -18,7 +18,8 @@ class D2DGraphicsDevice; //------------------------------------------------------------------------ class D2DGraphicsDeviceContext : public IPlatformGraphicsDeviceContext, - public IPlatformGraphicsDeviceContextBitmapExt + public IPlatformGraphicsDeviceContextBitmapExt, + public IPlatformGraphicsDeviceContextGradientExt { public: D2DGraphicsDeviceContext (const D2DGraphicsDevice& device, ID2D1DeviceContext* deviceContext, @@ -72,6 +73,11 @@ class D2DGraphicsDeviceContext : public IPlatformGraphicsDeviceContext, bool fillRectWithBitmap (IPlatformBitmap& bitmap, CRect srcRect, CRect dstRect, double alpha, BitmapInterpolationQuality quality) const override; + // IPlatformGraphicsDeviceContextGradientExt + bool drawLinearGradientLine (const PointList& line, const IPlatformGradient& gradient, + CCoord lineWidth, LineCap lineCap, + LineJoin lineJoin) const override; + // private void drawTextLayout (IDWriteTextLayout* textLayout, CPoint pos, CColor color, bool antialias);