Introduction à DirectX 10 – Écrire du texte à l’écran (système de polices) – partie 7

directx9c

Hello

Utilisation de BMFont :

BMFont

 

Intro :

Pour afficher du texte dans une application DirectX il faut procéder comme suit.

Prérequis :

– Savoir initialiser DirectX 10

– Savoir comment afficher une image 2D à l’écran

Septième partie :

Afficher du texte à l’écran.

Explications :

Il vous faudra plusieurs images bitmap pour supporter les différentes résolutions de l’écran de l’utilisateur.

« Their source rect will form our texture coordinates, and their destination rect will form our vertexcoordinates. »

 

Voici le fichier FontTextManager.h :

#ifndef FONT_TEXT_MANAGER_H
#define FONT_TEXT_MANAGER_H

#include <d3dx10math.h>
#include <vector>
#include <map>
#include <string>
#include <fstream>

#include "Singleton.h"
#include "Defines.h"
#include "Types.h"

namespace FontSystem
{
    struct FontTextFileCharacter
    {
        FontTextFileCharacter() :
        iXPos(0),
        iYPos(0),
        iWidth(0),
        iHeight(0),
        iXOffset(0),
        iYOffset(0),
        iXAdvance(0),
        iPage(0)
        {
        }

        uint16 iXPos, iYPos;
        uint16 iWidth, iHeight;
        float iXOffset, iYOffset;
        float iXAdvance;
        uint16 iPage;
    };

    struct PTPVertex
    {
        D3DXVECTOR3 position;
        D3DXVECTOR2 texture;
        int page;
    };

    struct Font
    {
        std::string sFontTextName;
        uint16 iLineHeight;
        uint16 iBase;
        uint16 iWidth; // Taille en largeur de l'image de la police
        uint16 iHeight; // Taille en hauteur de l'image de la police
        uint16 iPagesCount;
        int16 iSize;

        // Un tableau de caractères constituants la police de font
        FontTextFileCharacter* aCharacters;
        // Un tableau contenant les fichiers shader ressources  (les pages !) en l'occurence les textures de la police de font
        ID3D10ShaderResourceView* texturesArray;
    };

    class Text
    {
    public:
        Text(const std::wstring m_sText, const D3DXCOLOR& color, float fPosX, float fPosY);
        virtual ~Text();
    
        void SetFont(Font* pFont);
        Font* GetFont();

        float GetPosX();
        float GetPosY();

        std::wstring GetText();
    
        void SetVertexBuffer(ID3D10Buffer* pBuffer);
        void SetIndexBuffer(ID3D10Buffer* pBuffer);

        ID3D10Buffer* GetVertexBuffer();
        ID3D10Buffer* GetIndexBuffer();

        D3DXCOLOR GetColor();

        size_t GetVertexCount();
        size_t GetIndexCount();

        void SetVertexCount(size_t iCount);
        void SetIndexCount(size_t iCount);

        void SetTransparency(float fAlpha);

    private:
        std::wstring m_sText;

        float m_fPosX;
        float m_fPosY;

        D3DXCOLOR m_color;

        Font* m_pFont;

        // Un vertex / index buffer par page
        ID3D10Buffer* m_pVertexBuffer;
        ID3D10Buffer* m_pIndexBuffer;

        size_t m_iVertexCount;
        size_t m_iIndexCount;
    };
}

using namespace FontSystem;

class FontTextManager : public Singleton<FontTextManager>
{
public : // todo : mettre des commentaires partout ; utiliser AlphaTransparencyPass
    FontTextManager();
    virtual ~FontTextManager();
    
    bool Initialize();

    void Render(Text* pText);

    bool LoadFontTextFile(const std::string& sFileName, const std::string& sFontTextName);
    bool IsFontTextLoaded(const std::string& sFontTextName);

    Text* CreateText(const std::wstring& sText, const std::string& sFontTextName, const float fPosX, const float fPosY,
        const D3DXCOLOR& color);

    float GetGlyphAspectRatio(const wchar_t* c, const std::string& sFontTextName);
    RECT GetGlyphTexCoords(const wchar_t* c, const std::string& sFontTextName);
    uint16 GetCharacterPage(const wchar_t* c, const std::string& sFontTextName);

private:
    void CreateVertexInputLayout();
    void SetupMatrix();
    bool BuildTextBuffers(Text* text);
    bool InitializeShader();

    ID3D10Texture2D* CreateTexture(const std::string& sBitmapFileName);
    ID3D10Texture2D* CreateTextureArray(std::vector<ID3D10Texture2D*>& textures);
    ID3D10ShaderResourceView* GetTextureRVArray(ID3D10Texture2D* pTexArray);

private:
    D3D10_INPUT_ELEMENT_DESC* m_pLayoutPT; // todo : enlever
    ID3D10InputLayout* m_pVertexLayout;

    std::map<std::string, Font*> m_fonts;

    ID3D10Effect* m_pEffect;
    ID3D10EffectTechnique* m_pTechnique;

    ID3D10EffectShaderResourceVariable* m_pBitmapVariable;

    ID3D10EffectMatrixVariable* m_pWorldVariable;
    ID3D10EffectMatrixVariable* m_pViewVariable;
    ID3D10EffectMatrixVariable* m_pProjVariable;
    ID3D10EffectVectorVariable* m_pColorVariable;

    D3DXMATRIX m_worldMatrix;
    D3DXMATRIX m_viewMatrix;
    D3DXMATRIX m_projMatrix;
};

#endif

 

Voici le fichier FontTextManager.cpp :

#include "FontTextManager.h"
#include "D3D10Renderer.h"
#include "AlphaPass.h"

Text::Text(const std::wstring sText, const D3DXCOLOR& color, float fPosX, float fPosY) :
m_sText(sText),
m_color(color),
m_fPosX(fPosX),
m_fPosY(fPosY),
m_pFont(nullptr),
m_pIndexBuffer(nullptr),
m_pVertexBuffer(nullptr),
m_iIndexCount(0),
m_iVertexCount(0)
{
}

Text::~Text()
{
    SAFE_RELEASE(m_pVertexBuffer);
    SAFE_RELEASE(m_pIndexBuffer);
}

void Text::SetFont(Font* pFont)
{
    m_pFont = pFont;
}

Font* Text::GetFont()
{
    return m_pFont;
}

std::wstring Text::GetText()
{
    return m_sText;
}

void Text::SetVertexBuffer(ID3D10Buffer* pBuffer)
{
    m_pVertexBuffer = pBuffer;
}

void Text::SetIndexBuffer(ID3D10Buffer* pBuffer)
{
    m_pIndexBuffer = pBuffer;
}

ID3D10Buffer* Text::GetVertexBuffer()
{
    return m_pVertexBuffer;
}

ID3D10Buffer* Text::GetIndexBuffer()
{
    return m_pIndexBuffer;
}

size_t Text::GetVertexCount()
{
    return m_iVertexCount;
}

size_t Text::GetIndexCount()
{
    return m_iIndexCount;
}

void Text::SetVertexCount(size_t iCount)
{
    m_iVertexCount = iCount;
}

void Text::SetIndexCount(size_t iCount)
{
    m_iIndexCount = iCount;
}

D3DXCOLOR Text::GetColor()
{
    return m_color;
}

float Text::GetPosX()
{
    return m_fPosX;
}

float Text::GetPosY()
{
    return m_fPosY;
}

void Text::SetTransparency(float fAlpha)
{
    m_color.a = fAlpha;
}

// ---------------------------------------------//

template<> FontTextManager* Singleton<FontTextManager>::ms_instance = nullptr;

FontTextManager::FontTextManager() :
m_pLayoutPT(nullptr),
m_pBitmapVariable(nullptr),
m_pEffect(nullptr),
m_pTechnique(nullptr),
m_pVertexLayout(nullptr),
m_pWorldVariable(nullptr),
m_pViewVariable(nullptr),
m_pProjVariable(nullptr),
m_pColorVariable(nullptr)
{
}

FontTextManager::~FontTextManager()
{
    SAFE_DELETE(m_pLayoutPT);

    SAFE_RELEASE(m_pVertexLayout);
    SAFE_RELEASE(m_pEffect);
}

bool FontTextManager::Initialize()
{
    CreateVertexInputLayout();

    if (!InitializeShader())
    {
        return false;
    }

    SetupMatrix();

    return true;
}

bool FontTextManager::InitializeShader()
{
    HRESULT hr = S_OK;

    ID3D10Blob* pBlob = nullptr;
 
    hr = D3DX10CreateEffectFromFile(FONT_TEXT_FX_FILE_NAME, nullptr, nullptr, "fx_4_0",
        D3D10_SHADER_ENABLE_STRICTNESS | D3D10_SHADER_DEBUG, 0,
        D3D10_RENDERER->GetDevice(), nullptr, nullptr, &m_pEffect, &pBlob, nullptr);

    if (FAILED(hr))
    {
        if (pBlob)
        {
            // Affiche l'erreur de compilation du shader
            MessageBoxA(nullptr, (PCSTR)pBlob->GetBufferPointer(), "Erreur dans le fichier shader", MB_ICONHAND | MB_OK);
        }
        else
        {
            ShowMessageBoxDXError(hr);
        }
 
        return false;
    }
  

    m_pTechnique = m_pEffect->GetTechniqueByName("FontTechnique");

    m_pWorldVariable = m_pEffect->GetVariableByName("World")->AsMatrix();
    m_pViewVariable = m_pEffect->GetVariableByName("View")->AsMatrix();
    m_pProjVariable = m_pEffect->GetVariableByName("Projection")->AsMatrix();
    m_pBitmapVariable = m_pEffect->GetVariableByName("gTextures")->AsShaderResource();
    m_pColorVariable = m_pEffect->GetVariableByName("BlendColor")->AsVector();

    D3D10_PASS_DESC PassDesc;
    m_pTechnique->GetPassByIndex(0)->GetDesc(&PassDesc);
    hr = D3D10_RENDERER->GetDevice()->CreateInputLayout(m_pLayoutPT, 3, PassDesc.pIAInputSignature,
                                         PassDesc.IAInputSignatureSize, &m_pVertexLayout);

    VR_RETURN(hr);

    return true;
}

void FontTextManager::SetupMatrix()
{
    D3DXMatrixIdentity(&m_worldMatrix);
 
    D3DXVECTOR3 Eye(0.0f, 0.0f, -1.0f);
    D3DXVECTOR3 At(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f);
 
    D3DXMatrixLookAtLH(&m_viewMatrix, &Eye, &At, &Up);

    D3DXMatrixOrthoLH(&m_projMatrix, (float) D3D10_RENDERER->GetViewportWidth(), (float) D3D10_RENDERER->GetViewportHeight(),
        1.0f, 20.0f);
}

void FontTextManager::CreateVertexInputLayout()
{    
    m_pLayoutPT = new D3D10_INPUT_ELEMENT_DESC[3];

    D3D10_INPUT_ELEMENT_DESC layoutPT[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        { "PAGE", 0, DXGI_FORMAT_R16_UINT, 0, 20, D3D10_INPUT_PER_VERTEX_DATA, 0 },
    };

    memcpy(m_pLayoutPT, layoutPT, sizeof(D3D10_INPUT_ELEMENT_DESC) * 3);
}

bool FontTextManager::IsFontTextLoaded(const std::string& sFontTextName)
{
    return m_fonts.count(sFontTextName) != 0;
}
/*
    http://www.angelcode.com/products/bmfont/doc/render_text.html
*/
bool FontTextManager::BuildTextBuffers(Text* pText)
{
    std::string sFontTextName = pText->GetFont()->sFontTextName;

    std::wstring sText = pText->GetText();
    float fPosX = pText->GetPosX();
    float fPosY = -pText->GetPosY();

    // Décalage en fonction de la taille de l'écran
    fPosX -= (float)((D3D10_RENDERER->GetViewportWidth() / 2 ));
    fPosY += (float)((D3D10_RENDERER->GetViewportHeight() / 2 ));

    // On vérifie si l'on a bien la police chargée en mémoire
    if (m_fonts.count(sFontTextName) == 0)
    {
        return false;
    }

    // On obtient la police spécifiée
    Font* pFont = m_fonts[sFontTextName];

    // Tableau de tous les caractères de la police de font
    FontTextFileCharacter* aCharacters = pFont->aCharacters;

    D3D10_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
    D3D10_SUBRESOURCE_DATA vertexData, indexData;

    HRESULT hr;

    std::vector<PTPVertex> vertices;

    for (uint32 i = 0; i < sText.length(); i++)
    {
        // Chaque lettre
        uint32 iLetter = (uint32)sText[i];

        FontTextFileCharacter character = pFont->aCharacters[iLetter];

        if (iLetter == SPACE_ASCII_CODE) // Espace !
        {
            fPosX += character.iXAdvance;

            continue;
        }

        if (iLetter == '\n')
        {
            fPosX = 0;
        }

        float x = 0;
        float y = 0;

        float tu = 0;
        float tv = 0;

        uint32 iCharX = character.iXPos; // Abscisse du caractère dans la texture
        uint32 iCharY = character.iYPos; // Ordonnée du caractère dans la texture
        uint32 iWidth = character.iWidth; // Largeur du caractère dans la texture
        uint32 iHeight = character.iHeight; // Hauteur du caractère dans la texture
        float iOffsetX = character.iXOffset;
        float iOffsetY = character.iYOffset;
        float iXAdvance = character.iXAdvance;
        uint16 iPage = character.iPage;

         //----------------- 1er triangle de la face du caractère -----------------//

        // ---- Bottom left ---- //
        iOffsetY = - iOffsetY - iHeight;
        //iOffsetY = (- iOffsetY - pFont->iLineHeight
        //iOffsetY -= pFont->iLineHeight;
        //iOffsetY -= pFont->iLineHeight;

        x = fPosX + iOffsetX;
        y = fPosY + iOffsetY;

        tu = (float) (iCharX) / pFont->iWidth;
        tv = (float) (iCharY + iHeight) / pFont->iHeight;

        PTPVertex vertex;

        vertex.position = D3DXVECTOR3(x, y, 0.0f);
        vertex.texture = D3DXVECTOR2(tu, tv);
        vertex.page = iPage;

        vertices.push_back(vertex);

        // ---- Top left ---- //

        x = fPosX + iOffsetX;
        y = fPosY + iOffsetY + iHeight;

        tu = (float) iCharX / pFont->iWidth;
        tv = (float) iCharY / pFont->iHeight;

        vertex.position = D3DXVECTOR3(x, y, 0.0f);  
        vertex.texture = D3DXVECTOR2(tu, tv);
        vertex.page = iPage;

        vertices.push_back(vertex);

        // ---- Top right ---- //

        x = fPosX + iOffsetX + iWidth;
        y = fPosY + iOffsetY + iHeight;

        tu = (float) (iCharX + iWidth) / pFont->iWidth;
        tv = (float) iCharY / pFont->iHeight;

        vertex.position = D3DXVECTOR3(x, y, 0.0f);  
        vertex.texture = D3DXVECTOR2(tu, tv);
        vertex.page = iPage;

        vertices.push_back(vertex);

        //----------------- 2ème triangle de la face du caractère -----------------//

        // ---- Top right ---- //

        x = fPosX + iOffsetX + iWidth;
        y = fPosY + iOffsetY + iHeight;

        tu = (float) (iCharX + iWidth) / pFont->iWidth;
        tv = (float) iCharY / pFont->iHeight;

        vertex.position = D3DXVECTOR3(x, y, 0.0f);  
        vertex.texture = D3DXVECTOR2(tu, tv);
        vertex.page = iPage;

        vertices.push_back(vertex);

        // ---- Bottom right ---- //

        x = fPosX + iOffsetX + iWidth;
        y = fPosY + iOffsetY;

        tu = (float) (iCharX + iWidth) / pFont->iWidth;
        tv = (float) (iCharY + iHeight) / pFont->iHeight;

        vertex.position = D3DXVECTOR3(x, y, 0.0f);  
        vertex.texture = D3DXVECTOR2(tu, tv);
        vertex.page = iPage;

        vertices.push_back(vertex);

        // ---- Bottom left ---- //

        x = fPosX + iOffsetX;
        y = fPosY + iOffsetY;

        tu = (float) (iCharX) / pFont->iWidth;
        tv = (float) (iCharY + iHeight) / pFont->iHeight;

        vertex.position = D3DXVECTOR3(x, y, 0.0f);  
        vertex.texture = D3DXVECTOR2(tu, tv);
        vertex.page = iPage;

        vertices.push_back(vertex);

        // On décale de quelques pixels vers la gauche après chaque lettre
        fPosX += iXAdvance;
    }

    pText->SetVertexCount(vertices.size());
    pText->SetIndexCount( pText->GetVertexCount() );

    std::vector<uint16> indices;
    for (uint16 i = 0; i < pText->GetIndexCount(); i++)
    {
        indices.push_back(i);
    }

    vertexBufferDesc.Usage = D3D10_USAGE_DYNAMIC;
    vertexBufferDesc.ByteWidth = sizeof(PTPVertex) * pText->GetVertexCount();
    vertexBufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    vertexBufferDesc.MiscFlags = 0;

    vertexData.pSysMem = vertices.data();

    ID3D10Buffer* pVB = nullptr;

    hr = D3D10_RENDERER->GetDevice()->CreateBuffer(&vertexBufferDesc, &vertexData, &pVB);
    VR_RETURN(hr);

    pText->SetVertexBuffer(pVB);
        
    indexBufferDesc.Usage = D3D10_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(uint16) * pText->GetIndexCount();
    indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;

    indexData.pSysMem = indices.data();

    ID3D10Buffer* pIB = nullptr;
    hr = D3D10_RENDERER->GetDevice()->CreateBuffer(&indexBufferDesc, &indexData, &pIB);
    VR_RETURN(hr);

    pText->SetIndexBuffer(pIB);

    return true;
}

void FontTextManager::Render(Text* pText)
{
    if (!pText)
    {
        return;
    } 

    uint32 iStride = sizeof(PTPVertex);
    uint32 iOffset = 0;

    D3D10_RENDERER->EnableZBuffer(false);

    m_pWorldVariable->SetMatrix((float*)&m_worldMatrix);
    m_pViewVariable->SetMatrix((float*)&m_viewMatrix);
    m_pProjVariable->SetMatrix((float*)&m_projMatrix);
    m_pColorVariable->SetFloatVector((float*)pText->GetColor());

    ID3D10Buffer* pVertexBuffer = pText->GetVertexBuffer();
    ID3D10Buffer* pIndexBuffer = pText->GetIndexBuffer();

    size_t iVertexCount = pText->GetVertexCount();
    size_t iIndexCount = pText->GetIndexCount();

    D3D10_RENDERER->GetDevice()->IASetVertexBuffers(0, 1, &pVertexBuffer, &iStride, &iOffset);
    D3D10_RENDERER->GetDevice()->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
    D3D10_RENDERER->GetDevice()->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    ID3D10ShaderResourceView* pRV = pText->GetFont()->texturesArray;

    if (pRV)
    {
        m_pBitmapVariable->SetResource(pRV);
    }

    D3D10_TECHNIQUE_DESC techniqueDesc;
    D3D10_RENDERER->GetDevice()->IASetInputLayout(m_pVertexLayout);

    m_pTechnique->GetDesc(&techniqueDesc);

    AlphaPass TransparencyPass;

    for (uint32 i = 0; i < techniqueDesc.Passes; i++)
    {
        m_pTechnique->GetPassByIndex(i)->Apply(0);

        D3D10_RENDERER->GetDevice()->Draw(iVertexCount, 0);
    }

    D3D10_RENDERER->EnableZBuffer(true);
}

Text* FontTextManager::CreateText(const std::wstring& sText, const std::string& sFontTextName,
                                  const float fPosX, const float fPosY, const D3DXCOLOR& color)
{
    Text* pText = new Text(sText, color, fPosX, fPosY);

    if (!IsFontTextLoaded(sFontTextName)) // todo : add dummy text
    {
        PRINT_ERROR("Police de caractere non reconnu");

        return nullptr;
    }

    pText->SetFont(m_fonts[sFontTextName]);

    if (!BuildTextBuffers(pText))
    {
        PRINT_ERROR("Echec lors du la construction des buffers d'un texte speficie");

        return nullptr;
    }

    return pText;
}

/* Voir la documentation sur
    http://www.angelcode.com/products/bmfont/doc/file_format.html
*/
bool FontTextManager::LoadFontTextFile(const std::string& sFileName, const std::string& sFontTextName)
{
    std::vector<ID3D10Texture2D*> textures;

    std::string sLine;
    std::string sRead, sKey, sValue;

    std::ifstream file(sFileName);

    if (!file.is_open())
    {
        PRINT_ERROR("Impossible de charger un fichier font");

        return false;
    }

    std::string sBitmapFileName = "";

    FontTextFileCharacter* aCharacters = new FontTextFileCharacter[256];

    Font* pFont = new Font;
    pFont->sFontTextName = sFontTextName;
    pFont->aCharacters = aCharacters;

    while (!file.eof())
    {
        std::stringstream sLineStream;
        std::getline( file, sLine );
        sLineStream << sLine;

        // Lit le type de la ligne
        sLineStream >> sRead;

        if (sRead == "info")
        {
            while (!sLineStream.eof())
            {
                std::stringstream Converter;
                sLineStream >> sRead;

                uint32 i = sRead.find('=');
                sKey = sRead.substr(0, i);
                sValue = sRead.substr(i + 1);

                Converter << sValue;

                if (sKey == "size")
                {
                    Converter >> pFont->iSize;
                }
            }
        }
        else if (sRead == "common")
        {
            while (!sLineStream.eof())
            {
                std::stringstream Converter;
                sLineStream >> sRead;

                uint32 i = sRead.find('=');
                sKey = sRead.substr(0, i);
                sValue = sRead.substr(i + 1);

                Converter << sValue;

                if (sKey == "lineHeight")
                {
                    Converter >> pFont->iLineHeight;
                }
                else if (sKey == "base")
                {
                    Converter >> pFont->iBase;
                }
                else if (sKey == "scaleW")
                {
                    Converter >> pFont->iWidth;
                }
                else if (sKey == "scaleH")
                {
                    Converter >> pFont->iHeight;
                }
                else if (sKey == "pages")
                {
                    Converter >> pFont->iPagesCount;
                }
            }
        }
        else if (sRead == "page")
        {
            while (!sLineStream.eof())
            {
                std::stringstream Converter;
                sLineStream >> sRead;

                uint32 i = sRead.find('=');
                sKey = sRead.substr(0, i);
                sValue = sRead.substr(i + 1);

                Converter << sValue;
    
                if (sKey == "file")
                {
                    Converter >> sBitmapFileName;

                    // On supprime les guillemets entre le nom du fichier
                    sBitmapFileName.pop_back();    
                    sBitmapFileName.erase(0, 1);

                    fastprint("Chargement de " << sBitmapFileName << " pour " << pFont->sFontTextName);
                
                    ID3D10Texture2D* pTexture = CreateTexture(sBitmapFileName);

                    if (pTexture)
                    {
                        textures.push_back(pTexture);
                    }
                }

            }
        }
        else if (sRead == "char")
        {
            uint16 iCharID = 0;

            while (!sLineStream.eof())
            {
                std::stringstream Converter;
                sLineStream >> sRead;

                uint32 i = sRead.find('=');
                sKey = sRead.substr(0, i);
                sValue = sRead.substr(i + 1);
                Converter << sValue;

                if (sKey == "id")
                {
                    Converter >> iCharID;
                }
                else if (sKey == "x")
                {
                    Converter >> pFont->aCharacters[iCharID].iXPos;
                }
                else if (sKey == "y" )
                {
                    Converter >> pFont->aCharacters[iCharID].iYPos;
                }
                else if (sKey == "width")
                {
                    Converter >> pFont->aCharacters[iCharID].iWidth;
                }
                else if (sKey == "height")
                {
                    Converter >> pFont->aCharacters[iCharID].iHeight;
                }
                else if (sKey == "xoffset")
                {
                    Converter >> pFont->aCharacters[iCharID].iXOffset;
                }
                else if (sKey == "yoffset")
                {
                    Converter >> pFont->aCharacters[iCharID].iYOffset;
                }
                else if (sKey == "xadvance")
                {
                    Converter >> pFont->aCharacters[iCharID].iXAdvance;
                }
                else if (sKey == "page")
                {
                    Converter >> pFont->aCharacters[iCharID].iPage;
                }
            }
        }
    }
    
    m_fonts[sFontTextName] = pFont;

    debugprint(pFont->sFontTextName.c_str());
    debugprint(pFont->iBase);
    debugprint(pFont->iHeight);
    debugprint(pFont->iLineHeight);
    debugprint(pFont->iPagesCount);
    debugprint(pFont->iWidth);

    if (textures.size() == 0)
    {
        PRINT_ERROR("Aucune textures chargees");
    }

    fastprint("\n---------------------------\n");

    ID3D10Texture2D* pTextureArray = CreateTextureArray(textures);

    for (uint32 i = 0; i < textures.size(); i++)
    {
        ID3D10Texture2D* pCurrentTexture = textures[i];

        SAFE_RELEASE(pCurrentTexture);
    }

    ID3D10ShaderResourceView* pRVArray = GetTextureRVArray(pTextureArray);

    SAFE_RELEASE(pTextureArray);

    pFont->texturesArray = pRVArray;

    return true;
}

float FontTextManager::GetGlyphAspectRatio(const wchar_t* c, const std::string& sFontTextName)
{
    // On obtient la police spécifiée
    Font* pFont = m_fonts[sFontTextName];

    if (pFont)
    {
        return 0;
    }

    // Tableau de tous les caractères de la police de font
    FontTextFileCharacter* aCharacters = pFont->aCharacters;

    FontTextFileCharacter character = aCharacters[(uint32)c];

    uint32 iWidth = character.iWidth;
    uint32 iHeight = character.iHeight;

    return (float) (iWidth / iHeight);
}

RECT FontTextManager::GetGlyphTexCoords(const wchar_t* c, const std::string& sFontTextName)
{
    RECT rect;
    ZeroMemory(&rect, sizeof(RECT));

    // On obtient la police spécifiée
    Font* pFont = m_fonts[sFontTextName];

    if (!pFont)
    {
        return rect;
    }

    // Tableau de tous les caractères de la police de font
    FontTextFileCharacter* aCharacters = pFont->aCharacters;

    FontTextFileCharacter character = aCharacters[(uint32)c];

    uint32 iCharX = character.iXPos;
    uint32 iCharY = character.iYPos;
    uint32 iWidth = character.iWidth;
    uint32 iHeight = character.iHeight;

    rect.left = iCharX;
    rect.top = iCharY;
    rect.right = iWidth;
    rect.bottom = iHeight;

    return rect;
}

uint16 FontTextManager::GetCharacterPage(const wchar_t* c, const std::string& sFontTextName)
{
    // On obtient la police spécifiée
    Font* pFont = m_fonts[sFontTextName];

    if (!pFont)
    {
        return 0;
    }

    // Tableau de tous les caractères de la police de font
    FontTextFileCharacter* aCharacters = pFont->aCharacters;

    FontTextFileCharacter character = aCharacters[(uint32)c];

    return character.iPage;
}

ID3D10Texture2D* FontTextManager::CreateTexture(const std::string& sBitmapFileName)
{
    ID3D10Texture2D* pLoadedTexture = nullptr;

    D3DX10_IMAGE_LOAD_INFO loadinfo;
    ZeroMemory(&loadinfo, sizeof(D3DX10_IMAGE_LOAD_INFO));

    loadinfo.Width = D3DX10_FROM_FILE;
    loadinfo.Height = D3DX10_FROM_FILE;
    loadinfo.Depth = D3DX10_FROM_FILE;

    loadinfo.FirstMipLevel = 0;
    loadinfo.MipLevels = D3DX10_FROM_FILE;
    loadinfo.Usage = D3D10_USAGE_STAGING;

    loadinfo.BindFlags = 0;
    loadinfo.CpuAccessFlags = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE;
    loadinfo.MiscFlags = 0;

    loadinfo.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    loadinfo.Filter = D3DX10_FILTER_NONE;
    loadinfo.MipFilter = D3DX10_FILTER_NONE;
    loadinfo.pSrcInfo = 0;

    D3DX10CreateTextureFromFileA(D3D10_RENDERER->GetDevice(),
        sBitmapFileName.c_str(), &loadinfo, 0, (ID3D10Resource**)&pLoadedTexture, 0);

    return pLoadedTexture;
}

ID3D10Texture2D* FontTextManager::CreateTextureArray(std::vector<ID3D10Texture2D*>& textures)
{
    if (textures.size() == 0)
    {
        return nullptr;
    }

    ID3D10Texture2D* pTexturesArray = nullptr;

    D3D10_TEXTURE2D_DESC textElementDesc;
    ZeroMemory(&textElementDesc, sizeof(D3D10_TEXTURE2D_DESC));

    textures[0]->GetDesc(&textElementDesc);

    D3D10_TEXTURE2D_DESC textArrayDesc;

    textArrayDesc.Width = textElementDesc.Width;
    textArrayDesc.Height = textElementDesc.Height;
    textArrayDesc.MipLevels = textElementDesc.MipLevels;
    textArrayDesc.ArraySize = textures.size();
    textArrayDesc.Format = textElementDesc.Format;
    textArrayDesc.SampleDesc.Count = 1;
    textArrayDesc.SampleDesc.Quality = 0;
    textArrayDesc.Usage = D3D10_USAGE_DEFAULT;
    textArrayDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
    textArrayDesc.CPUAccessFlags = 0;
    textArrayDesc.MiscFlags = 0;

    D3D10_RENDERER->GetDevice()->CreateTexture2D(&textArrayDesc, 0, &pTexturesArray);

    // On copie toutes les textures dans le tableau !
    for (uint16 i = 0; i < textures.size(); i++)
    {
        for (uint16 j = 0; j < textElementDesc.MipLevels; j++)
        {
            D3D10_MAPPED_TEXTURE2D mappedTex2D;

            ID3D10Texture2D* pCurrentTexture = textures[i];

            pCurrentTexture->Map(j, D3D10_MAP_READ, 0, &mappedTex2D);

            uint32 c = D3D10CalcSubresource(j, i, textElementDesc.MipLevels);

            D3D10_RENDERER->GetDevice()->UpdateSubresource(pTexturesArray, c,
                0, mappedTex2D.pData, mappedTex2D.RowPitch, 0);

            pCurrentTexture->Unmap(j);
        }
    }

    return pTexturesArray;
}

ID3D10ShaderResourceView* FontTextManager::GetTextureRVArray(ID3D10Texture2D* pTexArray)
{
    if (pTexArray == nullptr)
    {
        return nullptr;
    }

    ID3D10ShaderResourceView* pArrayRV = nullptr;

    D3D10_SHADER_RESOURCE_VIEW_DESC viewDesc;
    ZeroMemory(&viewDesc, sizeof(D3D10_SHADER_RESOURCE_VIEW_DESC));

    D3D10_TEXTURE2D_DESC textArrayDesc;
    pTexArray->GetDesc(&textArrayDesc);

    viewDesc.Format = textArrayDesc.Format;
    viewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2DARRAY;
    viewDesc.Texture1DArray.MostDetailedMip = 0;
    viewDesc.Texture1DArray.MipLevels = textArrayDesc.MipLevels;
    viewDesc.Texture1DArray.FirstArraySlice = 0;
    viewDesc.Texture1DArray.ArraySize = textArrayDesc.ArraySize;

    D3D10_RENDERER->GetDevice()->CreateShaderResourceView(pTexArray, &viewDesc, &pArrayRV);

    return pArrayRV;
}

 

Résumé :

Nous avons présenter une méthode générique pour afficher du texte à l’écran ! Pas besoin d’utiliser D3DXFont !

Références :

– http://www.rastertek.com/dx10tut12.html

– http://kvazars.com/littera/

– http://www.angelcode.com/products/bmfont/

– http://www.angelcode.com/products/bmfont/doc/file_format.html

– http://www.gamedev.net/topic/330742-quick-tutorial-variable-width-bitmap-fonts/

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *