Skip to content

Commit

Permalink
direct2d implementation for drawLinearGradientLine
Browse files Browse the repository at this point in the history
  • Loading branch information
scheffle committed Apr 2, 2024
1 parent adacd83 commit 4f3edd4
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 14 deletions.
99 changes: 86 additions & 13 deletions vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp
Expand Up @@ -295,16 +295,15 @@ struct D2DGraphicsDeviceContext::Impl
}

//-----------------------------------------------------------------------------
void applyLineStyle ()
COM::Ptr<ID2D1StrokeStyle> strokeStyleFromLineStyle (const CLineStyle& s) const
{
if (state.strokeStyle)
return;
COM::Ptr<ID2D1StrokeStyle> result;

COM::Ptr<ID2D1Factory> 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;
Expand All @@ -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;
Expand All @@ -329,23 +328,32 @@ struct D2DGraphicsDeviceContext::Impl
properties.lineJoin = D2D1_LINE_JOIN_BEVEL;
break;
}
properties.dashOffset = static_cast<FLOAT> (state.lineStyle.getDashPhase ());
properties.dashOffset = static_cast<FLOAT> (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<FLOAT> (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<FLOAT> (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
Expand Down Expand Up @@ -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<const D2DGradient*> (&gradient);
if (d2dGradient == nullptr)
return false;

COM::Ptr<ID2D1Factory> factory {};
impl->deviceContext->GetFactory (factory.adoptPtr ());
if (!factory)
return false;

COM::Ptr<ID2D1PathGeometry> path;
if (FAILED (factory->CreatePathGeometry (path.adoptPtr ())))
return false;
COM::Ptr<ID2D1GeometrySink> 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<ID2D1PathGeometry> widenPath;
if (FAILED (factory->CreatePathGeometry (widenPath.adoptPtr ())))
return false;
if (FAILED (widenPath->Open (sink.adoptPtr ())))
return false;
CLineStyle lineStyle (static_cast<CLineStyle::LineCap> (lineCap),
static_cast<CLineStyle::LineJoin> (lineJoin));
auto style = impl->strokeStyleFromLineStyle (lineStyle);
if (!style)
return false;
if (FAILED (path->Widen (static_cast<FLOAT> (lineWidth), style.get (), nullptr, sink.get ())))
return false;
if (FAILED (sink->Close ()))
return false;
sink.reset ();

impl->doInContext ([&] (auto deviceContext) {
auto stopCollection = COM::adopt<ID2D1GradientStopCollection> (
d2dGradient->create (deviceContext, static_cast<FLOAT> (impl->state.globalAlpha)));
if (!stopCollection)
return;
COM::Ptr<ID2D1LinearGradientBrush> 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); }

Expand Down
8 changes: 7 additions & 1 deletion vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.h
Expand Up @@ -18,7 +18,8 @@ class D2DGraphicsDevice;

//------------------------------------------------------------------------
class D2DGraphicsDeviceContext : public IPlatformGraphicsDeviceContext,
public IPlatformGraphicsDeviceContextBitmapExt
public IPlatformGraphicsDeviceContextBitmapExt,
public IPlatformGraphicsDeviceContextGradientExt
{
public:
D2DGraphicsDeviceContext (const D2DGraphicsDevice& device, ID2D1DeviceContext* deviceContext,
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 4f3edd4

Please sign in to comment.