Jump to content
  • Advertisement
Sign in to follow this  
Rockaway

DX12 Direct2D/DirectWrite Text Resolution

This topic is 702 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey,

 

I've just been playing about with Direct2D this afternoon, and I've moved on to using DIrectWrite for outputting my text.

 

All easy enough, but I can't for the life of me figure out how to increase the resolution of the text. Anything I draw to the screen with Direct2D scales nicely, but text doesn't.

 

I have two screens, one at 1680x1050, the other at 3840x2160 and it is quite noticeable on the higher resolution screen.

 

[attachment=33027:D2D_Resolution.jpg]

 

You can see the difference between the window title, and the sample text i've done with DirectWrite.

 

Anyone shed any light on this?

 

The code follows, i've removed the extraneous extra code to focus on the DirectWrite stuff.

 

Thanks.

#pragma once

#include <d2d1.h>
#include <dwrite.h>
#include <string.h>
#include <Windows.h>

    template<class Interface>
    inline void SafeRelease( Interface **ppInterfaceToRelease )
    {
        if ( *ppInterfaceToRelease != NULL )
        {
            ( *ppInterfaceToRelease )->Release( );

            ( *ppInterfaceToRelease ) = NULL;
        }
    }

class Application
{
    // ================================================================
    // --> FIELD
    // ================================================================

        private : FLOAT                  m_dpiX;
        private : FLOAT                  m_dpiY;
        private : HWND                   m_hWnd;
        private : ID2D1Factory*          m_pDirect2dFactory;
        private : ID2D1HwndRenderTarget* m_pRenderTarget;
        private : ID2D1SolidColorBrush*  m_pLightSlateGrayBrush;
        private : IDWriteFactory*        m_pDWriteFactory;
        private : IDWriteTextFormat*     m_pTextFormat;
        private : IDWriteTextLayout*     m_pTextLayout;
                  

    // ================================================================
    // --> CONSTRUCTOR
    // ================================================================

        public : Application( );

    // ================================================================
    // --> METHOD
    // ================================================================
 
        // METHOD -> CreateDeviceIndependentResources()
        private : HRESULT CreateDeviceIndependentResources( );

        // METHOD -> CreateDeviceDependentResources()
        private : HRESULT CreateDeviceDependentResources( );

        // METHOD -> DiscardDeviceDependentResources()
        private : void DiscardDeviceDependentResources( );

        // METHOD -> Initialise()
        public : HRESULT Initialise( HINSTANCE hInstance );

        // METHOD -> MessageLoop()
        public : void MessageLoop( );

        // METHOD -> OnRender()
        private : HRESULT OnRender( );

        // METHOD -> OnRender()
        private: void OnResize( UINT height, UINT width );

        // METHOD -> Procedure()
        private : static LRESULT CALLBACK Procedure( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );

    // ================================================================
    // --> DESTRUCTOR
    // ================================================================

        public : ~Application( );
};
#include "Application.h"

// ================================================================
// CONSTRUCTOR
// ================================================================

    // PUBLIC
    Application::Application( ) : m_hWnd( NULL ),
                                  m_pDirect2dFactory( NULL ),
                                  m_pRenderTarget( NULL ),
                                  m_pLightSlateGrayBrush( NULL ),
                                  m_pDWriteFactory( NULL ),
                                  m_pTextFormat( NULL )
    {

    }

// ================================================================
// METHOD -> CreateDeviceIndependentResources()
// ================================================================

    // PRIVATE
    HRESULT Application::CreateDeviceIndependentResources( )
    {
        HRESULT hr = S_OK;

        hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory );

        if ( SUCCEEDED( hr ) )
        {
            hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED,
                                      __uuidof( IDWriteFactory ),
                                      reinterpret_cast<IUnknown**>( &m_pDWriteFactory ) );
        }

        if ( SUCCEEDED( hr ) )
        {
            hr = m_pDWriteFactory->CreateTextFormat(
                L"Segoe UI",                // Font family name.
                NULL,                       // Font collection (NULL sets it to use the system font collection).
                DWRITE_FONT_WEIGHT_REGULAR,
                DWRITE_FONT_STYLE_NORMAL,
                DWRITE_FONT_STRETCH_NORMAL,
                12.0f,
                L"en-us",
                &m_pTextFormat
            );  
        }

        return hr;
    }

// ================================================================
// METHOD -> CreateDeviceDependentResources()
// ================================================================

    // PRIVATE
    HRESULT Application::CreateDeviceDependentResources()
    {
        HRESULT hr = S_OK;

        if ( !m_pRenderTarget )
        {
            RECT rc;

            GetClientRect( m_hWnd, &rc );

            D2D1_SIZE_U size = D2D1::SizeU( rc.right - rc.left, rc.bottom - rc.top );

            // Create a Direct2D render target.
            hr = m_pDirect2dFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties( ),
                                                             D2D1::HwndRenderTargetProperties( m_hWnd, size ),
                                                             &m_pRenderTarget );
           

            if ( SUCCEEDED( hr ) )
            {
                // Create a black brush.
                hr = m_pRenderTarget->CreateSolidColorBrush( D2D1::ColorF( D2D1::ColorF( 0.0F, 0.0F, 0.0F, 1.0F ) ),
                    &m_pLightSlateGrayBrush );
            }
        }

        return hr;
    }

// ================================================================
// METHOD -> DiscardDeviceDependentResources()
// ================================================================

    // PRIVATE
    void Application::DiscardDeviceDependentResources( )
    {
        SafeRelease( &m_pRenderTarget );
        SafeRelease( &m_pLightSlateGrayBrush );
        SafeRelease( &m_pDWriteFactory );
        SafeRelease( &m_pTextFormat );
        SafeRelease( &m_pTextLayout );
    }

// ================================================================
// METHOD -> Initialise()
// ================================================================

    // PUBLIC
    HRESULT Application::Initialise( HINSTANCE hInstance )
    {
        HRESULT hr;

        hr = CreateDeviceIndependentResources( );

        if ( SUCCEEDED( hr ) )
        {
            // Register the window class.
            WNDCLASSEX wcex = { sizeof( WNDCLASSEX ) };

            wcex.style = CS_HREDRAW | CS_VREDRAW;
            wcex.lpfnWndProc = Application::Procedure;
            wcex.cbClsExtra = 0;
            wcex.cbWndExtra = sizeof( LONG_PTR );
            wcex.hInstance = hInstance;
            wcex.hbrBackground = NULL;
            wcex.lpszMenuName = NULL;
            wcex.hCursor = LoadCursor( NULL, IDI_APPLICATION );
            wcex.lpszClassName = L"DirectX 12 Application";

            RegisterClassEx( &wcex );

            m_pDirect2dFactory->GetDesktopDpi( &m_dpiX, &m_dpiY );

            // Create the window.
            m_hWnd = CreateWindow( L"DirectX 12 Application",
                L"DirectX 12 Application",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                1024,
                768,
                NULL,
                NULL,
                hInstance,
                this
            );

            hr = m_hWnd ? S_OK : E_FAIL;

            if ( SUCCEEDED( hr ) )
            {
                ShowWindow( m_hWnd, SW_SHOWNORMAL );
                UpdateWindow( m_hWnd );
            }
        }

        return hr;
    }

// ================================================================
// // METHOD -> MessageLoop()
// ================================================================

    // PUBLIC
    void Application::MessageLoop( )
    {
        MSG msg;

        while ( GetMessage( &msg, NULL, 0, 0 ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }

// ================================================================
// METHOD -> OnRender()
// ================================================================

    // PRIVATE
    HRESULT Application::OnRender( )
    {
        HRESULT hr = S_OK;

        hr = CreateDeviceDependentResources( );

        if ( SUCCEEDED( hr ) )
        {
            m_pRenderTarget->BeginDraw( );

            m_pRenderTarget->SetTransform( D2D1::Matrix3x2F::Identity( ) );

            m_pRenderTarget->Clear( D2D1::ColorF( D2D1::ColorF::White ) );

            D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize( );

            // START : DIRECTWRITE

            // Create a text layout using the text format.
            if ( SUCCEEDED( hr ) )
            {


                D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize( );

                // Align text to centre of layout box.
                m_pTextFormat->SetTextAlignment( DWRITE_TEXT_ALIGNMENT_CENTER );
                m_pTextFormat->SetParagraphAlignment( DWRITE_PARAGRAPH_ALIGNMENT_CENTER );

                const wchar_t* wszText_ = L"DirectX 12 Application";

                UINT32 cTextLength_ = ( UINT32 )wcslen( wszText_ );

                hr = m_pDWriteFactory->CreateTextLayout(
                    wszText_,       // The string to be laid out and formatted.
                    cTextLength_,   // The length of the string.
                    m_pTextFormat,  // The text format to apply to the string (contains font information, etc).
                    300.0F,         // The width of the layout box.
                    100.0F,         // The height of the layout box.
                    &m_pTextLayout  // The IDWriteTextLayout interface pointer.
                );
            }

            m_pRenderTarget->DrawTextLayout(
                D2D1_POINT_2F { ( ( rtSize.width / 2 ) - 150.0F ), ( ( rtSize.height / 2 ) - 50.0F ) },
                m_pTextLayout,
                m_pLightSlateGrayBrush,
                D2D1_DRAW_TEXT_OPTIONS_NONE
            );

            // END : DIRECTWRITE
            // ----------------------------------------------------------------

            hr = m_pRenderTarget->EndDraw( );
        }

        if ( hr == D2DERR_RECREATE_TARGET )
        {
            hr = S_OK;
            DiscardDeviceDependentResources( );
        }

        return hr;
    }

// ================================================================
// METHOD -> OnResize()
// ================================================================

    // PRIVATE
    void Application::OnResize( UINT height, UINT width )
    {
        if ( m_pRenderTarget )
        {
            m_pRenderTarget->Resize( D2D1::SizeU( width, height ) );
        }
    }

// ================================================================
// METHOD -> Procedure()
// ================================================================

    // PRIVATE, STATIC
    LRESULT CALLBACK Application::Procedure( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
        LRESULT result = 0;

        if ( uMsg == WM_CREATE )
        {
            LPCREATESTRUCT pcs = ( LPCREATESTRUCT )lParam;

            Application *pApplication = ( Application * )pcs->lpCreateParams;

            ::SetWindowLongPtrW( hWnd,
                GWLP_USERDATA,
                PtrToUlong( pApplication )
            );

            result = 1;
        }
        else
        {
            Application *pApplication = reinterpret_cast< Application * >( static_cast< LONG_PTR >( ::GetWindowLongPtrW( hWnd, GWLP_USERDATA ) ) );

            bool wasHandled = false;

            if ( pApplication )
            {
                switch ( uMsg )
                {
                    case WM_DESTROY :
                        {
                            PostQuitMessage( 0 );
                        }

                        result = 1;

                        wasHandled = true;

                        break;

                    case WM_DISPLAYCHANGE :
                        {
                            InvalidateRect( hWnd, NULL, FALSE );
                        }

                        result = 0;

                        wasHandled = true;

                        break;

                    case WM_PAINT :
                        {
                            pApplication->OnRender( );

                            ValidateRect( hWnd, NULL );
                        }

                        result = 0;

                        wasHandled = true;

                        break;

                    case WM_SIZE :
                        {
                            UINT height = HIWORD( lParam );
                            UINT width = LOWORD( lParam );
                            
                            pApplication->OnResize( height, width );
                        }

                        result = 0;

                        wasHandled = true;

                        break;
                }
            }

            if ( !wasHandled )
            {
                result = DefWindowProc( hWnd, uMsg, wParam, lParam );
            }
        }

        return result;
    }

    // ================================================================
    // DESTRUCTOR
    // ================================================================

    // PUBLIC
    Application::~Application( )
    {
        SafeRelease( &m_pDirect2dFactory );
        SafeRelease( &m_pRenderTarget );
        SafeRelease( &m_pLightSlateGrayBrush );
        SafeRelease( &m_pDWriteFactory );
        SafeRelease( &m_pTextFormat );
        SafeRelease( &m_pTextLayout );
    }
#include "Application.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow )
{
    HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );

    if ( SUCCEEDED( CoInitialize( NULL ) ) )
    {
        Application App;

        if ( SUCCEEDED( App.Initialise( hInstance ) ) )
        {
            App.MessageLoop( );
        }

        CoUninitialize( );
    }

    return 0;
}

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!