A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/microsoft/DirectXTK/wiki/TextConsole below:

TextConsole · microsoft/DirectXTK Wiki · GitHub

This is a C++ implementation of a simple console for displaying text. As more text is printed, the text display scrolls up.

TextConsole.h

class TextConsole
{
public:
    TextConsole();
    TextConsole(ID3D11DeviceContext* context, const wchar_t* fontName);

    TextConsole(TextConsole&&) = delete;
    TextConsole& operator= (TextConsole&&) = delete;

    TextConsole(TextConsole const&) = delete;
    TextConsole& operator= (TextConsole const&) = delete;

    void Render();

    void Clear();

    void Write(const wchar_t *str);
    void WriteLine(const wchar_t *str);
    void Format(const wchar_t* strFormat, ...);

    void SetWindow(const RECT& layout);

    void XM_CALLCONV SetForegroundColor(DirectX::FXMVECTOR color) { DirectX::XMStoreFloat4(&m_textColor, color); }

    void ReleaseDevice();
    void RestoreDevice(ID3D11DeviceContext* context, const wchar_t* fontName);

    void SetViewport(const D3D11_VIEWPORT& viewPort);

    void SetRotation(DXGI_MODE_ROTATION rotation);   

private:
    void ProcessString(const wchar_t* str);
    void IncrementLine();

    RECT                                            m_layout;
    DirectX::XMFLOAT4                               m_textColor;

    unsigned int                                    m_columns;
    unsigned int                                    m_rows;
    unsigned int                                    m_currentColumn;
    unsigned int                                    m_currentLine;

    std::unique_ptr<wchar_t[]>                      m_buffer;
    std::unique_ptr<wchar_t*[]>                     m_lines;
    std::vector<wchar_t>                            m_tempBuffer;

    std::unique_ptr<DirectX::SpriteBatch>           m_batch;
    std::unique_ptr<DirectX::SpriteFont>            m_font;
    Microsoft::WRL::ComPtr<ID3D11DeviceContext>     m_context;

    std::mutex                                      m_mutex;
};

TextConsole.cpp

#include "TextConsole.h"

#include <assert.h>

using Microsoft::WRL::ComPtr;

using namespace DirectX;

TextConsole::TextConsole()
    : m_textColor(1.f, 1.f, 1.f, 1.f)
{
    Clear();
}

TextConsole::TextConsole(ID3D11DeviceContext* context, const wchar_t* fontName)
    : m_textColor(1.f, 1.f, 1.f, 1.f)
{
    RestoreDevice(context, fontName);

    Clear();
}

void TextConsole::Render()
{
    std::lock_guard<std::mutex> lock(m_mutex);

    float lineSpacing = m_font->GetLineSpacing();

    float x = float(m_layout.left);
    float y = float(m_layout.top);

    XMVECTOR color = XMLoadFloat4(&m_textColor);

    m_batch->Begin();

    unsigned int textLine = unsigned int(m_currentLine - m_rows + m_rows + 1) % m_rows;

    for (unsigned int line = 0; line < m_rows; ++line)
    {
        XMFLOAT2 pos(x, y + lineSpacing * float(line));

        if (*m_lines[textLine])
        {
            m_font->DrawString(m_batch.get(), m_lines[textLine], pos, color);
        }

        textLine = unsigned int(textLine + 1) % m_rows;
    }

    m_batch->End();
}

void TextConsole::Clear()
{
    if (m_buffer)
    {
        memset(m_buffer.get(), 0, sizeof(wchar_t) * (m_columns + 1) * m_rows);
    }

    m_currentColumn = m_currentLine = 0;
}

void TextConsole::Write(const wchar_t *str)
{
    std::lock_guard<std::mutex> lock(m_mutex);

    ProcessString(str);
}

void TextConsole::WriteLine(const wchar_t *str)
{
    std::lock_guard<std::mutex> lock(m_mutex);

    ProcessString(str);
    IncrementLine();
}

void TextConsole::Format(const wchar_t* strFormat, ...)
{
    std::lock_guard<std::mutex> lock(m_mutex);

    va_list argList;
    va_start(argList, strFormat);

    auto len = size_t(_vscwprintf(strFormat, argList) + 1);

    if (m_tempBuffer.size() < len)
        m_tempBuffer.resize(len);

    memset(m_tempBuffer.data(), 0, sizeof(wchar_t) * len);

    vswprintf_s(m_tempBuffer.data(), m_tempBuffer.size(), strFormat, argList);

    va_end(argList);

    ProcessString(m_tempBuffer.data());
}

void TextConsole::SetWindow(const RECT& layout)
{
    m_layout = layout;

    assert(m_font != 0);

    float lineSpacing = m_font->GetLineSpacing();
    unsigned int rows = std::max<unsigned int>(1, static_cast<unsigned int>(float(layout.bottom - layout.top) / lineSpacing));

    RECT fontLayout = m_font->MeasureDrawBounds(L"X", XMFLOAT2(0,0));
    unsigned int columns = std::max<unsigned int>(1, static_cast<unsigned int>(float(layout.right - layout.left) / float(fontLayout.right - fontLayout.left)));

    std::unique_ptr<wchar_t[]> buffer(new wchar_t[(columns + 1) * rows]);
    memset(buffer.get(), 0, sizeof(wchar_t) * (columns + 1) * rows);

    std::unique_ptr<wchar_t*[]> lines(new wchar_t*[rows]);
    for (unsigned int line = 0; line < rows; ++line)
    {
        lines[line] = buffer.get() + (columns + 1) * line;
    }

    if (m_lines)
    {
        unsigned int c = std::min<unsigned int>(columns, m_columns);
        unsigned int r = std::min<unsigned int>(rows, m_rows);

        for (unsigned int line = 0; line < r; ++line)
        {
            memcpy(lines[line], m_lines[line], c * sizeof(wchar_t));
        }
    }

    std::swap(columns, m_columns);
    std::swap(rows, m_rows);
    std::swap(buffer, m_buffer);
    std::swap(lines, m_lines);
}

void TextConsole::ReleaseDevice()
{
    m_batch.reset();
    m_font.reset();
    m_context.Reset();
}

void TextConsole::RestoreDevice(ID3D11DeviceContext* context, const wchar_t* fontName)
{
    m_context = context;

    m_batch = std::make_unique<SpriteBatch>(context);

    ComPtr<ID3D11Device> device;
    context->GetDevice(device.GetAddressOf());

    m_font = std::make_unique<SpriteFont>(device.Get(), fontName);

    m_font->SetDefaultCharacter(L' ');
}

void TextConsole::SetViewport(const D3D11_VIEWPORT& viewPort)
{
    if (m_batch)
    {
        m_batch->SetViewport(viewPort);
    }
}


void TextConsole::SetRotation(DXGI_MODE_ROTATION rotation)
{
    if (m_batch)
    {
        m_batch->SetRotation(rotation);
    }
}

void TextConsole::ProcessString(const wchar_t* str)
{
    if (!m_lines)
        return;

    float width = float(m_layout.right - m_layout.left);

    for (const wchar_t* ch = str; *ch != 0; ++ch)
    {
        if (*ch == '\n')
        {
            IncrementLine();
            continue;
        }

        bool increment = false;

        if (m_currentColumn >= m_columns)
        {
            increment = true;
        }
        else
        {
            m_lines[m_currentLine][m_currentColumn] = *ch;

            auto fontSize = m_font->MeasureString(m_lines[m_currentLine]);
            if (XMVectorGetX(fontSize) > width)
            {
                m_lines[m_currentLine][m_currentColumn] = L'\0';

                increment = true;
            }
        }

        if (increment)
        {
            IncrementLine();
            m_lines[m_currentLine][0] = *ch;
        }

        ++m_currentColumn;
    }
}

void TextConsole::IncrementLine()
{
    if (!m_lines)
        return;

    m_currentLine = (m_currentLine + 1) % m_rows;
    m_currentColumn = 0;
    memset(m_lines[m_currentLine], 0, sizeof(wchar_t) * (m_columns + 1));
}

To use the text console, add a variable to hold the instance:

std::unique_ptr<DX::TextConsole> m_console;

Create it in your initialization:

m_console = std::make_unique<DX::TextConsole>();

// Optionally set a color other than white with something like:
// m_console->SetForegroundColor(Colors::Yellow);

In the equivalent to CreateDevice / CreateDeviceDependentResources:

m_console->RestoreDevice(context, L"consolas.spritefont");

For best results, consider using a monospaced (non-proportional) font. Proportional fonts will work, but might introduce additional newlines and will have a 'ragged' right edge.

In OnDeviceLost:

m_console->ReleaseDevice();

In the equivalent to CreateResources / CreateWindowSizeDependentResources, provide the pixel rectangle where you want the console text rendered:

RECT size = m_deviceResources->GetOutputSize();

m_console->SetWindow(SimpleMath::Viewport::ComputeTitleSafeArea(size.right, size.bottom));

Then in your Render function after clearing the screen and drawing whatever background image you want.

Wherever you want to add text to the console, use Write, WriteLine, and/or Format:

m_console->WriteLine(L"This is a test");
m_console->WriteLine(L"Line 2");
m_console->Format(L"Time %u, %f ", timer.GetFrameCount(), timer.GetTotalSeconds());

If you want to empty the console text, call Clear.

The text console class is thread-safe using a built-in mutex so that you can call Write, WriteLine, Format, or Clear from other threads. Since it uses a SpriteBatch to render, the Render function itself must be run on the same thread that is using the context you provided.

Since Xbox One XDK apps do not have 'lost device' scenarios, you can avoid using RestoreDevice and ReleaseDevice, and just use the alternate constructor in CreateDevice / CreateDeviceDependentResources:

m_console = std::make_unique<DX::TextConsole>(context, L"consolas.spritefont");

The example above uses the Viewport function ComputeTitleSafeArea which is important when rendering text or other UI element on televisions. This is of course optional when rendering on a PC or mobile device and can use the full render viewport instead.

For 11.X Fast Semantics support, you need to call SetViewport before rendering. This is optional for other platforms.

auto viewport = m_deviceResources->GetScreenViewport();
m_console->SetViewport(viewport);

For UWP apps, be sure to set the rotation for mobile devices, laptops, tablets, etc.:

m_console->SetRotation( m_deviceResources->GetRotation() );

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4