

Utilisation de 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/