Direct2D Tutorial Part 3: Affine Transforms

 

 

Table of Content

The example code is hosted at Github.

Introduction

In this article, we’ll look at how to do affine transform using matrices in Direct2D. The transformation has to be set up before any drawing that is to be transformed. The prerequisite of the article is the knowledge to set up the RenderTarget. If you haven’t got a clue what RenderTarget is, please go read the RenderTarget article first and then come back to read this article.

Text Format

To display the text in Direct2D, IDWriteTextFormat has to be created first. IDWriteTextFormat is a device-independent resource that is created in CreateDeviceIndependentResources() which is in turn called once by OnInitDialog() or in any initialization function you may have. A device-independent resource does not need to be recreated when the Direct2D target is lost. IDWriteTextFormat and its creation function, CreateTextFormat() shall be examined in more detail in a future text drawing tutorial.

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()));
}

Translation

d2d_trans

In this section, the text is translated (or moved) downward along the y-axis by 50 pixels. Before SetTransform() is set with our translation matrix, it has to be called with IdentityMatrix() to reset whatever matrix set prior to this stage. The translate matrix is created from Matrix3x2F::Translation(). The Matrix3x2F::Translation()‘s 2 parameters are the amount of X and Y coordinates to ‘move’ from the current point. Then m_FillBrush is set to a Direct2D predefined black color. You can choose other predefined or custom colors. To define a custom color to be used in SetColor(), give ColorF() 4 floating-point numbers in RGBA order. Then to draw the text, DrawTextW is called on the m_Target.

CRect rectClient;
GetClientRect(&rectClient);

auto rect = RectF(0.0f, 0.0f, rectClient.Width(), rectClient.Height());

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);

m_Target->SetTransform(trans);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(), &rect, m_FillBrush.Get());

Skew

d2d_skew

Next, we’ll see how to do a skew to make the text look italic and then followed by the same translation. GetClientRect() code from the previous section is not shown as they are unchanged. The transformations are chained by the matrix multiplication. You see the order of matrix multiplication is very important here. The order of matrix multiplication must be the opposite of the order of the desired transformation. For instance, we want the skew to be the first transformation, then in the matrix multiplication, then the skew matrix has to be the last operand. Vice-versa for the translation matrix. See the skew matrix is created from Matrix3x2F::Skew(). The Matrix3x2F::Skew()‘s first 2 parameters are the angle(degree) to skew the along the x-axis and y-axis and the last parameter is the center point of skew. Note: The translation matrix creation is discussed above.

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);
D2D1::Matrix3x2F skew = D2D1::Matrix3x2F::Skew(-10.0f, 0.0f, Point2F(rectClient.Width() / 2, rectClient.Height() / 2));

m_Target->SetTransform(trans * skew);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(), &rect, m_FillBrush.Get());

Rotation

d2d_rotate

In this section, the text is rotated upward by -10 degrees. The skew and rotation has to be performed before translation, therefore the matrix multiplication is trans * rotate * skew. The rotate matrix is created from Matrix3x2F::Rotation() which has an angle as its first parameter. The optional center point parameter defaults to 0,0 when left out.

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);
D2D1::Matrix3x2F rotate = D2D1::Matrix3x2F::Rotation(-10.0f);
D2D1::Matrix3x2F skew = D2D1::Matrix3x2F::Skew(-10.0f, 0.0f, Point2F(rectClient.Width() / 2, rectClient.Height() / 2));

m_Target->SetTransform(trans * rotate * skew);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(), &rect, m_FillBrush.Get());

Scale

d2d_scale

Scaling is normally used to implement zoom-in and zoom-out in computer drawing. In this last section, we’ll scale down the text drawing(make smaller). Scale has to be performed before all other transformation, so it is the last operand in the matrix multiplication. See the scale matrix is created from Matrix3x2F::Scale() which has 2 parameters to specify the scaling in the x-axis and y-axis.

m_Target->SetTransform(D2D1::IdentityMatrix());

D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(0, 50);
D2D1::Matrix3x2F rotate = D2D1::Matrix3x2F::Rotation(-10.0f);
D2D1::Matrix3x2F skew = D2D1::Matrix3x2F::Skew(-10.0f, 0.0f, Point2F(rectClient.Width() / 2, rectClient.Height() / 2));
D2D1::Matrix3x2F scale = D2D1::Matrix3x2F::Scale(0.6f, 0.6f);

m_Target->SetTransform(trans * rotate * skew * scale);

m_FillBrush->SetColor(ColorF(ColorF::Black));
m_Target->DrawTextW((LPCTSTR)m_Text, m_Text.GetLength(), m_TextFormat.Get(), &rect, m_FillBrush.Get());

Other articles in the series

 

2 thoughts on “Direct2D Tutorial Part 3: Affine Transforms

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close