Allowing the DrawText function to create and use its own ID3DX10Sprite
object is costly if you’re planning on drawing more than one line of
text. It is more efficient for you to create the sprite object yourself,
allowing it to be reused for each line of text. This keeps the number
of sprite objects being created and destroyed to a minimum.
Using a Sprite Object
The first parameter to the DrawText function is a pointer to the sprite object. In the previous section, you passed NULL to this parameter; to utilize your own sprite, a valid ID3DX10Sprite object needs to be created.
The sprite object can be created anytime before the first DrawText
function call is made. To keep similar functionality together, the
sprite object can be created right after the font object. The InitFont function can be updated to include both tasks.
/*******************************************************************
* InitFont
* Initialize the font object
* Inputs - void
* Outputs - bool - true/success, false/failure
*******************************************************************/
bool InitFont()
{
HRESULT hr = D3DX10CreateFont(pD3DDevice,
35, // the font height
0, // the font width
FW_BOLD, // the weight of the font
1, // number of mip levels
FALSE, // this is not an italic font
DEFAULT_CHARSET, // default character set
OUT_DEFAULT_PRECIS, // default size mapping
DEFAULT_QUALITY, // default quality mapping
DEFAULT_PITCH | FF_DONTCARE, // default pitch
L"Helvetica", // use Helvetica as the basis for this font
&pFont); // the output
if (FAILED(hr))
{
return false;
}
// Create the sprite that fonts will use to draw with
D3DX10CreateSprite(pD3DDevice, 512, &pFontSprite);
return true;
}
Remember to release both the font and sprite objects when the program ends.
// Release the font
if (pFont != NULL)
{
pFont->Release();
pFont = NULL;
}
// Release the font sprite
if (pFontSprite != NULL)
{
pFontSprite->Release();
pFontSprite = NULL;
}
Text Drawing
The DrawText function is still the workhorse of text drawing; the major difference now is the text is being drawn to objects you specify.
There are only a few changes needed to draw the text using your own sprites. The DrawText function call needs to be updated to pass in a pointer to your sprite object. Because sprites are being drawn here, the DrawText function needs to be placed between calls to the sprite object’s Begin and End calls. This prepares the system for sprite drawing. An updated Render function follows, showing which changes should be made.
/*******************************************************************
* Render
* All drawing happens in the Render function
* Inputs - void
* Outputs - void
*******************************************************************/
void Render()
{
if (pD3DDevice != NULL)
{
// clear the target buffer
pD3DDevice->ClearRenderTargetView(pRenderTargetView, D3DXCOLOR(0.0f,
0.0f, 0.0f, 0.0f));
// Create and Initialize the destination rectangle
RECT rc;
SetRectEmpty(&rc);
// Use the GetFontRectangle helper function to get the proper size
// of the rectangle.
GetFontRectangle(TEXT("This is a test string"), &rc);
// Start font drawing
pFontSprite->Begin(D3DX10_SPRITE_SORT_TEXTURE);
// Draw the text to the screen
HRESULT hr = pFont->DrawText( pFontSprite,
TEXT("This is a test string"),
-1,
&rc,
DT_LEFT,
D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
pFontSprite->End();
// display the next item in the swap chain
pSwapChain->Present(0, 0);
}
}
While this may seem
like a simple change, the results won’t quite be what you were
expecting. The text being drawn shows up as a series of color-filled
rectangles. Figure 1 shows the result of using your own sprites to draw text.
The rectangles contain an alpha channel that is not being drawn correctly. To solve this problem, the Render
function needs to be updated to change the current blend state.
The Render function shown next correctly updates the blend state for font drawing.
/*******************************************************************
* Render
* All drawing happens in the Render function
* Inputs - void
* Outputs - void
*******************************************************************/
void Render()
{
FLOAT OriginalBlendFactor[4];
UINT OriginalSampleMask = 0;
if (pD3DDevice != NULL)
{
// clear the target buffer
pD3DDevice->ClearRenderTargetView(pRenderTargetView, D3DXCOLOR(0.0f,
0.0f, 0.0f, 0.0f));
// Create and Initialize the destination rectangle
RECT rc;
SetRectEmpty(&rc);
// Use the GetFontRectangle helper function to get the proper size
// of the rectangle.
GetFontRectangle(TEXT("This is a test string"), &rc);
// Start font drawing
pFontSprite->Begin(D3DX10_SPRITE_SORT_TEXTURE);
// Draw the text to the screen
HRESULT hr = pFont->DrawText( pFontSprite,
TEXT("This is a test string"),
-1,
&rc,
DT_LEFT,
D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
// Save the current blend state
pD3DDevice->OMGetBlendState(&pOriginalBlendState10,
OriginalBlendFactor,
&OriginalSampleMask);
// Set the blend state for font drawing
if(pFontBlendState10)
{
FLOAT NewBlendFactor[4] = {0,0,0,0};
pD3DDevice->OMSetBlendState(pFontBlendState10, NewBlendFactor,
0xffffffff);
}
pFontSprite->End();
// Restore the previous blend state
pD3DDevice->OMSetBlendState(pOriginalBlendState10,
OriginalBlendFactor, OriginalSampleMask);
// display the next item in the swap chain
pSwapChain->Present(0, 0);
}
}
|