技巧如下:
字体的绘制需要使用ID3DXFont对象和 D3DXCreateFontIndirect函数。
DirectX SDK文档对ID3DXFont做了简要的说明:
The ID3DXFont interface encapsulates the textures and resources needed to render
a specific font on a specific device.
The ID3DXFont interface is obtained by calling D3DXCreateFont or
D3DXCreateFontIndirect.
我们来看看SDK文档提供的关于 D3DXCreateFontIndirect的使用说明:
Creates a font object indirectly
for both a device and a font.
HRESULT D3DXCreateFontIndirect(
LPDIRECT3DDEVICE9 pDevice,
CONST D3DXFONT_DESC * pDesc,
LPD3DXFONT * ppFont
);
Parameters
- pDevice
- [in] Pointer to an IDirect3DDevice9 interface, the device to be
associated with the font object.
- pDesc
- [in] Pointer to a D3DXFONT_DESC structure, describing the attributes of
the font object to create. If the compiler settings require Unicode, the
data type D3DXFONT_DESC resolves to D3DXFONT_DESCW; otherwise, the data type
resolves to D3DXFONT_DESCA. See Remarks.
- ppFont
- [out] Returns a pointer to an ID3DXFont interface, representing the
created font object.
Return Values
If the function succeeds, the return value is D3D_OK. If the function fails,
the return value can be one of the following: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
Remarks
The compiler setting also determines the function version. If Unicode is
defined, the function call resolves to D3DXCreateFontIndirectW. Otherwise, the
function call resolves to D3DXCreateFontIndirectA because ANSI strings are being
used.
该函数的第二个参数使用了一个结构体D3DXFONT_DESC,来看看它的具体定义:
Defines the attributes of a font.
typedef struct D3DXFONT_DESC {
INT Height;
UINT Width;
UINT Weight;
UINT MipLevels;
BOOL Italic;
BYTE CharSet;
BYTE OutputPrecision;
BYTE Quality;
BYTE PitchAndFamily;
TCHAR FaceName[LF_FACESIZE];
} D3DXFONT_DESC, *LPD3DXFONT_DESC;
Members
- Height
- Height, in logical units, of the font's character cell or character.
- Width
- Width, in logical units, of characters in the font.
- Weight
- Weight of the font in the range from 0 through 1000.
- MipLevels
- Number of mip levels requested. If this value is zero or D3DX_DEFAULT, a
complete mipmap chain is created. If the value is 1, the texture space is
mapped identically to the screen space.
- Italic
- Set to TRUE for an Italic font.
- CharSet
- Character set.
- OutputPrecision
- Output precision. The output precision defines how closely the output
must match the requested font height, width, character orientation,
escapement, pitch, and font type.
- Quality
- Output quality.
- PitchAndFamily
- Pitch and family of the font.
- FaceName
- A null-terminated string or characters that specifies the typeface name
of the font. The length of the string must not exceed 32 characters,
including the terminating null character. If FaceName is an empty string,
the first font that matches the other specified attributes will be used. If
the compiler settings require Unicode, the data type TCHAR resolves to WCHAR;
otherwise, the data type resolves to CHAR. See Remarks.
Remarks
The compiler setting also determines the structure type. If Unicode is
defined, the D3DXFONT_DESC structure type resolves to a D3DXFONT_DESCW;
otherwise the structure type resolves to a D3DXFONT_DESCA.
Possible values of the above members are given in the GDI LOGFONT structure.
当然,在设置的时候我们不需要设置所有的属性,只要设置其中的几个主要属性就可以了。
我们可以这样设置字体的属性并创建字体:
D3DXFONT_DESC font_desc;
// create the font
ZeroMemory(&font_desc, sizeof(font_desc));
// set font descripter
strcpy(font_desc.FaceName, "Arial");
font_desc.Height = 32;
// Creates a font object indirectly for both a device and a font
D3DXCreateFontIndirect(g_d3d_device, &font_desc, &g_font);
通过ID3DXFont::DrawText方法我们可以绘制字体了,来看看它的具体使用信息:
Draws formatted text. This
method supports ANSI and Unicode strings.
INT DrawText(
LPD3DXSPRITE pSprite,
LPCTSTR pString,
INT Count,
LPRECT pRect,
DWORD Format,
D3DCOLOR Color
);
Parameters
- pSprite
- [in] Pointer to an ID3DXSprite object that contains the string. Can be
NULL, in which case Direct3D will render the string with its own sprite
object. To improve efficiency, a sprite object should be specified if
ID3DXFont::DrawText is to be called more than once in a row.
- pString
- [in] Pointer to a string to draw.If the Count parameter is -1, the
string must be null-terminated.
- Count
- [in] Specifies the number of characters in the string. If Count is -1,
then the pString parameter is assumed to be a pointer to a null-terminated
string and ID3DXFont::DrawText computes the character count
automatically.
- pRect
- [in] Pointer to a RECT structure that contains the rectangle, in logical
coordinates, in which the text is to be formatted. As with any RECT object,
the coordinate value of the rectangle's right side must be greater than that
of its left side. Likewise, the coordinate value of the bottom must be
greater than that of the top.
- Format
- [in] Specifies the method of formatting the text. It can be any
combination of the following values:
- DT_BOTTOM
- Justifies the text to the bottom of the rectangle. This value must
be combined with DT_SINGLELINE.
- DT_CALCRECT
- Determines the width and height of the rectangle. If there are
multiple lines of text, ID3DXFont::DrawText uses the width of the
rectangle pointed to by the pRect parameter and extends the base of the
rectangle to bound the last line of text. If there is only one line of
text, ID3DXFont::DrawText modifies the right side of the
rectangle so that it bounds the last character in the line. In either
case, ID3DXFont::DrawText returns the height of the formatted
text but does not draw the text.
- DT_CENTER
- Centers text horizontally in the rectangle.
- DT_EXPANDTABS
- Expands tab characters. The default number of characters per tab is
eight.
- DT_LEFT
- Aligns text to the left.
- DT_NOCLIP
- Draws without clipping. ID3DXFont::DrawText is somewhat
faster when DT_NOCLIP is used.
- DT_RIGHT
- Aligns text to the right.
- DT_RTLREADING
- Displays text in right-to-left reading order for bidirectional text
when a Hebrew or Arabic font is selected. The default reading order for
all text is left-to-right.
- DT_SINGLELINE
- Displays text on a single line only. Carriage returns and line feeds
do not break the line.
- DT_TOP
- Top-justifies text.
- DT_VCENTER
- Centers text vertically (single line only).
- DT_WORDBREAK
- Breaks words. Lines are automatically broken between words if a word
would extend past the edge of the rectangle specified by the pRect
parameter. A carriage return/line feed sequence also breaks the line.
- Color
- [in] Color of the text. For more information, see D3DCOLOR.
Return Values
If the function succeeds, the return value is the height of the text in
logical units. If DT_VCENTER or DT_BOTTOM is specified, the return value is the
offset from pRect (top to the bottom) of the drawn text. If the function fails,
the return value is zero.
Remarks
The parameters of this method are very similar to those of the GDI DrawText
function.
This method supports both ANSI and Unicode strings.
This method must be called inside a IDirect3DDevice9::BeginScene ...
IDirect3DDevice9::EndScene block. The only exception is when an application
calls ID3DXFont::DrawText with DT_CALCRECT to calculate the size of a
given block of text.
Unless the DT_NOCLIP format is used, this method clips the text so that it
does not appear outside the specified rectangle. All formatting is assumed to
have multiple lines unless the DT_SINGLELINE format is specified.
If the selected font is too large for the rectangle, this method does not
attempt to substitute a smaller font.
This method supports only fonts whose escapement and orientation are both
zero.
我们可以这样使用该函数:
RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
// Begin scene
if(SUCCEEDED(g_d3d_device->BeginScene()))
{
// draw some text
g_font->DrawTextA(NULL, "Programming is fun!", -1, &rect, DT_CENTER | DT_VCENTER, 0xFFFFFFFF);
// end the scene
g_d3d_device->EndScene();
}
完整源码如下:
/***************************************************************************************
PURPOSE:
Font Demo
Required libraries:
D3D9.LIB and D3DX9.LIB
***************************************************************************************/
#include <windows.h>
#include <stdio.h>
#include "d3d9.h"
#include "d3dx9.h"
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma warning(disable : 4996)
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 400
#define Safe_Release(p) if((p)) (p)->Release();
// window handles, class and caption text.
HWND g_hwnd;
HINSTANCE g_inst;
static char g_class_name[] = "FontClass";
static char g_caption[] = "Font Demo";
// the Direct3D and device object
IDirect3D9* g_d3d = NULL;
IDirect3DDevice9* g_d3d_device = NULL;
// the font object
ID3DXFont* g_font = NULL;
//--------------------------------------------------------------------------------
// Window procedure.
//--------------------------------------------------------------------------------
long WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return (long) DefWindowProc(hwnd, msg, wParam, lParam);
}
//--------------------------------------------------------------------------------
// Initialize d3d, d3d device, vertex buffer, texutre.
//--------------------------------------------------------------------------------
BOOL Do_Init()
{
D3DPRESENT_PARAMETERS present_param;
D3DDISPLAYMODE display_mode;
D3DXFONT_DESC font_desc;
// do a windowed mode initialization of Direct3D
if((g_d3d = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
return FALSE;
// retrieves the current display mode of the adapter
if(FAILED(g_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &display_mode)))
return FALSE;
ZeroMemory(&present_param, sizeof(present_param));
// initialize d3d presentation parameter
present_param.Windowed = TRUE;
present_param.SwapEffect = D3DSWAPEFFECT_DISCARD;
present_param.BackBufferFormat = display_mode.Format;
// creates a device to represent the display adapter
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_param, &g_d3d_device)))
return FALSE;
// create the font
ZeroMemory(&font_desc, sizeof(font_desc));
// set font descripter
strcpy(font_desc.FaceName, "Arial");
font_desc.Height = 32;
// Creates a font object indirectly for both a device and a font
D3DXCreateFontIndirect(g_d3d_device, &font_desc, &g_font);
return TRUE;
}
//--------------------------------------------------------------------------------
// Release all d3d resource.
//--------------------------------------------------------------------------------
BOOL Do_Shutdown()
{
Safe_Release(g_font);
Safe_Release(g_d3d_device);
Safe_Release(g_d3d);
return TRUE;
}
//--------------------------------------------------------------------------------
// Render a frame.
//--------------------------------------------------------------------------------
BOOL Do_Frame()
{
RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
// clear device back buffer
g_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 64, 128, 255), 1.0f, 0);
// Begin scene
if(SUCCEEDED(g_d3d_device->BeginScene()))
{
// draw some text
g_font->DrawTextA(NULL, "Programming is fun!", -1, &rect, DT_CENTER | DT_VCENTER, 0xFFFFFFFF);
// end the scene
g_d3d_device->EndScene();
}
// present the contents of the next buffer in the sequence of back buffers owned by the device
g_d3d_device->Present(NULL, NULL, NULL, NULL);
return TRUE;
}
//--------------------------------------------------------------------------------
// Main function, routine entry.
//--------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
WNDCLASSEX win_class;
MSG msg;
g_inst = inst;
// create window class and register it
win_class.cbSize = sizeof(win_class);
win_class.style = CS_CLASSDC;
win_class.lpfnWndProc = Window_Proc;
win_class.cbClsExtra = 0;
win_class.cbWndExtra = 0;
win_class.hInstance = inst;
win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hbrBackground = NULL;
win_class.lpszMenuName = NULL;
win_class.lpszClassName = g_class_name;
win_class.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(! RegisterClassEx(&win_class))
return FALSE;
// create the main window
g_hwnd = CreateWindow(g_class_name, g_caption, WS_CAPTION | WS_SYSMENU, 0, 0,
WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, inst, NULL);
if(g_hwnd == NULL)
return FALSE;
ShowWindow(g_hwnd, SW_NORMAL);
UpdateWindow(g_hwnd);
// initialize game
if(Do_Init() == FALSE)
return FALSE;
// start message pump, waiting for signal to quit.
ZeroMemory(&msg, sizeof(MSG));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// draw a frame
if(Do_Frame() == FALSE)
break;
}
// run shutdown function
Do_Shutdown();
UnregisterClass(g_class_name, inst);
return (int) msg.wParam;
}
效果图如下: