In this tutorial, we are going to take a look at drawing with linear and radial gradient brush.
Table of Contents
The example code is hosted at Github.
Introduction
In this article, we'll look at how to draw with linear and radial gradient colors in Direct2D. The prerequisite of the article is the knowledge to set up the RenderTarget
. If you haven't got a clue of what RenderTarget
is, please go read the RenderTarget article first and then come back to read this article.
Linear Gradient
To create a linear gradient brush, an array of gradient stop has to be defined. A gradient stop consists of its position and color. The first gradient stop position should be 0
and the last be 1
. Then CreateGradientStopCollection()
is called to create ID2D1GradientStopCollection
from stops[]
which is followed by CreateLinearGradientBrush()
to create the ID2D1LinearGradientBrush
.
ComPtr<ID2D1LinearGradientBrush> m_LinearBrush;
void CD2DGradientDlg::CreateLinearGradientBrush()
{
D2D1_GRADIENT_STOP stops[] =
{
{ 0.0f, ColorF(ColorF::Cyan) },
{ 1.0f, ColorF(ColorF::DarkBlue) }
};
ComPtr<ID2D1GradientStopCollection> collection;
HR(m_Target->CreateGradientStopCollection(stops, _countof(stops),
collection.GetAddressOf()));
D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = {};
HR(m_Target->CreateLinearGradientBrush(props, collection.Get(),
m_LinearBrush.ReleaseAndGetAddressOf()));
}
After the gradient brush is created, we can draw with it. First, we set the start and end point with SetStartPoint()
and SetEndPoint()
. Alternatively, the start and end point can be specified in D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES
structure during the brush creation code above. Our gradient starts from position (0,0
) to a position of the dialog width and height, meaning the gradient is diagonal.
void CD2DGradientDlg::DrawLinearGradientRect()
{
auto size = m_Target->GetSize();
m_LinearBrush->SetStartPoint(Point2F(0.0f, 0.0f));
m_LinearBrush->SetEndPoint(Point2F(size.width, size.height));
auto r = RectF(0.0f, 0.0f, size.width, size.height);
m_Target->FillRectangle(r, m_LinearBrush.Get());
}
Rainbow Linear Gradient
Next, we'll create a horizontal linear gradient with rainbow colors (meaning more than 2 colors). The previous gradient stops are commented out and a new stops comprised of 4 colors are specified. The 2nd and 3rd stops are positioned at 0.33
and 0.66
. Any colors in-between these stops are linearly interpolated.
ComPtr<ID2D1LinearGradientBrush> m_LinearBrush;
void CD2DGradientDlg::CreateLinearGradientBrush()
{
D2D1_GRADIENT_STOP stops[] =
{
{ 0.0f, ColorF(227.0f / 255.0f, 9.0f / 255.0f, 64.0f / 255.0f, 1.0f) },
{ 0.33f, ColorF(231.0f / 255.0f, 215.0f / 255.0f, 2.0f / 255.0f, 1.0f) },
{ 0.66f, ColorF(15.0f / 255.0f, 168.0f / 255.0f, 149.0f / 255.0f, 1.0f) },
{ 1.0f, ColorF(19.0f / 255.0f, 115.0f / 255.0f, 232.0f / 255.0f, 1.0f) }
};
ComPtr<ID2D1GradientStopCollection> collection;
HR(m_Target->CreateGradientStopCollection(stops, _countof(stops),
collection.GetAddressOf()));
D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = {};
HR(m_Target->CreateLinearGradientBrush(props, collection.Get(),
m_LinearBrush.ReleaseAndGetAddressOf()));
}
In the drawing, code remains unchanged except for the end point's y
coordinate which is changed to 0
to create a horizontal gradient.
m_LinearBrush->SetStartPoint(Point2F(0.0f, 0.0f));
m_LinearBrush->SetEndPoint(Point2F(size.width, 0.0f));
This is the rainbow gradient we created.
Rainbow Linear Gradient Text
In this section, we look at how to apply the gradient brush to text. In Direct2D, the brush can be applied to any drawing whose function accepts a brush parameter. To display text with DrawText
, a device independent resource, IDWriteTextFormat
, has to created with CreateTextFormat()
from the DirectWrite
factory.
ComPtr<IDWriteTextFormat> m_TextFormat;
void CD2DAffineTransformDlg::CreateDeviceIndependentResources()
{
HR(FactorySingleton::GetDWriteFactory()->CreateTextFormat(L"Arial Black",
nullptr, DWRITE_FONT_WEIGHT_ULTRA_BOLD, DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL, 40, L"",
m_TextFormat.ReleaseAndGetAddressOf()));
}
To draw text, the FillRectangle()
in the above drawing code is replaced by DrawText()
.
void CD2DGradientDlg::DrawLinearGradientText()
{
auto size = m_Target->GetSize();
m_LinearBrush->SetStartPoint(Point2F(0.0f, 0.0f));
m_LinearBrush->SetEndPoint(Point2F(size.width, 0.0f));
auto r = RectF(0.0f, 0.0f, size.width, size.height);
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(),
&r, m_LinearBrush.Get());
}
This is gradient text output.
Radial Gradient
In this section, we'll show how to create and use a radial gradient brush. Its creation function is almost similar to the linear one, except the functions are related to radial gradient brush. Notice, in D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES
, its center point is set.
ComPtr<ID2D1RadialGradientBrush> m_RadialBrush;
void CD2DGradientDlg::CreateRadialGradientBrush()
{
D2D1_GRADIENT_STOP stops[] =
{
{ 0.0f, ColorF(ColorF::Cyan) },
{ 1.0f, ColorF(ColorF::DarkBlue) }
};
ComPtr<ID2D1GradientStopCollection> collection;
HR(m_Target->CreateGradientStopCollection(stops, _countof(stops),
collection.GetAddressOf()));
D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props = {};
props.center = Point2F(50.0f, 50.0f);
HR(m_Target->CreateRadialGradientBrush(props, collection.Get(),
m_RadialBrush.ReleaseAndGetAddressOf()));
}
Then FillRectangle()
is called with the radial gradient brush.
void CD2DGradientDlg::DrawRadialGradientRect()
{
auto size = m_Target->GetSize();
auto radius = min(size.width, size.height);
m_RadialBrush->SetRadiusX(radius);
m_RadialBrush->SetRadiusY(radius);
m_Target->FillRectangle(RectF(0.0f, 0.0f, size.width, size.height),
m_RadialBrush.Get());
}
Radial Gradient Text
To draw text with radial gradient brush, the code is the same as linear gradient text, except the radial gradient brush is passed to DrawText()
.
void CD2DGradientDlg::DrawRadialGradientText()
{
auto size = m_Target->GetSize();
auto radius = min(size.width, size.height);
m_RadialBrush->SetRadiusX(radius);
m_RadialBrush->SetRadiusY(radius);
auto r = RectF(0.0f, 0.0f, size.width, size.height);
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(),
&r, m_RadialBrush.Get());
}
Demo Code
All the code shown in the article is put in one single demo. To see certain gradient demo, just comment and uncomment the function you want to see in the Draw()
.
void CD2DGradientDlg::Draw()
{
m_Target->Clear(ColorF(ColorF::White));
DrawRadialGradientText();
}
History
- 18th September, 2020: First release
Articles in the Series