Import .ttf

Jun 1, 2013 at 12:47 AM
Is it possible to use downloaded .ttf's with this wrapper? If so, how does one go about importing them?
Coordinator
Jun 1, 2013 at 1:31 AM
Edited Jun 1, 2013 at 1:33 AM
They can be used by importing them into DirectWrite and creating text-layouts for them.
Here's an example.
// CustomFont.cpp

#include <D3D11.h>
#include "FW1FontWrapper.h"

#pragma comment (lib, "D3D11.lib")
#pragma comment (lib, "FW1FontWrapper.lib")

// TODO: Custom font settings
#define CUSTOMFONT_FILEPATH L"../Aegyptus312.otf"
#define CUSTOMFONT_NAME L"Aegyptus"

#include <string>

// Font enumerator wrapper for a single font
class CFontEnum : public IDWriteFontFileEnumerator {
    public:
        virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
            if(ppvObject == NULL)
                return E_INVALIDARG;
            
            if(IsEqualIID(riid, __uuidof(IUnknown))) {
                *ppvObject = static_cast<IUnknown*>(this);
                AddRef();
                return S_OK;
            }
            else if(IsEqualIID(riid, __uuidof(IDWriteFontFileEnumerator))) {
                *ppvObject = static_cast<IDWriteFontFileEnumerator*>(this);
                AddRef();
                return S_OK;
            }
            
            *ppvObject = NULL;
            return E_NOINTERFACE;
        }
        
        virtual ULONG STDMETHODCALLTYPE AddRef() {
            return static_cast<ULONG>(InterlockedIncrement(reinterpret_cast<LONG*>(&m_cRefCount)));
        }
        
        virtual ULONG STDMETHODCALLTYPE Release() {
            ULONG newCount = static_cast<ULONG>(InterlockedDecrement(reinterpret_cast<LONG*>(&m_cRefCount)));
            
            if(newCount == 0)
                delete this;
            
            return newCount;
        }
        
        virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(IDWriteFontFile **ppFontFile) {
            if(ppFontFile == NULL)
                return E_INVALIDARG;
            
            if(m_pFontFile == NULL)
                return E_FAIL;
            
            m_pFontFile->AddRef();
            *ppFontFile = m_pFontFile;
            
            return S_OK;
        }
        
        virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL *pHasCurrentFile) {
            if(pHasCurrentFile == NULL)
                return E_INVALIDARG;
            
            if(m_count > 0)
                *pHasCurrentFile = FALSE;
            else
                *pHasCurrentFile = TRUE;
            
            ++m_count;
            
            return S_OK;
        }
    
    public:
        CFontEnum(IDWriteFontFile *pFontFile) :
            m_cRefCount(1),
            m_pFontFile(pFontFile),
            m_count(0)
        {
            if(m_pFontFile)
                m_pFontFile->AddRef();
        }
    
    private:
        ~CFontEnum() {
            if(m_pFontFile)
                m_pFontFile->Release();
        }
    
    private:
        ULONG                       m_cRefCount;
        IDWriteFontFile             *m_pFontFile;
        UINT                        m_count;
    
    private:
        CFontEnum(const CFontEnum&);
        CFontEnum& operator=(const CFontEnum&);
};

// Font collection loader for a single font
class CCollectionLoader : public IDWriteFontCollectionLoader {
    public:
        virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
            if(ppvObject == NULL)
                return E_INVALIDARG;
            
            if(IsEqualIID(riid, __uuidof(IUnknown))) {
                *ppvObject = static_cast<IUnknown*>(this);
                AddRef();
                return S_OK;
            }
            else if(IsEqualIID(riid, __uuidof(IDWriteFontCollectionLoader))) {
                *ppvObject = static_cast<IDWriteFontCollectionLoader*>(this);
                AddRef();
                return S_OK;
            }
            
            *ppvObject = NULL;
            return E_NOINTERFACE;
        }
        
        virtual ULONG STDMETHODCALLTYPE AddRef() {
            return static_cast<ULONG>(InterlockedIncrement(reinterpret_cast<LONG*>(&m_cRefCount)));
        }
        
        virtual ULONG STDMETHODCALLTYPE Release() {
            ULONG newCount = static_cast<ULONG>(InterlockedDecrement(reinterpret_cast<LONG*>(&m_cRefCount)));
            
            if(newCount == 0)
                delete this;
            
            return newCount;
        }
        
        virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
            IDWriteFactory *pFactory,
            const void *collectionKey,
            UINT32 collectionKeySize,
            IDWriteFontFileEnumerator **ppFontFileEnumerator
        ) {
            collectionKey;
            collectionKeySize;
            
            if(pFactory == NULL || ppFontFileEnumerator == NULL)
                return E_INVALIDARG;
            
            IDWriteFontFile *pFontFile;
            HRESULT hResult = pFactory->CreateFontFileReference(m_filepath.c_str(), NULL, &pFontFile);
            if(FAILED(hResult))
                return hResult;
            
            CFontEnum *pEnum = new CFontEnum(pFontFile);
            *ppFontFileEnumerator = pEnum;
            
            pFontFile->Release();
            
            return S_OK;
        }
    
    public:
        CCollectionLoader(const WCHAR *szFontfilePath) :
            m_cRefCount(1),
            m_filepath(szFontfilePath)
        {
        }
    
    private:
        ~CCollectionLoader() {
        }
    
    private:
        ULONG                       m_cRefCount;
        std::wstring                m_filepath;
    
    private:
        CCollectionLoader(const CCollectionLoader&);
        CCollectionLoader& operator=(const CCollectionLoader&);
};


LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Main
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // Register windowclass
    WNDCLASSEX wc = {0};
    wc.cbSize = sizeof(wc);
    wc.lpszClassName = TEXT("MyClass");
    wc.hInstance = hInstance;
    wc.lpfnWndProc = WndProc;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassEx(&wc);
    
    // Create window
    HWND hWnd = CreateWindowEx(
        WS_EX_OVERLAPPEDWINDOW,
        wc.lpszClassName,
        TEXT("D3D11 Font Wrapper - Custom Font"),
        WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );
    
    // Create device and swapchain
    DXGI_SWAP_CHAIN_DESC scd = {0};
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    scd.SampleDesc.Count = 1;
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scd.BufferCount = 1;
    scd.OutputWindow = hWnd;
    scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    scd.Windowed = TRUE;
    
    IDXGISwapChain *pSwapChain;
    ID3D11Device *pDevice;
    ID3D11DeviceContext *pImmediateContext;
    
    HRESULT hResult = D3D11CreateDeviceAndSwapChain(
        NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        0,
        NULL,
        0,
        D3D11_SDK_VERSION,
        &scd,
        &pSwapChain,
        &pDevice,
        NULL,
        &pImmediateContext
    );
    if(FAILED(hResult)) {
        MessageBox(NULL, TEXT("D3D11CreateDeviceAndSwapChain"), TEXT("Error"), MB_OK);
        return 0;
    }
    
    // Render target
    ID3D11Texture2D *pBackBuffer;
    pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
    
    ID3D11RenderTargetView *pRTV;
    pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRTV);
    
    D3D11_TEXTURE2D_DESC bd;
    pBackBuffer->GetDesc(&bd);
    
    pBackBuffer->Release();
    
    // Viewport
    D3D11_VIEWPORT vp = {0};
    vp.Width = static_cast<FLOAT>(bd.Width);
    vp.Height = static_cast<FLOAT>(bd.Height);
    vp.MaxDepth = 1.0f;
    pImmediateContext->RSSetViewports(1, &vp);
    
    // Create the font-wrapper
    IFW1Factory *pFW1Factory;
    hResult = FW1CreateFactory(FW1_VERSION, &pFW1Factory);
    if(FAILED(hResult)) {
        MessageBox(NULL, TEXT("FW1CreateFactory"), TEXT("Error"), MB_OK);
        return 0;
    }
    
    IFW1FontWrapper *pFontWrapper;
    hResult = pFW1Factory->CreateFontWrapper(pDevice, L"Arial", &pFontWrapper);
    if(FAILED(hResult)) {
        MessageBox(NULL, TEXT("CreateFontWrapper"), TEXT("Error"), MB_OK);
        return 0;
    }
    
    pFW1Factory->Release();
    
    // Get DWrite factory
    IDWriteFactory *pDWriteFactory;
    hResult = pFontWrapper->GetDWriteFactory(&pDWriteFactory);
    
    // Set up custom font collection
    IDWriteFontCollectionLoader *pCollectionLoader = new CCollectionLoader(CUSTOMFONT_FILEPATH);
    
    hResult = pDWriteFactory->RegisterFontCollectionLoader(pCollectionLoader);
    if(FAILED(hResult)) {
        MessageBox(NULL, TEXT("RegisterFontCollectionLoader"), TEXT("Error"), MB_OK);
        return 0;
    }
    
    IDWriteFontCollection *pFontCollection;
    hResult = pDWriteFactory->CreateCustomFontCollection(pCollectionLoader, NULL, 0, &pFontCollection);
    if(FAILED(hResult)) {
        MessageBox(NULL, TEXT("CreateCustomFontCollection"), NULL, MB_OK);
        return 0;
    }
    
    // Create the default DWrite text format for the text layout
    IDWriteTextFormat *pTextFormat;
    hResult = pDWriteFactory->CreateTextFormat(
        CUSTOMFONT_NAME,
        pFontCollection,// Use custom font collection
        DWRITE_FONT_WEIGHT_NORMAL,
        DWRITE_FONT_STYLE_NORMAL,
        DWRITE_FONT_STRETCH_NORMAL,
        32.0f,
        L"",
        &pTextFormat
    );
    
    // Create a text layout for a string
    IDWriteTextLayout *pTextLayout;
    const WCHAR str[] = L"test string 12345f!!";
    hResult = pDWriteFactory->CreateTextLayout(
        str,
        sizeof(str)/sizeof(str[0]),
        pTextFormat,
        0.0f,
        0.0f,
        &pTextLayout
    );
    pTextLayout->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
    
    pFontCollection->Release();
    pDWriteFactory->UnregisterFontCollectionLoader(pCollectionLoader);
    pCollectionLoader->Release();
    pDWriteFactory->Release();
    
    // Main loop
    ShowWindow(hWnd, nCmdShow);
    
    bool loop = true;
    while(loop) {
        MSG msg;
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
            if(msg.message == WM_QUIT)
                loop = false;
            else {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        else {
            pImmediateContext->OMSetRenderTargets(1, &pRTV, NULL);
            
            FLOAT backgroundColor[4] = {0.2f, 0.3f, 0.4f, 1.0f};
            pImmediateContext->ClearRenderTargetView(pRTV, backgroundColor);
            
            FLOAT posX = 100.0f;
            FLOAT posY = 50.0f;
            
            // Draw the text layout
            pFontWrapper->DrawTextLayout(pImmediateContext, pTextLayout, posX, posY, 0xffffffff, 0);
            
            // Present
            pSwapChain->Present(0, 0);
        }
    }
    
    // Release
    pSwapChain->SetFullscreenState(FALSE, NULL);
    
    pImmediateContext->ClearState();
    
    pTextFormat->Release();
    pTextLayout->Release();
    
    pFontWrapper->Release();
    
    pRTV->Release();
    
    pImmediateContext->Flush();
    pImmediateContext->Release();
    pDevice->Release();
    pSwapChain->Release();
    
    UnregisterClass(wc.lpszClassName, hInstance);
    
    return 0;
}

// Window procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {
        case WM_DESTROY:
            PostQuitMessage(0);
        return 0;
    }
    
    return DefWindowProc(hWnd, msg, wParam, lParam);
}
Jun 1, 2013 at 2:09 AM
Works like a charm! Thanks for such a quick reply!