简体   繁体   中英

DirectX 11: text output, using your own font texture

I'm learning DirectX, using the book "Sherrod A., Jones W. - Beginning DirectX 11 Game Programming - 2011" Now I'm exploring the 4th chapter about drawing text.

Please, help we to fix my function, that I'm using to draw a string on the screen. I've already loaded font texture and in the function I create some sprites with letters and define texture coordinates for them. This compiles correctly, but doesn't draw anything. What's wrong?

bool DirectXSpriteGame :: DrawString(char* StringToDraw, float StartX, float StartY)
{
//VAR
    HRESULT D3DResult;                                                                              //The result of D3D functions

    int i;                                                                                          //Counters
    const int IndexA = static_cast<char>('A');                                                      //ASCII index of letter A
    const int IndexZ = static_cast<char>('Z');                                                      //ASCII index of letter Z
    int StringLenth = strlen(StringToDraw);                                                         //Lenth of drawing string
    float ScreenCharWidth = static_cast<float>(LETTER_WIDTH) / static_cast<float>(SCREEN_WIDTH);    //Width of the single char on the screen(in %)
    float ScreenCharHeight = static_cast<float>(LETTER_HEIGHT) / static_cast<float>(SCREEN_HEIGHT); //Height of the single char on the screen(in %)
    float TexelCharWidth = 1.0f / static_cast<float>(LETTERS_NUM);                                  //Width of the char texel(in the texture %)
    float ThisStartX;                                                                               //The start x of the current letter, drawingh
    float ThisStartY;                                                                               //The start y of the current letter, drawingh
    float ThisEndX;                                                                                 //The end x of the current letter, drawing
    float ThisEndY;                                                                                 //The end y of the current letter, drawing
    int LetterNum;                                                                                  //Letter number in the loaded font
    int ThisLetter;                                                                                 //The current letter

    D3D11_MAPPED_SUBRESOURCE MapResource;                                                           //Map resource
    VertexPos* ThisSprite;                                                                          //Vertecies of the current sprite, drawing
//VAR

//Clamping string, if too long
if(StringLenth > LETTERS_NUM)
{
    StringLenth = LETTERS_NUM;
}

//Mapping resource
D3DResult = _DeviceContext -> Map(_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MapResource);
if(FAILED(D3DResult))
{
    throw("Failed to map resource");
}
ThisSprite = (VertexPos*)MapResource.pData;

for(i = 0; i < StringLenth; i++)
{
    //Creating geometry for the letter sprite
    ThisStartX = StartX + ScreenCharWidth * static_cast<float>(i);
    ThisStartY = StartY;
    ThisEndX = ThisStartX + ScreenCharWidth;
    ThisEndY = StartY + ScreenCharHeight;

    ThisSprite[0].Position = XMFLOAT3(ThisEndX, ThisEndY, 1.0f);
    ThisSprite[1].Position = XMFLOAT3(ThisEndX, ThisStartY, 1.0f);
    ThisSprite[2].Position = XMFLOAT3(ThisStartX, ThisStartY, 1.0f);

    ThisSprite[3].Position = XMFLOAT3(ThisStartX, ThisStartY, 1.0f);
    ThisSprite[4].Position = XMFLOAT3(ThisStartX, ThisEndY, 1.0f);
    ThisSprite[5].Position = XMFLOAT3(ThisEndX, ThisEndY, 1.0f);

    ThisLetter = static_cast<char>(StringToDraw[i]);

    //Defining the letter place(number) in the font
    if(ThisLetter < IndexA || ThisLetter > IndexZ)
    {
        //Invalid character, the last character in the font, loaded
        LetterNum = IndexZ - IndexA + 1;
    }
    else
    {
        LetterNum = ThisLetter - IndexA;
    }

    //Unwraping texture on the geometry
    ThisStartX = TexelCharWidth * static_cast<float>(LetterNum);
    ThisStartY = 0.0f;
    ThisEndY = 1.0f;
    ThisEndX = ThisStartX + TexelCharWidth;

    ThisSprite[0].TextureCoords = XMFLOAT2(ThisEndX, ThisEndY);
    ThisSprite[1].TextureCoords = XMFLOAT2(ThisEndX, ThisStartY);
    ThisSprite[2].TextureCoords = XMFLOAT2(ThisStartX, ThisStartY);

    ThisSprite[3].TextureCoords = XMFLOAT2(ThisStartX, ThisStartY); 
    ThisSprite[4].TextureCoords = XMFLOAT2(ThisStartX, ThisEndY);   
    ThisSprite[5].TextureCoords = XMFLOAT2(ThisEndX, ThisEndY);

    ThisSprite += VERTEX_IN_RECT_NUM;
}

for(i = 0; i < StringLenth; i++, ThisSprite -= VERTEX_IN_RECT_NUM);

_DeviceContext -> Unmap(_vertexBuffer, 0);
_DeviceContext -> Draw(VERTEX_IN_RECT_NUM * StringLenth, 0);

return true;
}

Although the piece of code constructing the Vertex Array seems correct to me at first glance, it seems like you are trying to Draw your vertices with a Shader which has not been set yet ! It is difficult to precisely answer you without looking at the whole code, but I can guess that you will need to do something like that :

1) Create Vertex and Pixel Shaders by compiling them first from their respective buffers

2) Create the Input Layout description, which describes the Input Buffers that will be read by the Input Assembler stage. It will have to match your VertexPos structure and your shader structure.

3) Set the Shader parameters.

4) Only now you can Set Shader rendering parameters : Set the InputLayout , as well as the Vertex and Pixel Shaders that will be used to render your triangles by something like :

_DeviceContext -> Unmap(_vertexBuffer, 0);

_DeviceContext->IASetInputLayout(myInputLayout);
_DeviceContext->VSSetShader(myVertexShader, NULL, 0); // Set Vertex shader
_DeviceContext->PSSetShader(myPixelShader, NULL, 0); // Set Pixel shader

_DeviceContext -> Draw(VERTEX_IN_RECT_NUM * StringLenth, 0);

This link should help you achieve what you want to do : http://www.rastertek.com/dx11tut12.html

Also, I recommend you to set an IndexBuffer and to use the method DrawIndexed to render your triangles for performance reasons : It will allow the graphics adapter to store vertices in a vertex cache, allowing recently-used vertex to be fetched from the cache instead of reading it from the vertex buffer. More about this concern can be found on MSDN : http://msdn.microsoft.com/en-us/library/windows/desktop/bb147325(v=vs.85).aspx

Hope this helps!

PS : Also, don't forget to release the resources after using them by calling Release() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM