- E/ q- J/ z3 W$ c `% l); , A: _0 G. \2 @* }1 W8 b 9 T5 _/ u) y' h9 O' o; ^' U& S
6 I6 K4 r' [* l8 q
译者注:我所使用的DirectX SDK是Microsoft DirectX 9.0 SDK Update (Summer 2004),也就是使用DirectX 9.0c的那个版本,在较早的版本里,该函数的原型有所不同:第二个参数为CONST LOGFONT *pLogFont,它是GDI中的结构。以后,如无特别说明,将以DirectX 9.0 SDK Update (Summer 2004)中声明的函数原型为准,特此声明! 7 B$ j1 X0 \% n6 p8 g 1 J1 c8 k% a& i0 @( ^2 k& e7 ]' N) P使用这个函数时,需要一个D3DXFONT_DESC结构: - l, ?+ f- T1 G3 g1 q& V' K ) }7 ~# }; K: T6 ND3DXFONT_DESC d3dFont;* [, O. C9 l: U, H3 F4 n/ n1 }
# }" v5 V4 f! p5 b% v
memset(&d3dFont,0,sizeof(d3dFont));6 S3 l8 O' Q! i7 K
2 G; @. r7 M& h- `: c
d3dFont.Height=25; // in logical units 0 j$ U5 C/ s5 M* H1 X8 ^ . \9 ]6 q8 K: f( Wd3dFont.Width=12; // in logical units 8 A( ?% b7 x1 H! ^1 D8 U# X3 Y 6 ?: H4 A% \4 H8 u3 fd3dFont.Weight=500;// boldness, range 0(light) - 1000(bold)# B! V. M+ ?; z% U2 B
+ y/ e7 Y; D. |* F/ A' Id3dFont.Italic=FALSE; 9 V- K! z& e! k - A# z0 I# h! d* r+ \3 J, a- Wd3dFont.CharSet=DEFAULT_CHARSET;5 V; Z8 `! g' I* l8 W
0 I0 K* N0 l2 |/ F
strcpy(d3dFont.FaceName,"Times New Roman"); $ K: g( f: S/ z: [+ K F4 G% L0 @ " Z0 b' i1 w' O3 [& ZID3DXFont* font=0;) S t( Q" X- a+ S( G, b
, z& |" S; f0 f8 z5 s9 w
D3DXCreateFontIndirect(Device,&d3dFont,&font); 3 B( h. ?, y9 E# h2 y% N 8 N3 Y' _& x# J: p" _% C: h4 P3 {% p* }! b
如果你使用的是LOGFONT结构,则: " X, w4 M$ P/ W" Q: z* K# G2 O( Y5 B# g6 C% `% B/ [
LOGFONT lf; f% N4 ~: A- s 9 H; t/ k- T0 U K8 v# v7 p' [/ y& iZeroMemory(&lf, sizeof(LOGFONT)); % X; @8 w o" p7 o - y+ m2 E7 w1 Y7 P" [+ e9 x% F j' q0 blf.lfHeight = 25; // in logical units ' y; K; e: n! n* i7 c# Q ~ ' K; ~9 A/ U) \lf.lfWidth = 12; // in logical units 9 Q8 |- D4 { c d" n: |+ d, E. { $ ]. p' e3 K* M! qlf.lfWeight = 500; // boldness, range 0(light) - 1000(bold)$ R/ A+ K. w( r+ `9 D3 K7 J
9 X9 U5 v. b$ w" ]/ G1 v4 wlf.lfItalic = false; , P9 ?% O: E5 t: C" w. ?8 y2 j7 h! [5 p' X0 [0 \; f
lf.lfUnderline = false;4 Z+ x$ q: U: x( i; F
6 B# ^ p7 l% x n* F: l/ v
lf.lfStrikeOut = false; 4 A3 q4 n! s n* ?% y9 \& J' c) d5 A9 x
lf.lfCharSet = DEFAULT_CHARSET; # A5 i2 E) _- N / @4 j5 x' F7 _( R- Istrcpy(lf.lfFaceName, "Times New Roman"); // font style7 A% F; {# b" a5 \, @. k! \
* p- y! w5 V8 L: b4 `8 k
ID3DXFont* font = 0; 4 z6 g; M# B0 m- G- I; A9 E1 ~8 r2 t
D3DXCreateFontIndirect(Device, &lf, &font); & i! |# ] R) s4 J + m% n/ [# G i
9 g6 V6 U4 i- t) x4 q, F c. m" T" H
另外,还可以使用D3DXCreateFont函数创建ID3DXFont的对象。 , b+ a# g* E' s1 X2 c* I " n3 q2 ~, H1 ]9.1.2. 绘制文字 - M' n$ t$ k; ^& j* y2 N3 I得到ID3DXFont接口后,绘制文字就很简单了,只需要调用ID3DXFont::DrawText方法: ) `( H' L" l! _5 m$ L0 i/ V) D: s9 V1 V0 L* N
INT ID3DXFont::DrawText( & s( T! x- Q5 B, V) V' j$ C& | ! W( x" W2 Q' R. W$ [: L- q, h LPD3DXSPRITE pSprite, ! q* e5 n$ X$ O5 D# l0 |% E+ h2 M" k3 V, i6 c
LPCTSTR pString,) ~2 _: S4 ~9 z* N6 @' {
. o. ^( x5 Y5 f$ L" y |7 V: ^
INT Count, 3 R" w1 t0 _5 B, B# w" d7 r+ @! y% ?) T9 F6 ^
LPRECT pRect,. N6 Q0 r. v- Z" `3 S
5 K c7 c, P3 o4 @' D4 M DWORD Format, 6 W9 s9 S8 ~* { d. y. ^; u* M9 a' p: l2 n# y* n; e
D3DCOLOR Color/ A/ D# w( s- l# j
( h* d/ y* y# L+ F6 A% k# D
); {/ _0 J. E4 }( A& S% d ! {: r* M, ]+ |7 z6 l; z3 F
3 R+ `3 K( @$ Z0 X' rl pSprite –输出目标,为ID3DXSprite对象指针,可以为NULL值,此时字符串输出到默认对象6 V$ H* W# [ n' b4 }% d' A# {
. Z1 D! l1 j8 ]* L3 O% u
l pString –需要输出的字符串 # X A& @8 Y* v+ N8 _) N / t$ Q3 X, A- p1 Pl Count –字符串的字符数,如果为-1,则以0字符为结束标志5 u$ P' o! E3 S( J9 w: ]
- U/ b1 _# k! L5 H1 p. e: E
l pRect –绘制字符串的区域 ) w9 G5 e2 b* w. E: ] I. y+ I; m7 R, m
l Format –文字的输出格式 & _* c+ |, v+ p, t8 W s& s7 i! n5 u% m' C( Q. `4 q
l Color –文字颜色# f+ q4 E6 z1 a" G
$ L5 Q/ J7 b; E: q8 }例如,可以这样使用该方法:$ C: a7 b' J# w. u
- F9 s1 u% ]- v- S3 _
Font->DrawText(NULL, 5 q. e8 \ t! X `2 p + `; A. T' A0 ]' ~& y "Hello World", // String to draw.2 I: y. `3 w9 S5 }9 w* [
( R' h+ b+ a1 e/ z& t% v -1, // Null terminating string.3 X$ ?/ j9 V; r4 Y2 p$ |
$ I& L' I$ Q7 @) h
&rect, // Rectangle to draw the string in. 2 i; F* F; s, T. B4 U+ P9 s k# z( K9 Y
DT_TOP | DT_LEFT, // Draw in top-left corner of rect.( L% \; R" l7 o
, _" N, Q6 `6 q' o3 j7 f* f9 c- y" B# E
0xff000000); // Black. % s4 y1 s+ D) o" h' ?; l7 k , q% h" f2 F8 [$ c c
- K% p7 {3 ?# E4 k, F
9.1.3. 计算帧速率, C! k! j! z6 |: B2 G6 r# D2 v3 g
帧速率用FPS(Frame per Second)表示。首先声明三个全局变量: ) U) T7 a9 n! L1 D5 K9 I( O& n" M }4 K# k% F& f
DWORD FrameCnt; // The number of frames that have occurred. 8 h3 f) [% i% S, i) o, v* C0 D5 w3 E3 Q+ C, D3 a
float TimeElapsed; // The time that has elapsed so far. . c* J6 u( L( c, j$ v( V ! ~( ?; U1 n7 w' W. ^2 hfloat FPS; // The frames rendered per second.& R2 s% Z8 d$ G, V# u2 t7 z
+ e& j2 g4 \; v
* w! W+ y) H. j3 c6 ?6 Q: {
每秒计算一次FPS,这里计算的是平均值。我们也可以有足够的时间去读FPS值,而不至于因FPS的快速变化而产生较大误差。- [ X- I c' u
0 i, R! N3 n- |9 Q" H
每渲染一帧,累加一次帧数和所用的时间值:6 O4 p' Q5 [7 m9 [) c
1 R v, n5 d5 L# y" ~FrameCnt++; , ~0 d# H, E4 h1 d. L8 j3 P8 I+ m$ R3 Y. z2 _
TimeElapsed += timeDelta;* m0 ?; b+ V# Z! E- c1 j. U
+ N; c3 W! V7 w3 J
3 j8 d+ w/ E2 C
这里的timeDelta表示两帧间的时间间隔。每过去一秒,就可以使用下面的公式计算FPS了: ; G3 I9 i. F/ V: S% S H* M ' `/ {& g5 d" N2 g+ nFPS = (float)FrameCnt / TimeElapsed;# j; v1 o3 O4 k4 W1 h+ b% j
" @7 E8 P; X7 A6 N& X : `. Z6 j P# w计算完成后,需要将FrameCnt和TimeElapsed重新置0,这样下一次的计算结果才正确:+ t' r2 V5 G' T0 n. x' o; `
; P- r1 I0 R2 i! O/ b6 k
void CalcFPS(float timeDelta)1 J2 l- e# o3 y) n1 x
' w4 g. ~4 L5 E) K9 x
{ 4 s1 ^& V( M/ ?: m p% G/ a; e5 o) e$ W+ P1 G5 q+ `
FrameCnt++; " x8 y u& p7 T7 e' b4 e4 C; t; ]
TimeElapsed += timeDelta;2 B) H4 D0 z' Y! P
; D) A" N! a) s- y/ n
if(TimeElapsed >= 1.0f)7 |( C9 S- |1 x. O2 k! n* _
/ |+ K( S( _7 u. P {6 Q- T5 \# [& B$ @2 O
% K8 k& I! _ d4 I1 t9 ?
FPS = (float)FrameCnt / TimeElapsed;) g- E1 Y& B9 |) B2 D
& p2 Z: s' k$ a. Q* s4 h* U" I
TimeElapsed = 0.0f; 1 m* B- o; b6 v/ w% S( g. C1 u5 r( R 6 S- C5 y5 A0 z! o$ R FrameCnt = 0; % N& D' M) ?+ t* s . f& p0 U; W, L3 C6 a( G } ( v) N9 C5 }! I0 q+ R. V# T7 `. }9 `1 z' y. N9 }
} 4 J. l, g. ]! k( H9 p. T- g 8 ?& ^% s! j! J) M- m
$ D( q, I; y- Z9 L4 Z6 J9.2. CD3DFont1 x2 w/ I. I( E e
在DirectX SDK的安装目录下,提供了很多有用的代码CD3DFont类就位于其中。该类使用纹理三角形和Direct3D渲染文字,而不是通过GDI渲染,所以,其效率高于ID3DXFont。但是,CD3DFont不支持复杂的字体和文本格式,如果只需要高速渲染简单的字体,CD3DFont应是首选。 ' d/ S5 p4 k; c5 p * j4 D/ w4 b0 C- i `! E- E, f使用CD3DFont类时,需要加入以下源文件:d3dfont.h,d3dfont.cpp,d3dutil.h,d3dutil.cpp,dxutil.h,dxutil.cpp。这些文件可在DirectX SDK的安装目录下找到。在DirectX 9.0 SDK Update (Summer 2004)中,该类却消失了,所以,该节内容只适用于较早的DirectX 9.0 SDK版本!: h/ D6 `9 v r. B3 K, X; J9 K
* `- q( z" J! K) }4 ^) ~9.2.1. 创建CD3DFont对象4 a/ q8 W/ Q. x
创建CD3DFont的对象,就像创建一个普通的C++对象一样,其构造函数如下:6 Q/ h1 c# F: b# \# h! I
3 ^% S: F0 ?; `- L4 a
CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L); 7 }) M2 d( ?# I' @- x' m- ] ; }6 n% Z7 v k
8 ] k3 ^( n; F
l strFontName –所使用的字体名称 # n0 X, ^3 ?8 `' X) p4 _* ]0 O6 k8 l' g; \" ~+ S& i, H$ o$ r
l dwHeight –字体高度7 O9 N" l3 [- @ _6 n% d' G, ]
- O3 y4 _, l4 c& E( H* @l dwFlags –可选的标志,如D3DFONT_BOLD、D3DFONT_ITALIC、D3DFONT_ZENABLE等。 0 {- ^7 ]# S9 @' [( V& b/ P + V) q3 ?: y" [得到CD3DFont对象后,还需按顺序进行初始化,如:) M9 Q# A* d. Y) D- ^
. x6 s+ E# m' h) F4 I7 E8 u5 E/ T
Font = new CD3DFont("Times New Roman", 16, 0); // instantiate( S* P: Y# A V5 k0 }) n
- Z' m ?, q5 g0 R. ~( xFont->InitDeviceObjects( Device ); * e% w5 u" N# W/ V ; i3 N4 y( |9 I6 Q3 Q+ F& L$ fFont->RestoreDeviceObjects(); , i" d, X4 M) O) W ; ^9 {- K' p4 u$ F' v' X: A5 m( X0 O, K+ P$ ?% ]
9.2.2. 绘制文字- r( z4 y# B! o9 j$ h
使用CD3DFont对象的如下方法渲染文字:9 O! S- A0 U! d) g% J* J
. c& k5 `% U- _/ d" DHRESULT CD3DFont::DrawText(FLOAT x, FLOAT y, DWORD dwColor, # C% K, V) h G4 @& ] ' \1 k% N- k* Q" y const TCHAR* strText, DWORD dwFlags=0L);; O6 p. P0 Q( Y8 ]$ M8 F' i
5 o5 I# a2 ?) V& h" R& \* B$ i, E Y; I6 z% V) u. k
l x –屏幕的x坐标9 h1 x5 p7 _( @# X. [
9 V7 Q2 t! k: ql y –屏幕的y坐标 ' u t ?0 x* g% A% D! U2 n& R( x/ D h. C, @9 j
l dwColor –文字的颜色4 D! f4 x( r& X% A; I
: d" f) t0 X' ]+ G3 T1 B j5 s
l strText –要绘制的字符串3 F5 R! y! u2 t# E5 r# v0 l/ a
( `3 F4 o6 ?: p: l2 X$ U. [( bl dwFlags –可选的渲染标志,可为0或下面的值:D3DFONT_CENTERED、D3DFONT_TWOSIDED、D3DFONT_FILTERED。2 z) J9 z5 w! A
. A% P! K8 N# m例如:. [. W' v0 S5 y+ r5 n
! d+ E+ k6 k8 p& V- ?) {, N: i
Font->DrawText(20, 20, 0xff000000, “Hello, World”);# W0 z' e# p* |1 ^3 B. O9 l
$ o( ~( i$ Q4 S% ilf.lfCharSet = DEFAULT_CHARSET; / H6 U! p2 L4 Q: ~ 2 N! j. S$ `$ Z# Y3 E- gstrcpy(lf.lfFaceName, "Times New Roman"); // font style8 `/ @6 Y: P! b9 c7 n+ X
" W c8 D+ e p, U$ {
// Create a font and select that font with the device context. W4 r: U6 V' q$ |
% H, y6 z M! g5 y% P, _3 l8 a
HFONT hFont;' g* y' O- W6 K# ~7 t7 f. x
; @ H1 D3 t1 [) D+ r N- UHFONT hFontOld; 0 N" j N' W+ a! `% s* c5 e; A* f ' t. j+ N& D8 t3 A* whFont = CreateFontIndirect(&lf); 5 m! d$ Q& ~* _( N h5 u3 D- A3 A' A, I
hFontOld = (HFONT)SelectObject(hdc, hFont);' ~: i2 P( Z( T% h) `: ]( k
& `. q& L$ n, a% e: x H// Create the 3D mesh of text. " t e; P) Y- p' Z, y; s ) _4 g; [ S# @( J4 z' JID3DXMesh* Text = 0;" m) h4 C" @# \* W
! v. Y, @( m5 ^( k/ ^6 ]
D3DXCreateText(_device, hdc, "Direct3D", 0.001f, 0.4f, &Text, 0, 0);# T# ]8 h; X0 t- a0 i
* Q. q1 s0 ^: X7 G8 I M// Reselect the old font, and free resources./ {6 S% G8 j* w+ U% R6 D1 z& M
: L$ ~6 Y$ M* y/ e
SelectObject(hdc, hFontOld); 3 j( U0 R- Z2 z + g, B% x, u$ Y4 A# O# {7 J6 bDeleteObject( hFont );8 A, D% w1 P6 e
. \/ H i/ q! ^DeleteDC( hdc ); 6 ] l, ]; t" |0 f. i/ z 9 }1 o& S# ?7 Z7 g! t' V7 @. n; Z% `3 b% t- B: T2 s
这时,Mesh对象已经得到了。最后,直接使用DrawSubset方法渲染即可: % w8 B5 |; K: } T5 o& ^% V+ d 3 r0 e$ L1 n& a" y# I. [; ]Text->DrawSubset( 0 ); 8 K! Z$ b6 O6 k* B 7 E5 e4 ?+ T: F% d1 V 3 `9 a. @3 H6 c( D译者注:上面的例子代码,使用的是较早的DirectX 9.0 SDK,不是Summer 2004版本。3 j9 R$ l# N0 e$ G3 r+ J; d" p, d
4 d) |! o; d8 R8 o! V( t0 T9.4. 总结 " i) F; h& I O6 a Dl 如果需要渲染较复杂的字体和格式,使用ID3DXFont接口会很方便。但是该接口是使用GDI实现的,故效率较低。# g2 I1 V8 H, `+ b/ u, a2 g
+ }; M9 l# ~4 e+ d+ b# Q
l CD3DFont类可以快速的渲染简单的字体。该类实用D3D的纹理三角形渲染文字,故速度较ID3DXFont为快。 B3 h5 Z7 I: S a& i3 ]$ l+ X2 d9 ^ P
l 使用D3DXCreateText函数可以创建文字的3D网格模型。