Nibiru经测试,用了OpenGL的wglUseFontBitmaps,glCallLists函数来显示文字。 % }4 ]* O- d) Q$ q* t$ j
也许是一个汉化的突破口? ( |# o; }$ E/ k( q2 F
* P) }, `+ g4 l0 Q---- 本文详细讨论了在OpenGL中显示文本的几种方法。
/ m1 q D! A4 ]1 K1 K: V5 Y3 O- b7 C1 X; g w: \' L
----也许大多数程序员使用OpenGL更多的是将精力集中于动态三维图形应用,因此,OpenGL中的文本显示往往被忽视,使人有不见积薪之感。本文介绍了几种文本显示的方法,希望能对使用OpenGL的编程者有所帮助。
' {/ g H+ H5 H
C$ a- F) U2 A% J1 L/ ?建立并修改程序
! _9 G' V3 ]5 \* [1 f2 [. C----建立一个MFC SDI Windows应用工程Text,除单文档属性外,使用其他的所有默认选择。在菜单Project打开Settings对话框,在Link属性页的 object/library modules编辑框中加入opengl32.lib glu32.lib glaux.lib三个GL库。我们利用这些库函数完成图形编辑工作。 & Q- E1 P* Q" b& Z7 ~; X
----为使VC++的AppWizard产生的SDI应用程序能使用 OpenGL绘图,还需要作一些修改,说明如下。 7 V! B: \' f* @4 W% ]
5 O, `$ q* v3 C0 b
----1.介绍PreCreateWindow函数 " R5 I& v, T8 t& A- V- V
, n$ `# ~: T$ _( {- Q
---- OpenGL窗口必须具有WS_CLIPCHILDREN(创建父窗口使用的Windows风格,用于重绘时剪裁子窗口所覆盖的区域)和WS_CLIPIBLINGS(创建子窗口使用的Windows风格,用于重绘时剪裁其他子窗口所覆盖的区域)两种风格。此外,窗口类属性不能包括CS_PARENTDC风格。具体程序实现如下:
4 Q* t) T% g: ]
A0 R+ m& d: I% e* v. n" QBOOL CTextView::PreCreateWindow
+ \; p$ p, t2 R. b(CREATESTRUCT& cs)
7 r9 C, H; z% F{
: [* g5 U! D3 V, O- z" T8 d- _' ~// TODO: Modify the Window class or styles here by modifying % L% A4 |- q8 ^9 [" H
// the CREATESTRUCT cs $ n( o2 w# |4 K( v7 S
3 q" \6 t& V6 y2 ^5 H/ ]) A% [8 T" }//An OpenGL window must be created with the following flag
7 [( e' D% ]3 J// and must not include CS_PARENTIDC for the class style. - r. E6 Z4 O! G: g+ w8 B
cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
3 I! h" ?& q+ K1 D% M5 \
3 ?4 O* M" u# p% u, E* A% \return CView::PreCreateWindow(cs);
/ U( h1 ]6 G4 E% N4 d3 ?}
2 @- J3 W0 |7 A' n0 T( n0 W4 @
. ]8 q. j& Q' U6 H6 x" e, T1 k----2.OnCreate函数中定义像素格式PIXELFORMAT和创建 RC
8 y3 Y+ B! k: Z" Q: y( Y
3 c- y( a; p- Z( W3 s$ V----要使窗口支持OpenGL绘图,必须对窗口进行初始化。其中包括定义像素格式PIXELFORMAT和创建RC,为OpenGL指定一个合适的像素格式,创建着色上下文并将它和窗口的设备上下文关联起来。着色上下文保存着当前着色环境的信息。可在OnCreate中调用一个自建视口成员函数SetupPixelFormat(),具体函数如下:
- h, v0 C& f$ ]( X2 o$ J& V; {1 r# ?( P3 f' y1 x4 K
BOOL CTextView::SetupPixelFormat() 8 S; g( Y2 _% v7 ~# m/ K5 U. H
{
$ B9 s- z" w# `* f4 Z ^6 X//Create a rendering context % j4 {" M9 Y0 [$ ?0 e5 x0 L$ a
CDC* m_pDC=GetDC();
7 \/ H b( o1 ~ t. i/ vif(m_pDC==NULL) //failure to get DC
# }2 |% g3 S# p& D7 L; j{ 7 y8 E8 i2 q5 o- t" C. S' _( m
MessageBox(“Could't get a valid DC.");
, e! X& m" P, H9 } j" R; Xreturn FALSE; ) S- T2 c) X3 ]
} 0 ]7 K! d4 ?$ _; Q0 l# |
" ^6 b$ X- [$ y/ q9 Q* o! w//Default pixel format is a single-buffered, / N+ w- {; X k1 [$ w4 S
//OpenGL support hardware-accelerated,RGBA mode format
8 ~ m" }( h/ w1 A7 D jPIXELFORMATDESCRIPTOR pfd = ( C. w3 `1 g+ C) A8 y# {
{
4 I9 u0 K- D6 wsizeof(PIXELFORMATDESCRIPTOR),//Structure size. & X p8 [/ g G/ |) _! I; }4 Z8 G/ m
1, + S& C4 t2 \" e- E k/ O
// Structure version number.Property flags(特性标志):
5 m! s L$ X! z! A+ K, }- t) PPFD_DRAW_TO_WINDOW | // support window
2 j: r( p# }% ^3 ~ P7 zPFD_SUPPORT_OPENGL | // support OpenGL
8 ]; f0 T O, v; J2 R7 [3 UPFD_DOUBLEBUFFER, ! K8 y) i1 n+ D* z. h6 A- ]
PFD_TYPE_RGBA, // RGBA type " T" Z+ K p J7 L& f
24, // 32-bit color. 3 q' `' v: ] Z( }8 v
0, 0, 0, 0, 0, 0, // Not concerned with these:不涉及的属性 ( a* _ _0 [% ?
0, // No alpha :无alpha缓存 . a \+ ^) j" s( I% _+ H d
0, // Shift bit ignored:忽略转换位 2 Q! N+ M& p5 q& ?. ?; B8 \/ b, P2 C
0, 0, 0, 0, 0,// No accum buffer:没有累积缓存 2 e* t4 H( K9 L- {# `: u1 Y
32, // 32-bit depth buffer. * N+ T& O5 y# R7 d0 a* C
0, // No stencil:无模板缓存
% s4 n$ u: y' g9 s# Z' H+ G0, // No auxliliary buffers:无辅助缓存
( i8 ]+ A! D3 C# p4 V* u8 DPFD_MAIN_PLANE, // Main layer type.:主层类型 ; l9 X5 i9 A5 L d) q
0, // Reserved.:保留结构数 # [3 M5 ^6 C: |9 l/ _
0, 0, 0 // Unsupported.:不支持结构数
- H( D$ }# [7 A5 J" X6 q) H};
0 {# G- Q1 s" k1 A! Zint nPixelFormat=
8 t: H2 H" @) x3 GChoosePixelFormat(m_pDC->GetSafeHdc(),&pfd);
# `# R ?( u1 S4 o7 f9 Qif( nPixelFormat ==0)
& s1 a( W( ]' r7 ~: x. K{
% v; O a5 P- s" i7 LMessageBox(“ChoosePixelFormat failed.");
) Q, k; ?5 h& n% D treturn FALSE; a9 {/ G* G3 U4 {) n6 {
} / k/ i, \2 s$ O5 a( ~
6 G* I8 S& `- x* x6 iif(SetPixelFormat(m_pDC->GetSafeHdc(), % H5 e6 t! V2 e0 I! v
nPixelFormat,&pfd)==0) 9 V: G% E0 g+ @
{
O0 J# r, k; m, w: cMessageBox(“SetPixelFormat failed.");
* @ f- X- g+ |3 e4 }/ O$ Sreturn FALSE;
5 Z, H9 Y$ P5 v, `7 A8 _" ]6 F}
1 D3 b& S$ F H) @+ V# I$ r
* a8 E, A8 B# I9 x! v% N+ qif( (m_hRC=wglCreateContext(m_pDC-> ( h0 d' O1 F7 U0 p5 P, m- V/ A7 z" M
GetSafeHdc())) ==0) + e+ r. z d# Y* X) L" N- B
{ . U+ r' ?9 T' ~& _! B
MessageBox(“wglCreateContext failed.");
9 B& ?' o2 f1 ~/ ^4 E- C B rreturn FALSE; 2 ^5 I& r$ u" f0 Q( {' y& [
} * N% J8 h$ \. G0 i) K
if( (wglMakeCurrent(m_pDC->GetSafeHdc(),m_hRC)) ==0)
% ]* W# V$ \! _& i6 o{ # T% ]2 P! _1 h8 y, K) p4 c0 E
MessageBox(“wglMakeCurrent failed."); / _+ z2 D: P4 W. l
return FALSE;
9 I+ _: {# U+ J} 5 a0 C3 u2 m1 G2 _
4 }. A4 Q8 i! ~ Q& p, @if(m_pDC) ReleaseDC(m_pDC); $ a6 l' l/ ?0 e5 Q* i: c( d
return TRUE; ; q1 g, h3 N6 i4 z% @
} ! j( A: o9 [! H2 m( @& s
* S' ]! s9 S' {/ d: q% j
----3.在OnCreate()函数中调用初始化背景函数 InitializeOpenGL() 3 H# x3 v( d6 `/ R ?9 S7 B- H
# u5 Q1 i" }+ }% |8 qvoid CTextView::InitializeOpenGL() ( n* D* f/ m, ?7 O# e d
{
9 Y) s$ T- F* \) T7 E4 ]glClearColor(0.2f,0.2f,0.2f,0.0f); . z0 d! k1 d6 b$ c5 h1 n
glClearDepth(1.0);
4 i& I" J0 g, k! tglDepthFunc(GL_LESS); ! R5 _% |- d1 j8 z0 p9 N, r2 }3 W
glEnable(GL_DEPTH_TEST); : U1 r! r' T3 _3 _; |5 i
glShadeModel(GL_SMOOTH);
4 c6 y0 R/ f5 ^- w}
, ]8 j# j o" F9 j* M+ [
) w' V* C) _3 U+ B; }; w5 l----4.在OnCreate()中启动动画定时器
0 Z$ E I+ ^1 J- p
) X$ X8 y% r2 u9 ASetTimer(0,40,NULL);
; o7 o0 y0 N+ F# v3 b% X+ [$ r6 q( }& y- ~2 Z; P
----5.在收到WM_SIZE消息时要重新计算场景尺寸,用OnSize 设置图形显示模式
- d" _$ ]" f( X* H/ b) F; W: Z8 R7 Q4 j: i; ]
----为了使物体能合适的显示,必须要经过投影和确定视口的工作。
* S4 m" C7 X5 M/ y' F8 d1 F/ I1 C0 u9 N, Z. _3 C2 p
void CTextView::OnSize(UINT nType, int cx, int cy)
: h* ~$ F9 ]+ z, S% o7 {{ ; n; d, Z* H5 n2 |
CView::OnSize(nType, cx, cy); 7 \$ c. Y, {( ^3 ?. u, D* l
" ]. T' u$ J$ g- N [+ F9 W// TODO: Add your message handler code here
8 F3 D3 ]) s1 W. b# s i//Save the wide and height of the current window Client 2 V+ c0 L4 s4 C+ u% O
GLsizei nWidth=(GLsizei)cx; ( T" [8 G' d9 ]- E- Z5 G4 H' o
GLsizei nHeight=(GLsizei)cy; 1 U) c6 n7 S' w% Z
ratio=(double)cx/(double)cy; # e: e* @; r( m: D, ]
2 A- Y2 B& _* l. r0 R
//Coupute the aspect ratio , `! ]( E- j) h0 _
GLdouble dAspect=(GLdouble)nWidth/(GLdouble)nHeight; 8 r, z: W0 l( n' W6 C; o4 }, k
+ d% C; |# J( |1 Q- G
glViewport(0,0,nWidth,nHeight); : E5 S! p3 M' c3 K
glMatrixMode(GL_PROJECTION);
3 c3 l3 m# e! @6 }- q. g+ eglLoadIdentity();
" Y) c- ]( B& \/ i/ O/ QgluPerspective 6 ` ^# a+ j# V3 A
(FOV,dAspect,NEARPLANE,FARPLANE);
i U# g5 Y/ u8 a8 n
: H* F0 J) x+ ~, k) l* UglMatrixMode(GL_MODELVIEW); ( p5 k! B; S; H( l4 e2 M
glLoadIdentity(); 1 \! s, h# k$ r, X5 I$ M: p( c
}
: @ j7 Q) J* f& ^
# ~$ E: I' m/ t, R& b- l# G----6.在OnDraw()中简单调用DrawScene()以执行OpenGL函数
1 y& W3 @/ G! K( t, P$ `" O4 B6 H# m" c9 J
void CTextView::OnDraw(CDC* pDC) + z5 }& b3 S, Y0 q2 D3 F8 I# ~
{ 1 \4 h- u* ^& I @
CTextDoc* pDoc = GetDocument();
3 O- B& ] q: v* R1 ^- f( ]ASSERT_VALID(pDoc);
. T; c+ ], V4 M" n7 ]: D" j
/ g( O7 [* u+ _ e. s4 L5 ^+ I6 U// TODO: add draw code for native data here
' W& `! a6 w0 [1 o, kDrawScene(); / U n5 [% @' |9 K8 e
//Invalidate();
: ~4 L" U/ X2 e5 J: }0 t9 d}
$ b& ^0 m( ?1 B! g% [8 {, ]' a$ F/ ~8 W6 I1 t" S; c
----7.撤销视窗时删除上下文并撤销定时器
6 E7 S* E7 y F" p) f( `, A4 b0 B( Z: N2 U
void CTextView::OnDestroy() # z: d" S6 \8 l, a4 `- M
{ 0 r3 E% E7 i/ |( A
CView::OnDestroy();
: O# M$ v3 U9 w* c" @/ Z& y, P& o+ ^3 I
// TODO: Add your message handler code here 3 U- s- e9 e) l* Q5 [
//This call makes the current RC not current 9 C- i8 n7 }) M7 E8 D6 F T
if(wglMakeCurrent(0,0)==FALSE)
; ~+ y% L. ~6 z' VMessageBox(“wglMakeCurrent failed.");
3 n$ i7 [* _3 q) u$ k$ D
; a$ I: C( l4 k |4 S5 ?( n//delete the RC
$ c* ]5 L, o; ]/ J( M+ h1 ~1 h9 f! H' n% hif(m_hRC && (wglDeleteContext(m_hRC)==FALSE)) 3 O$ A, R N6 t" J) G7 ?# `
MessageBox(“wglDeleteContext fail.");
$ O B) D/ p& S6 X0 k! A- H* O0 dKillTimer(1); 8 w, F, X9 W, D' ^1 a: |
} - V. i! |% }" l3 A' c5 X& }) b
. h, M! i' g8 c$ G0 R% V) [ Y
----8.当40ms定时器时间到时,简单地将整个场景的客户区置无效,使之重画 ' Q$ i/ S! T* K* h6 U
/ G1 k! _( \5 N1 f
void CTextView::OnTimer(UINT nIDEvent) _, Y6 T5 `+ g
{
4 y& t( X# F3 j) i. A" @3 @+ V// TODO: Add your message handler code here and/or call default & @( Z6 W/ A3 c
Invalidate(); 7 M, f/ w5 l; V5 v/ m
CView::OnTimer(nIDEvent);
& W5 X4 r5 B: G, i7 G}
! C) F4 S$ Y m% L; l2 S4 O8 N: U! Y# @8 |, k0 H% U6 l: r7 H
修改界面
3 a, y3 R; A# X/ {---- 删除菜单IDR_MAINFRAME中File下除去Exit菜单项外的所有选项,添加“显示GDI文字” “列表制作文字”“列表三维文字”三个菜单项,并给他们分配适当的ID。使用ClassWizard为这三个菜单项在视类中添加命令处理函数和界面更新函数,其中显示GDI文字的对应的函数如下: ) L1 p3 f Q. j+ y7 \1 x; g
void CTextView::OnGdiText()
+ g3 x/ k) S* }( K8 w6 i{
6 [. W7 p/ }9 x; C; M// TODO: Add your command handler code here
5 l s: R) Z5 u8 A% }! O" sm_iWhichText=0;
; C1 S7 m0 Q3 R uInvalidate();
& p+ s+ }: f y1 i, `9 c}
2 @0 M T# I% N M* B- P. b% j( P4 w& o& H. @- s
void CTextView::OnUpdateGdiText(CCmdUI* pCmdUI) - }- i, B5 E$ L3 S, I. [3 G
{ 2 S+ d9 r; h, ^# a: A- r
// TODO: Add your command update UI handler code here
, M2 m9 ~6 N6 w: X6 `if(m_iWhichText==0) pCmdUI->SetCheck(); " F+ Z/ D- ~, A, L
else pCmdUI->SetCheck(0); 0 E& F: x/ ?% a/ Q
} % j1 N5 T& I# W' ^, L1 j
0 _! A; t. t' M, P" R5 @
----增加Draw3DText()、DrawListText()和DrawGdiText()三个函数用于三种不同的文本绘制方法。增加DrawScene()函数,它被OnDraw函数调用,用于绘制场景。在DrawScene()函数中,当m_iWhichText为0、1、2时,分别调用 DrawGdiText()、DrawListText()和Draw3DText()显示文本。具体函数实现如下: : q) H7 R7 Z% n4 a2 H2 s) y* L" g
+ i6 _; ~1 |. A% P& Cvoid CTextView::OnDraw(CDC* pDC) # c- W7 h* m- ~
{
) F6 L, k0 q/ U& PCTextDoc* pDoc = GetDocument();
5 X4 A; H! p) m7 [/ WASSERT_VALID(pDoc);
, z* W5 W$ d9 y [2 G' Z: y) ?* L) l" b, y
// TODO: add draw code for native data here " _9 Z8 y7 ]0 e' A, [1 m
DrawScene();
1 V& F2 d) S# z+ R# ]3 } {, P//Invalidate();
# W9 R' t: r; t) ?} , a8 `7 F2 n' w2 z+ J- D/ a
r; [! @7 Z+ R! e2 W- Nvoid CTextView::DrawScene()
' S8 c' ~6 x5 h2 Q, W( X, e{ 2 V+ J% g$ H3 S. T; \2 F# R5 e1 G
glClear
& b. Y n% L- @(GL_COLOR_BUFFERBIT|GL_DEPTH_BUFFER_BIT);
4 h( A) x2 ^8 r. x; t$ n8 n6 ~
6 ]. M' O8 a4 L8 n7 c& sglPushMatrix(); 6 B w- n, d F- T2 `3 T
glTranslatef(0.0f,0.0f,-FARPLANE); 5 l, X5 ?; A% O" c' {" A3 W9 s h
//TextureMap(); 5 Q- C% o3 K& O" Y
glPopMatrix();
4 H! j: p6 u, A, L9 EglPushMatrix(); ( L5 I+ i- g" M
glTranslatef $ b% N9 [, `0 L8 t1 X. E
(0.0f,0.0f,-(FARPLANE+NEARPLANE)/2); 8 A# E$ Y j9 j/ ^+ _: R1 A8 n1 [1 ]2 W
9 y+ L$ ^; W. x9 j0 H- Gif(m_iWhichText==1) DrawListText(); $ N* @0 }9 M% l8 c& Y3 Z
if(m_iWhichText==2) Draw3DText();
5 @6 @2 j4 h2 X Y' ^) D3 V) @glPopMatrix(); 8 ?/ f5 A1 m- t, j% K- G
glFinish(); . Q3 l3 F6 S, k$ j' s
SwapBuffers(wglGetCurrentDC()); ' u' j; \7 d6 ?$ G
8 Y) D1 {0 k- `if(m_iWhichText==0) DrawGdiText();
/ M8 E& w4 e% \9 W1 i' }( \}
! g5 B7 ]5 e, g# B( E- U& q# y! q: V6 `6 n* C% _9 g5 i L! d
GDI 显示文本 ) Y" Q9 ~0 _; K
---- 调用wglGetCurrentDC()函数取得当前的设备上下文,使用TextOut函数显示文本,不过要注意在DoubleBuffer模式下,绘制函数要在glFinish()和 SwapBuffers(wglGetCurrentDC())函数之后调用,否则会产生闪烁,在绘制OpenGL结束之前使用GDI函数,要除去闪烁则只能使用SingleBuffer模式,具体函数如下: " ?6 v( L M7 L+ @
void CTextView::DrawGdiText() 1 D- Z p9 n7 R2 m3 d5 o
{ 3 x: F( j" u0 p/ ^" u7 ^
HDC hdc=wglGetCurrentDC();
5 c, w8 d: _; o! R: m5 I b j/ o::SetBkMode( hdc, TRANSPARENT );
$ C0 a, ?, R: Q% Q::SetTextColor( hdc, RGB(250,0,0) );
; a1 `7 N- ~ z; ?. b/ |0 d% O/ y( O) P3 @3 |
CString sState(“显示GDI文本。");
$ s2 k+ f; |% \ V2 c7 |::TextOut(hdc,5,5,sState,sState.GetLength());
5 z, @3 k& s1 A5 p}
3 X5 B5 ~/ A, ]; m! \ ^2 b! c4 I0 q* l: c5 X
wglUseFontBitmaps / Z4 i4 t6 m/ T2 R1 \1 \
函数显示文字
! D* [! W' P& a----使用wglUseFontBitmaps()将ASCII字符装入显示列表,然后使用glCallLists()函数利用显示列表序列显示文本。wglUseFontBitmaps有四个参数,分别是当前使用的DC、从第几个ASCII字符起始装入列表、装入列表的ASCII字符数和起始的列表序号。glListBase()指定glCallLists执行的起始列表序列号。glCallLists()含有三个参数:执行列表序列的个数、列表值的类型和所要显示的文本。注意如果所要显示的文本是字符串,它所提供的信息是相对于起始装入ASCII字符的偏移量,因此最终所显示的ASCII字符是从glListBase()所指定的列表起始号在经过glCallLists()中偏移后的列表,因此wglUseFontBitmaps的从第几个ASCII字符起始装入列表参数、glListBase()指定的 glCallLists执行的起始列表序列号和glCallLists()中的所要显示的文本参数都可以影响最终显示结果。由于显示的是ASCII 字符,因此不能显示汉字。glRasterPos3f函数决定在 OpenGL视景体坐标系下的偏移。具体函数实现如下: 1 k$ }5 Q/ a: J) b) N
void CTextView::DrawListText() 9 v2 ~, y& X, V' ~; U
{
# Z) A+ s' K( h1 Y( C- J# ]0 FwglUseFontBitmaps(wglGetCurrentDC(),0,256,1000); - z7 p* {9 [" z' C
glListBase(1000); 2 c) E% M* m& m/ e/ P
glRasterPos3f(-5.0f,0.0f,0.0f);
* c/ U9 W% |9 M$ [glCallLists(20,GL_UNSIGNED ) s3 V8 X6 i# v+ B& g. w
_BYTE,“Draw with List Text.");
: E( _1 t Z3 G) }& W( S4 n} & K- s( R; @) C/ M. T+ s0 Z% ^9 w
, m$ O! l }+ u' D+ {) YwglUseFontOutlines 5 j& z3 d: N2 o, @; z3 F% i. T
函数显示三维文字 : p$ _. q1 I1 U6 b. z4 l
----wglUseFontOutlines使得OpenGL可以显示三维文字。它的用法与wglUseFontBitmaps函数大致相同,但是多了内插计算参数、字体深度、显示方式和装载字模的缓存四个参数,且只能显示TrueType字体,显示前应该先选择字体类型。具体函数实现如下:
/ b* n; Q7 g' \9 n6 wvoid CTextView::Draw3DText() 6 v( `$ K; n+ Q9 C
{ $ A; p5 S+ {2 J: X
GLYPHMETRICSFLOAT agmf[256];
" J) \) G0 G' n: B+ V// create display lists for glyphs 0 through 255
" o e" g5 c, v( }; ?9 v// with 0.1 extrusion and default deviation. ; z' L8 [2 J, w5 a; c
//The display list numbering starts at 1000
6 O3 X' W1 u9 N. S9 }* `+ G5 n+ i/ W(it could be any number)
6 A& ^: _5 d2 V! w1 i8 ?0 WwglUseFontOutlines(wglGetCurrentDC(),
) w. n' {+ T+ w! n5 Q, F) E4 b/ c' I0,255,1000,0.3f,0.8f, WGL_FONT_LINES ,agmf); + q; M6 ?7 B" z* H& f
0 ]' e* M' `/ l M0 m& L
// Set up transformation to draw the string
/ d+ f. c' F! i8 u( G$ K5 ZglTranslatef(-15.0f,0.0f,0.0f); 2 Q7 x" r9 t( l9 \
glScalef(4.0f, 4.0f, 4.0f); 1 ?2 V" ]* \0 L
// Display a string 6 f6 v' P6 ~6 V7 i
glListBase(1000); 2 @2 ^& C- W# g8 D7 J1 W
// Indicates the start of display lists for the glyphs . \6 y; L6 T) G7 n* f& U' x
// Draw the characters in a string 2 C( J. [3 Y1 y; m' A$ v2 s# K
; @, Q$ e- D) H4 y4 x7 D
glCallLists(26, GL_UNSIGNED_BYTE,
2 P! J8 u5 J3 W* y+ O; g“Draw outline list 3D text."); 6 F4 t9 S( p% D- ?. b" L. [
} |