游戏开发论坛

 找回密码
 立即注册
搜索
查看: 6628|回复: 6

NeHe OpenGL Tutorial lesson 13[原创]

[复制链接]

19

主题

106

帖子

111

积分

注册会员

Rank: 2

积分
111
发表于 2004-10-7 01:53:00 | 显示全部楼层 |阅读模式
呵呵,刚刚写完的呢。(由于即将用到字体的绘制,所以先译了这个)
第一时间在我的blog上发了,呵呵。
恩,也传了一份给 江超宇 (Aman JIANG)前辈,
我相信 江超宇 (Aman JIANG)前辈会把我的译版也放在他的页子上面的,呵呵恩我该去睡觉了阿
大家慢慢看 。

sea_bug及各位前辈,多多批评,多多指正阿。

sf_200410715341.rar

37.67 KB, 下载次数:

19

主题

106

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2004-10-7 01:58:00 | 显示全部楼层

Re:NeHe OpenGL Tutorial lesson 13[原创]




NeHe
OpenGL
Tutorial


by NeHe






原著 Jeff Molofee (NeHe) http://nehe.gamedev.net/
nehe@connect.ab.ca
译著 戴瑞 DaiRui  (Terry)    QQ: 21240154
my blog:   http://the_eternal_god.blogone.net
e-mail addr:  terryd1983@yahoo.com.cn
the_eternal_god@163.com
the_eternal_god @hotmail.com


Version 1.0.0

Preface
这是我第一次进行翻译,呵呵,在这里首先感谢原著作者Jeff Molofee (NeHe),为我们提供了很好的学习材料,其次我要感谢江超宇 (Aman JIANG),是他给了我想要进行翻译的冲动。恩,还要感谢我的一位网友七七(PP)她在我翻译过程中很热心的听我解释并提出自己的看法,Terry特地向她表示感谢。
下面是原文的保留字。
Originally compiled by LOneWoolf
Recompiled by M0RPhEuS

The lessons on this page may contain mistakes, poor commenting, and should not be considered the best resource to learn OpenGL from. What you do with the code is up to you. I am merely trying to make the learning process a little easier for those people new to OpenGL. If you are serious about learning OpenGL, you should spend the money and invest in the OpenGL Red Book (ISBN 0-201-46138-2) and OpenGL Blue Book (ISBN 0-201-46140-4). I have the second edition of each book, and although they can be difficult for the new OpenGL programmer to understand, they are by far the best books written on the subject of OpenGL. Another book I would recommend is the OpenGL Superbible, although opinions vary. It is also important that you have a solid understanding of the language you plan to use. Although I do comment the non-GL lines, I am self-taught, and may not always write proper or even good code. It's up to you to take what you have learned from this site and apply it to projects of your own. Play around with the code, read books, ask me questions if need be. Once you have surpassed the code on this site or even before, check out some of the more professional sites such as OpenGL.org. Also be sure to visit the many OpenGL links on my page. Each site I link to is an incredible asset the OpenGL community. Most of these sites are run by talented individuals that not only know their GL, they also program alot better than I do. Please keep all of this in mind while browsing my site. I hope you enjoy what I have to offer, and hope to see projects created by yourself in the near future!

One final note, if you see code that you feel is to similar to someone else's code, please contact me. I assure you, any code I borrow from or learn from either comes from the MSDN or from sites created to help teach people in a similar way that my site teaches GL. I never intentionally take code, and never would without giving the proper person credit. There may be instances where I get code from a free site not knowing that site took it from someone else, so if that happens, please contact me. I will either rewrite the code, or remove it from my program. Most the code should be original however, I only borrow when I absolutely have no idea how to accomplish something, and even then I make sure I understand the code before I decide to include it in my program. If you spot mistakes in any of the lessons, no matter how tiny the mistake may be, please let me know.

One important thing to note about my base code is that it was written in 1997. It has undergone many changes, and it is definitely not borrowed from any other sites. It will more than likely be altered in the future. If I am not the one that modifies it, the person responsible for the changes will be credited.
Lesson 13
Bitmap Fonts:

原文Index中的前言:
I think the question I get asked most often in email is "how can I display text on the screen using OpenGL?". You could always texture map text onto your screen. Of course you have very little control over the text, and unless you're good at blending, the text usually ends up mixing with the images on the screen. If you'd like an easy way to write the text you want anywhere you want on the screen in any color you want, using any of your computers built in fonts, then this tutorial is definitely for you. Bitmaps font's are 2D scalable fonts, they can not be rotated. They always face forward.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




正文:
Welcome to yet another Tutorial. This time on I'll be teaching you how to use Bitmap Fonts. You may be saying to yourself "what's so hard about putting text onto the screen". If you've ever tried it, it's not that easy!
欢迎进入教程新的一课。这次我将告诉你如何使用位图字体(原文Bitmap Fonts)。你或许会自言自语道:“在屏幕上绘制字符(原文:text文本)有什么困难的。”但是,如果你尝试过的话,你会发现,它的确不是那么容易的呢!

Sure you can load up an art program, write text onto an image, load the image into your OpenGL program, turn on blending then map the text onto the screen. But this is time consuming, the final result usually looks blurry or blocky depending on the type of filtering you use, and unless your image has an alpha channel your text will end up transparent (blended with the objects on the screen) once it's mapped to the screen.
当然,你可以使用一个图像处理程序(原文: an art program),把文字(text)写在一幅图(原文: an image)上,然后把这幅图像载入到你的OpenGL程序[Terry:就是你正在写的,使用到OpenGL程序]里面。

If you've ever used Wordpad, Microsoft Word or some other Word Processor, you may have noticed all the different types of Font's available. This tutorial will teach you how to use the exact same fonts in your own OpenGL programs. As a matter of fact... Any font you install on your computer can be used in your demos.
如果你曾用过“写字板”(Wordpad,Windows的写字板程序),Microsoft Word(Terry:微软Word)或者别的什么字处理软件的话,你或许已经注意到了他们都支持很多不同的可选字体。这一课将教你怎样在你的程序里使用那些特定字体。 实际上,你可以在你的程序中使用在你机器上安装的任何字体。

Not only do Bitmap Fonts looks 100 times better than graphical fonts (textures). You can change the text on the fly. No need to make textures for each word or letter you want to write to the screen. Just position the text, and use my handy new gl command to display the text on the screen.
“位图字体(原文Bitmap Fonts)”可不仅仅是比“图形字体”[原文:graphical font (textures)]看起来好一百倍。[Terry:其实就是前面所述的那种使用image的方法]

你还可以频繁地改变文字(原文:the text) [Terry:原文说是:“You can change the text on the fly.”,字典中,把on the fly解释为“匆忙的”,呵呵我还是觉得写成“频繁”的好] 。
你没有必要再为每个你想要的单词或是字母创建纹理了,你要做得仅仅只是确定显示得位置,然后使用我现成的gl命令(原文: gl command)来在屏幕上显示那些文字。

I tried to make the command as simple as possible. All you do is type glPrint("Hello"). It's that easy. Anyways. You can tell by the long intro that I'm pretty happy with this tutorial. It took me roughly 1 1/2 hours to create the program. Why so long? Because there is literally no information available on using Bitmap Fonts, unless of course you enjoy MFC code. In order to keep the code simple I decided it would be nice if I wrote it all in simple to understand C code
我尽力使得命令能够简单。你所需要做的只是敲入glPrint("Hello"),这是多么简单啊。恩,通过这么长的介绍,你可以发现我因为写了这一课而感到非常的高兴呢。[Terry: 原文为“Anyways. You can tell by the long intro that I'm pretty happy with this tutorial.”,但是我觉得自己译得还不够“信达雅”]。恩,写这个程序花了我大概一个半小时。为什么会花这么长时间呢?因为,关于使用“位图字体(原文Bitmap Fonts)”,没有现成可用的文字信息,当然除非你喜欢MFC的代码[Terry:“当然除非你喜欢MFC的代码”, 我还没搞明白呢]。为了保持代码简单,我觉得自己使用简单易懂的C代码来写程序会比较好,于是我使用了C代码。

A small note, this code is Windows specific. It uses the wgl functions of Windows to build the font. Apparently Apple has agl support that should do the same thing, and X has glx. Unfortunately I can't guarantee this code is portable. If anyone has platform independant code to draw fonts to the screen, send it my way and I'll write another font tutorial.
这里小小的提示一下,这个代码是针对Windows的。它使用了Windows wgl函数建立字体。当然[Terry:原文:“Apparently”,“显然”,我觉得还是用“当然”好],苹果有agl支持,X有glx,它们都完成和wgl同样的事情。[Terry: 我不知道X是什么是X window,是不是用于Unix的窗口阿?]但不幸的是,我不能保证这个代码的可移植性[Terry: 就是不一定可以用在别的平台上],如果谁写出了绘制字体的与平台无关的代码,请把它发给我,我将再写一篇关于字体的教程。

We start off with the typical code from lesson 1. We'll be adding the stdio.h header file for standard input/output operations; the stdarg.h header file to parse the text and convert variables to text, and finally the math.h header file so we can move the text around the screen using SIN and COS.
还是从第一课的代码开始吧。 我们将包含stdio.h头文件以使用标准的 输入/输出 操作(stdio.h头文件分析文本并把变量转换为文本)然后包含math.h头文件,这样我们就可以使用SIN 和 COS把文字在屏幕上移来移去了[Terry: SIN,COS应该是正弦函数和余弦函数]。


#include <windows.h>                // Header File For Windows
#include <math.h>                        // Header File For Windows Math Library
#include <stdio.h>                        // Header File For Standard Input/Output
#include <stdarg.h>                        // Header File For Variable Argument Routines
#include <gl\gl.h>                        // Header File For The OpenGL32 Library
#include <gl\glu.h>                        // Header File For The GLu32 Library
#include <gl\glaux.h>                // Header File For The Glaux Library

HDC                        hDC=NULL;                // Private GDI Device Context
HGLRC                hRC=NULL;                // Permanent Rendering Context
HWND                hWnd=NULL;                // Holds Our Window Handle
HINSTANCE        hInstance;                // Holds The Instance Of The Application


We're going to add 3 new variables as well. base will hold the number of the first display list we create. Each character requires it's own display list. The character 'A' is 65 in the display list, 'B' is 66, 'C' is 67, etc. So 'A' would be stored in display list base+65.
我们还将添加3个新的变量。Base将用来存储我们创建的第一个显示列表的数字[Terry:应该相当于基地址]。每个字符需要她自己的显示列表。字符’A’在显示列表里是65,’B’是66,’C’是67,等等。所以’A’将存储在显示列表 base+65。

Next we add two counters (cnt1 & cnt2). These counters will count up at different rates, and are used to move the text around the screen using SIN and COS. This creates a semi-random looking movement on the screen. We'll also use the counters to control the color of the letters (more on this later).
接下来,我们添加两个计数器(cnt1 & cnt2)。这些计数器将按不同的变化率计数,我们将使用它们并使用SIN和COS来在屏幕上移动文字。这样就我们就创建了文字在屏幕上半随机的运动[Terry: 原文:“semi-random”,应该就是一种伪随机]。我们还是用这两个计数器来控制字母的颜色(后文将详述)。


GLuint        base;                                // Base Display List For The Font Set
GLfloat        cnt1;                                // 1st Counter Used To Move Text & For Coloring
GLfloat        cnt2;                                // 2nd Counter Used To Move Text & For Coloring

bool        keys[256];                        // Array Used For The Keyboard Routine
bool        active=TRUE;                // Window Active Flag Set To TRUE By Default
bool        fullscreen=TRUE;        // Fullscreen Flag Set To Fullscreen Mode By Default

LRESULT        CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);        // Declaration For WndProc


The following section of code builds the actual font. This was the most difficult part of the code to write. 'HFONT font' in simple english tells Windows we are going to be manipulating a Windows font. oldfont is used for good house keeping.
下面的代码建立了字体。这是我写的代码里面最困难的部分了。’HFONT font’告诉Windows我们将要操作一个Windows字体。HFONT        oldfont是用较好的完成内务处理(内部的字体处理)[Terry:原文:” oldfont is used for good house keeping.”,这个第一次没看懂啊~,现在明白了呢。就是用来保存字体的,号称为old实际上就是当时用的,因为后面的代码中直接把 font给Delete掉了阿。参见下面代码]

        oldfont = (HFONT)SelectObject(hDC, font);           // Selects The Font We Want
        wglUseFontBitmaps(hDC, 32, 96, base);                                // Builds 96 Characters Starting At Character 32
        SelectObject(hDC, oldfont);                                                        // Selects The Font We Want
        DeleteObject(font);                                                                        // Delete The Font
}

[/Terry:上面这些都是后话]


Next we define base. We do this by creating a group of 96 display lists using glGenLists(96). After the display lists are created, the variable base will hold the number of the first list.
接下来我们定义base。我们使用glGenLists(96)建立了一组有96个显示列表 (display list) 的列表组(display lists)。创建显示列表组织后,变量base将会保存第一个显示列表的数字[Terry: 编号]。

GLvoid BuildFont(GLvoid)                                                                // Build Our Bitmap Font
{
        HFONT        font;                                                                                // Windows Font ID
        HFONT        oldfont;                                                                        // Used For Good House Keeping

        base = glGenLists(96);                                                                // Storage For 96 Characters


Now for the fun stuff. We're going to create our font. We start off by specifying the size of the font. You'll notice it's a negative number. By putting a minus, we're telling windows to find us a font based on the CHARACTER height. If we use a positive number we match the font based on the CELL height.
下面的是很有趣的哦。我们将要创建我们的字体。首先,要确定字体的大小(原文:size of the font)。你会注意到那是一个负数。通过使用负号‘-’,我们告诉Windows来为我们找到一个基于字符(原文:CHARACTER)高度的字体。如果我们使用一个正数,Windows会找到一个基于CELL高度的字体。[Terry:这个CHARACTER和 这个CELL到底是什么东东,还有待我的理解。不过我尝试过修改源码的-24,换为+/- 240 觉得没什么差别。]


font = CreateFont(         -24,                                                        // Height Of Font


Then we specify the cell width. You'll notice I have it set to 0. By setting values to 0, windows will use the default value. You can play around with this value if you want. Make the font wide, etc.
然后我们确定了cell的宽度[Terry: cell不是显示的字符的笔画的宽度,而是单个字符的宽度,或者说应该是一个字符显示区域cell的宽度,这个区域有看不到的边界]。你注意到了我把它设为0了。通过把它设为0,windows将会是用默认值。如果你想要修改它的值的话,你可以试着改改看。可以把字体改宽,等等。


0,                                                                // Width Of Font


Angle of Escapement will rotate the font. Unfortunately this isn't a very useful feature. Unless your at 0, 90, 180, and 270 degrees, the font usually gets cropped to fit inside it's invisible square border. Orientation Angle quoted from MSDN help Specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device. Unfortunately I have no idea what that means
Angle of Escapement 将会旋转字体,但是这并不是非常有用的参数。除非你的角度是0°,90°,180°
和270°,通常字体为了适应它们不可见的方形边界,从而不会被正确地裁剪。引自MSDN的Orientation Angle可以帮助解释这个角度,”in tenths of degrees, between each character's base line and the x-axis of the device.”很可惜我还不理解那究竟是什么意思。[Terry: 作者也不知道那究竟是什么,崩溃~~~]

                                                0,                                                                // Angle Of Escapement
                                                0,                                                                // Orientation Angle

Font weight is a great parameter. You can put a number from 0 - 1000 or you can use one of the predefined values. FW_DONTCARE is 0, FW_NORMAL is 400, FW_BOLD is 700 and FW_BLACK is 900. There are alot more predefined values, but those 4 give some good variety. The higher the value, the thicker the font (more bold).
字体的笔画宽度(原文:Font weight)是一个很重要的参数。你可以给它一个介于0和1000之间的数,或者给它一些预定义的取值。FW_DONTCARE值为0,FW_NORMAL值为400,FW_BOLD值为700,FW_BLACK值为900。当然还有很多预定义值,这4个预定义值已经够用了(原文: but those 4 give some good variety.)。[Terry:Font weight是字体的字形笔画宽度(可以理解为笔画格式,比如 FW_BOLD粗体,FW_BLACK在VC6的WINGDI.h头文件中被定义为FW_HEAVY值为900,等等)]
取值越大,字体笔画越宽(越粗) (原文:The higher the value, the thicker the font (more bold).)。


                                                FW_BOLD,                                                // Font Weight


Italic, Underline and Strikeout can be either TRUE or FALSE. Basically if underline is TRUE, the font will be underlined. If it's FALSE it wont be. Pretty simple :)
斜体,下划线,删除线的取值可以为TRUE 或者 FALSE。基本上,如果下划线(underline)取值为TRUE,则字体将会带有下划线。如果下划线(underline)为FALSE,则字体不会带有下划线。很简单是吧:)


                                                FALSE,                                                        // Italic
                                                FALSE,                                                        // Underline
                                                FALSE,                                                        // Strikeout


Character set Identifier describes the type of Character set you wish to use. There are too many types to explain. CHINESEBIG5_CHARSET, GREEK_CHARSET, RUSSIAN_CHARSET, DEFAULT_CHARSET, etc. ANSI is the one I use, although DEFAULT would probably work just as well.
字符集描述符(原文:Character set Identifier)描述了你想要使用的字符集的类型。字符集有好多类型的。CHINESEBIG5_CHARSET, GREEK_CHARSET, RUSSIAN_CHARSET, DEFAULT_CHARSET,等等[Terry: 大家从定义的这些名字就可以看出来了吧,我就不再解释了。]。 尽管DEFAULT (默认)或许也可以正常使用,但我用的字符集是ANSI。

If you're interested in using a font such as Webdings or Wingdings, you need to use SYMBOL_CHARSET instead of ANSI_CHARSET.
如果你想使用Webdings字体 或者 Wingdings字体[Terry:是两种西文字体,看起来都是符号,恩,你可以在Word里面试试看,呵呵],你就需要使用SYMBOL_CHARSET来换掉ANSI_CHARSET。

                                                ANSI_CHARSET,                                        // Character Set Identifier

Output Precision is very important. It tells Windows what type of character set to use if there is more than one type available. OUT_TT_PRECIS tells Windows that if there is more than one type of font to choose from with the same name, select the TRUETYPE version of the font. Truetype fonts always look better, especially when you make them large. You can also use OUT_TT_ONLY_PRECIS, which ALWAYS trys to use a TRUETYPE Font.
输出精度非常的重要。如果有多于一个的字符集类型可用的情况下,它会告知Windows要使用什么类型的字符集。OUT_TT_PRECIS告知Windows,如果由同一个名字可以选择不只一个字体类型的话,则选择字体的TRUETYPE版本(原文:OUT_TT_PRECIS tells Windows that if there is more than one type of font to choose from with the same name, select the TRUETYPE version of the font.)特别是当你把文字变得很大时,Truetype字体会看起来跟好的。你还可以使用OUT_TT_ONLY_PRECIS,它总是尝试使用一个TRUETYPE字体。

                                                OUT_TT_PRECIS,                                        // Output Precision。

Clipping Precision is the type of clipping to do on the font if it goes outside the clipping region. Not much to say about this, just leave it set to default.
裁剪精度描述的是 如果字体超出了裁剪区域(原文:the clipping region)时所使用的裁剪类型[Terry: the clipping region可能就是前面说的那个cell的东东。]。我不想过多地解释它,这里把它设成默认值。

                                                CLIP_DEFAULT_PRECIS,                        // Clipping Precision

Output Quality is very important. You can have PROOF, DRAFT, NONANTIALIASED, DEFAULT or ANTIALIASED. We all know that ANTIALIASED fonts look good :) Antialiasing a font is the same effect you get when you turn on font smoothing in Windows. It makes everything look less jagged.
输出品质也非常重要。你可以使用DEFAULT 默认,DRAFT草稿,PROOF印刷,NONANTIALIASED无抗锯齿 或者 ANTIALIASED抗锯齿[Terry:这里我改变了这些值的顺序,我的顺序是参照WINGDI.h中的定义顺序由小到大的排列的。恩“ANTIALIASED抗锯齿”,也可以译作“反走样”,意思一样,但是从字面上看还是“抗锯齿”比较形象贴切,因为图形光栅化之后呢的确会呈现锯齿状的呢。]。我们都知道ANTIALIASED抗锯齿的字体看起来会很棒:) ,消除一个字体的锯齿走样同样可以在Windows中打开字体平滑时实现(原文 :Antialiasing a font is the same effect you get when you turn on font smoothing in Windows.)它会使所有字体看起来比较平滑(原文:It makes everything look less jagged. Jagged,锯齿状的)

                                                ANTIALIASED_QUALITY,                        // Output Quality

Next we have the Family and Pitch settings. For pitch you can have DEFAULT_PITCH, FIXED_PITCH and VARIABLE_PITCH, and for family you can have FF_DECORATIVE, FF_MODERN, FF_ROMAN, FF_SCRIPT, FF_SWISS, FF_DONTCARE. Play around with them to find out what they do. I just set them both to default.
下来我们来设置Family 和 Pitch[Terry:the Family and Pitch settings,我不知道Family是个什么东东,我只能查到说Pitch setting是“节距置位”根据理解应该是指“间距方式的设置”吧]。关于节距(原文:pitch)你可以取用DEFAULT_PITCH 默认节距, FIXED_PITCH 固定节距 和 VARIABLE_PITCH可变节距,而;关于family你可以用FF_DECORATIVE可装饰的, FF_MODERN现代, FF_ROMAN 罗马字,FF_SCRIPT手写,FF_SWISS瑞士字,FF_DONTCARE随便。你可以尝试在例子中改变他们取值,看看他们究竟起到什么作用。我在这里仅是把它们都设成默认值。
[Terry:我还没发现上面那些有什么用处,呵呵。这些是在 WINGDI.h中定义的 Families]
/* Font Families */
#define FF_DONTCARE         (0<<4)  /* Don't care or don't know. */
#define FF_ROMAN            (1<<4)  /* Variable stroke width, serifed. */
                                    /* Times Roman, Century Schoolbook, etc. */
#define FF_SWISS            (2<<4)  /* Variable stroke width, sans-serifed. */
                                    /* Helvetica, Swiss, etc. */
#define FF_MODERN           (3<<4)  /* Constant stroke width, serifed or sans-serifed. */
                                    /* Pica, Elite, Courier, etc. */
#define FF_SCRIPT           (4<<4)  /* Cursive, etc. */
#define FF_DECORATIVE       (5<<4)  /* Old English, etc. */
[/Terry:上面的这些仅供参考,如果想要详细了解还是去看看MSDN吧,或许那个有些帮助的。]

                                                FF_DONTCARE|DEFAULT_PITCH,                // Family And Pitch

Finally... We have the actual name of the font. Boot up Microsoft Word or some other text editor. Click on the font drop down menu, and find a font you like. To use the font, replace 'Courier New' with the name of the font you'd rather use.
最后,我们设置字体的名字。运行Microsoft Word或者其他的文本编辑器,单击字体的下拉菜单,然后找一个你喜欢的字体。要使用你想要的字体,只需要把代码中的'Courier New'用你找到的字体的名字替换掉就好了。

                                                "Courier New");                                        // Font Name

19

主题

106

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2004-10-7 01:58:00 | 显示全部楼层

Re:NeHe OpenGL Tutorial lesson 13[原创]

oldFont stores the previously used font. SelectObject will return the font (or pen, or filler, or whatever GDI objects) that was previously set when it switches to the new font. The way that GDI works is such that the use of the return value of SelectObject is not very apparent. At first glance it looks as if the code is selecting the new font and returning a pointer and storing it within oldFont.
oldfont[Terry:原文中为oldFont前面的变量是oldfont]存储着前一次使用过的字体。当GDI对象转向新字体时,SelectObject将会返回字体(或者 pen画笔,filter过滤器,或者任何GDI Obejects  GDI对象)。
而这个字体就是前一次设置的字体。GDI的工作方式是这样的----不是很明显的使用了SelectObject的返回值。初看的时候,它看起来好像是选择了一个新的字体并返回一个指针并将它存在oldfont之中。


        oldfont = (HFONT)SelectObject(hDC, font);           // Selects The Font We Want
        wglUseFontBitmaps(hDC, 32, 96, base);                                // Builds 96 Characters Starting At Character 32
        SelectObject(hDC, oldfont);                                                        // Selects The Font We Want
        DeleteObject(font);                                                                        // Delete The Font
}


The following code is pretty simple. It deletes the 96 display lists from memory starting at the first list specified by 'base'. I'm not sure if windows would do this for you, but it's better to be safe than sorry
接下来的代码很简单哈~~~,它在内存中,删除了以’base’确定的第一个显示列表的,96个显示列表(display list)组成的列表组(display lists)。我不是很确定Windows是否会替你做这件事,但是,考虑到代码安全性,我还是这么做了。

GLvoid KillFont(GLvoid)                                                                        // Delete The Font List
{
        glDeleteLists(base, 96);                                                        // Delete All 96 Characters
}

Now for my handy dandy GL text routine. You call this section of code with the command glPrint("message goes here"). The text is stored in the char string *fmt.
现在到了我那很棒的GL文本的程序段了。你可以通过是用命令glPrint("message goes here")调用这一段代码。要绘制的文本保存在*fmt所确定的字符串中。[Terry:这里的command命令,其实就是一个函数。]

GLvoid glPrint(const char *fmt, ...)                                        // Custom GL &quotrint" Routine
{

The first line below creates storage space for a 256 character string. text is the string we will end up printing to the screen. The second line below creates a pointer that points to the list of arguments we pass along with the string. If we send any variables along with the text, this will point to them.
下面的第一行创建了一个256个字符的字符串的存储空间。数组text就是我们最后要在屏幕上绘制的字符串。第二行创建了一个指向一个参数列表的指针。我们在传递字符串时一起传递了这个参数列表。如果我们传递传递文本时也传递变量的话,它(这个指针)将指向它们(传递的变量)。

        char                text[256];                                                                // Holds Our String
        va_list                ap;                                                                                // Pointer To List Of Arguments


The next two lines of code check to see if there's anything to display? If there's no text, fmt will equal nothing (NULL), and nothing will be drawn to the screen.
接着的两行代码检测是否有要显示的文本,如果没有任何文本,fmt将会等于NULL 空,而且不会再屏幕上绘制任何东西。
        if (fmt == NULL)                                                                        // If There's No Text
                return;                                                                                        // Do Nothing


The following three lines of code convert any symbols in the text to the actual numbers the symbols represent. The final text and any converted symbols are then stored in the character string called "text". I'll explain symbols in more detail down below.
接下来的3行代码将文本中任何一个符号转换成这个符号代表的真正的数字。[Terry:比如“我今年2岁了。”其中那个“2”会被转换为数字“2”而不是什么字符编码。我的理解。]最终的文本,和转换后的符号被存储在text的字符串里。我将在后面更详细地解释符号(原文: symbols)。

        va_start(ap, fmt);                                                        // Parses The String For Variables
            vsprintf(text, fmt, ap);                                        // And Converts Symbols To Actual Numbers
        va_end(ap);                                                                // Results Are Stored In Text

We then push the GL_LIST_BIT, this prevents glListBase from affecting any other display lists we may be using in our program.
我们将把GL_LIST_BIT压栈,这将防止glListBase影响到任何其他的我们程序中使用到的显示列表。

The command glListBase(base-32) is a little hard to explain. Say we draw the letter 'A', it's represented by the number 65. Without glListBase(base-32) OpenGL wouldn't know where to find this letter. It would look for it at display list 65, but if base was equal to 1000, 'A' would actually be stored at display list 1065. So by setting a base starting point, OpenGL knows where to get the proper display list from. The reason we subtract 32 is because we never made the first 32 display lists. We skipped them. So we have to let OpenGL know this by subtracting 32 from the base value. I hope that makes sense.
命令glListBase(base-32)有一点点不好解释。比如我们要绘制字母’A’,它由数字65来代表。如果没有glListBase(base - 32),OpenGL将无法知道从哪里可以找到这个字母。它将去显示列表65去找字母’A’,如果base等于1000,则’A’将会被存储在显示列表1065。所以,通过设置一个显示列表组的起始位置,OpenGL就知道了到哪里去获得恰当的显示列表。我们减去32的原因是,我们根本没用到前面32个显示列表。所以我们要跳过它们。所以,我们必须通过从基值base减去32让OpenGL知道我们跳过了它们。我希望这样说,你们就能理解了。


        glPushAttrib(GL_LIST_BIT);                                                        // Pushes The Display List Bits
        glListBase(base - 32);                                                                // Sets The Base Character to 32


Now that OpenGL knows where the Letters are located, we can tell it to write the text to the screen. glCallLists is a very interesting command. It's capable of putting more than one display list on the screen at a time.
既然OpenGL知道了那些字母存储的位置,我们就可以告诉它来在屏幕上写字了。glCallLists是个非常有趣的命令。它每次都可以将好几个显示列表一起应用于绘图(原文:It's capable of putting more than one display list on the screen at a time. )。

The line below does the following. First it tells OpenGL we're going to be displaying lists to the screen. strlen(text) finds out how many letters we're going to send to the screen. Next it needs to know what the largest list number were sending to it is going to be. We're not sending any more than 255 characters. The lists parameter is treated as an array of unsigned bytes, each in the range 0 through 255. Finally we tell it what to display by passing text (pointer to our string).
这行代码[Terry:就是这个glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);]完成了下述的工作。首先,它告诉了OpenGL我们将要在屏幕上显示那些列表。strlen(text)得到我们将要绘制的字母的个数。(原文:strlen(text) finds out how many letters we're going to send to the screen.)接着,OpenGL还需要知道传送的列表的最大数字将是多少[Terry:(原文:Next it needs to know what the largest list number were sending to it is going to be.)初看这句话,可能会看得有点混乱阿~~,呵呵现在基本上明白了]。我们传送不多于255个字符。列表参数被看作是一组unsigned bytes字节型的无符号数,每个都介于0 ~ 255之间。最后,通过传递text(我们的字符串的指针),我们告诉OpenGL要显示的文字。

In case you're wondering why the letters don't pile on top of eachother. Each display list for each character knows where the right side of the letter is. After the letter is drawn, OpenGL translates to the right side of the drawn letter. The next letter or object drawn will be drawn starting at the last location GL translated to, which is to the right of the last letter.
如果你想知道为什么这些字母不会相互重叠地堆积在一起,答案是这样的:每个字符的显示列表都知道这个字符的右边的位置(下一个),当符绘制完一个字母(或者字符),OpenGL(将坐标)转换到刚刚所绘制的字母(或者字符)的右边的位置,后面的字母(或者字符)或对象将会在上一个GL转换到的位置开始被绘制。这个转到的位置就在上一个字母的右边。
Finally we pop the GL_LIST_BIT setting GL back to how it was before we set our base setting using glListBase(base-32).
最后我们将GL_LIST_BIT出栈来设定GL回到先前的那个状态,即我们使用glListBase(base-32)来设置我们的base的那个状态。


glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);        // Draws The Display List Text
        glPopAttrib();                                                                                // Pops The Display List Bits
}

The only thing different in the Init code is the line BuildFont(). This jumps to the code above that builds the font so OpenGL can use it later on.
在Iint部分(int InitGL(GLvoid))中和以前的代码唯一的不同就是BuildFont()。这行代码仅仅只是调用前面的代码来建立后来OpenGL可以使用的字体。
int InitGL(GLvoid)                                                                // All Setup For OpenGL Goes Here
{
        glShadeModel(GL_SMOOTH);                                        // Enable Smooth Shading
        glClearColor(0.0f, 0.0f, 0.0f, 0.5f);                                // Black Background
        glClearDepth(1.0f);                                                        // Depth Buffer Setup
        glEnable(GL_DEPTH_TEST);                                        // Enables Depth Testing
        glDepthFunc(GL_LEQUAL);                                        // The Type Of Depth Testing To Do
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  //Really Nice Perspective Calculations

        BuildFont();                                                                                // Build The Font

        return TRUE;                                                                                // Initialization Went OK
}

Now for the drawing code. We start off by clearing the screen and the depth buffer. We call glLoadIdentity() to reset everything. Then we translate one unit into the screen. If we don't translate, the text wont show up. Bitmap fonts work better when you use an ortho projection rather than a perspective projection, but ortho looks bad, so to make it work in projection, translate.
现在开始我们的绘制代码。首先清除屏幕并清除深度缓存。调用glLoadIdentity()来复位场景。然后我们向屏幕里面移动一个单位[Terry:使用glTranslatef(0.0f,0.0f,-1.0f); ]。如果我们不移动的话,这些文字将不会显示出来。当你使用ortho projection正投影 而不是 perspective projection透视投影时,位图字体Bitmap fonts会运行得更好,但是正投影看起来不好,所以我们还得使用透视,所以需要移动。

You'll notice that if you translate even deeper into the screen the size of the font does not shrink like you'd expect it to. What actually happens when you translate deeper is that you have more control over where the text is on the screen. If you translate 1 unit into the screen, you can place the text anywhere from -0.5 to +0.5 on the X axis. If you translate 10 units into the screen, you place the text from -5 to +5. It just gives you more control instead of using decimal places to position the text at exact locations. Nothing will change the size of the text. Not even glScalef(x,y,z). If you want the font bigger or smaller, make it bigger or smaller when you create it!
你会注意到如果你已经移动得尽可能的深入屏幕,但是字体的尺寸却没有缩小到你期望的那样。当你移动的越深入时,你会获得对于屏幕上文字位置更多的控制。如果你向屏幕里移动一个单位,你就可以把文字放在X轴的-0.5 ~ +0.5的区间里。如果你向屏幕里移动了10个单位,你就可以把文字放在-5 ~ +5之间。
这种方式给你更多的控制,而不用再使用小数来去定文字的位置。没有任何东西可以改变你的字体的大小。
glScalef(x,y,z)也无法实现。如果你想要使字体更大些或者更小些的话,你应该在建立字体的时候把它设置的更大或者更小。
int DrawGLScene(GLvoid)                                                                        // Here's Where We Do All The


Drawing
{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer
        glLoadIdentity();                                                                        // Reset The Current Modelview Matrix
        glTranslatef(0.0f,0.0f,-1.0f);                                                // Move One Unit Into The Screen


Now we use some fancy math to make the colors pulse. Don't worry if you don't understand what I'm doing. I like to take advantage of as many variables and stupid tricks as I can to achieve results :)
现在呢,我们使用一些神奇的数学来生成颜色的变化[Terry:Now we use some fancy math to make the colors pulse.]。如果你不理解我所写的,也没有关系的。我喜欢利用多变得和愚蠢得技巧来实现结果 :)

In this case I'm using the two counters we made to move the text around the screen to change the red, green and blue colors. Red will go from -1.0 to 1.0 using COS and counter 1. Green will also go from -1.0 to 1.0 using SIN and counter 2. Blue will go from 0.5 to 1.5 using COS and counter 1 and 2. That way blue will never be 0, and the text should never completely fade out. Stupid, but it works :)
在这里,我们使用我们设置的两个计数器来再屏幕上移动文字,还用来改变红色,绿色和蓝色。使用COS和计数器1使红色取值从-1.0变化到1.0。使用SIN和计数器2使绿色取值从-1.0 变化到 1.0。使用COS和计数器1,2使蓝色取值从0.5变化到1.5。这样蓝色永远不会取到0值,而且文字将永远不会完全消失掉。很蠢,是么,呵呵,但是有效 :)


        // Pulsing Colors Based On Text Position
        glColor3f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)));


Now for a new command. glRasterPos2f(x,y) will position the Bitmapped Font on the screen. The center of the screen is still 0,0. Notice there's no Z position. Bitmap Fonts only use the X axis (left/right) and Y axis (up/down). Because we translate one unit into the screen, the far left is -0.5, and the far right is +0.5. You'll notice that I move 0.45 pixels to the left on the X axis. This moves the text into the center of the screen. Otherwise it would be more to the right of the screen because it would be drawn from the center to the right.
现在来介绍一条新的命令。glRasterPos2f(x,y)将把位图字体(原文Bitmap Fonts)定位在屏幕上。屏幕的中心依然是0,0,这里是没有Z坐标的。位图字体(原文Bitmap Fonts)仅使用X轴(左/右)和Y轴(上/下)。因为我们向屏幕里移进了一个单位,左边的边界是-0.5,右边的边界时+0.5。你将会注意到我沿X轴向左移动了0.45个像素,这样就将文字移到了屏幕的中间。否则的话,由于字体是从中心向右的方式来绘制的,从而使文字会比较靠近屏幕的右边。

The fancy(?) math does pretty much the same thing as the color setting math does. It moves the text on the x axis from -0.50 to -0.40 (remember, we subtract 0.45 right off the start). This keeps the text on the screen at all times. It swings left and right using COS and counter 1. It moves from -0.35 to +0.35 on the Y axis using SIN and counter 2.
这fancy math完成了和color setting math[Terry:color setting math我还没想好译作什么,恩,先叫做“颜色设置计算”]同样的工作。它可将文字沿X轴从-0.50移到-0.40(还记得么,我们从开始处减去了0.45)[Terry:应该就前面说的向左移动了0.45。]。这将使得文字可以在一直在屏幕中显示。使用COS和计数器1令它左右摆动。使用SIN和计数器2令它会沿Y轴从-0.35到+0.35上下移动。[Terry:color setting math就是前面的代码glColor3f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2))); 中的参数部分了。]


        // Position The Text On The Screen
        glRasterPos2f(-0.45f+0.05f*float(cos(cnt1)), 0.32f*float(sin(cnt2)));


Now for my favorite part... Writing the actual text to the screen. I tried to make it super easy, and very user friendly. You'll notice it looks alot like an OpenGL call, combined with the good old fashioned Print statement :) All you do to write the text to the screen is glPrint("{any text you want}"). It's that easy. The text will be drawn onto the screen at the exact spot you positioned it.
现在是我最喜欢的部分了…来向写屏幕写真正的文字呢。我尽力使得它非常简单,尽力使它方便好用。你将注意到它比较像是一个OpenGL调用(原文:You'll notice it looks alot like an OpenGL call),一个结合老式的Print风格的OpenGL调用 :) 你要在屏幕上写字时所要做的仅仅只是添加glPrint("{any text you want}")这样的代码。这是多么的好用阿。文字将被绘制在屏幕上那你所指定的位置上。

Shawn T. sent me modified code that allows glPrint to pass variables to the screen. This means that you can increase a counter and display the results on the screen! It works like this... In the line below you see our normal text. Then there's a space, a dash, a space, then a "symbol" (%7.2f). Now you may look at %7.2f and say what the heck does that mean. It's very simple. % is like a marker saying don't print 7.2f to the screen, because it represents a variable. The 7 means a maximum of 7 digits will be displayed to the left of the decimal place. Then the decimal place, and right after the decimal place is a 2. The 2 means that only two digits will be displayed to the right of the decimal place. Finally, the f. The f means that the number we want to display is a floating point number. We want to display the value of cnt1 on the screen. As an example, if cnt1 was equal to 300.12345f the number we would end up seeing on the screen would be 300.12. The 3, 4, and 5 after the decimal place would be cut off because we only want 2 digits to appear after the decimal place.
Shawn T.发给我他修改过的代码。他的代码允许glPrint向屏幕传递变量。这意味着你可以递加一个计数器并在屏幕上显示它的结果!它是这样工作的…下面这行你将看到我们一般的文本。然后有一个空格符,一个破折号,一个空格符,然后是一个“格式”(%7.2f)。现在你或许盯着%7.2f并会问那个鬼玩意到底是什么意思阿(原文:what the heck does that mean.)。它其实很简单。%就像一个标记,告知程序不要在屏幕上绘制7.2f,因为它代表一个变量。7表示整数部分最大将显示7位数字。然后是小数部分,(格式定义中小数部分)剩下的是2,这表示小数部分最大将显示2位数字。最后,那个f,表示我们要显示的数字是一个浮点数。我们将以在屏幕上显示cnt(计数器1)的值为例。如果cnt1等于300.12345f,我们最终将在屏幕上看到的是300.12。由于我们只要小数点后显示2位数字,所以那小数点后的3,4和5都将被舍掉。[Terry:C中有这样的输出格式的,呵呵,原文中提到的"symbol"可以译为“格式”]

I know if you're an experienced C programmer, this is absolute basic stuff, but there may be people out there that have never used printf. If you're interested in learning more about symbols, buy a book, or read through the MSDN.
我知道,如果你是一个经验丰富的C程序员,这对你来水绝对是小儿科。但是,这里还有些人们从来没有使用过printf。如果你有兴趣更多地了解“格式”,去买本书吧,或者查查MSDN,我向会有帮助的。

        glPrint("Active OpenGL Text With NeHe - %7.2f", cnt1);        // Print GL Text To The Screen


The last thing to do is increase both the counters by different amounts so the colors pulse and the text moves
下来我们要给两个计数器以不同的增量,这样文字的颜色就会变化,文字也会移动。

        cnt1+=0.051f;                                                                                // Increase The First Counter
        cnt2+=0.005f;                                                                                // Increase The First Counter
        return TRUE;                                                                                // Everything Went OK
}


The last thing to do is add KillFont() to the end of KillGLWindow() just like I'm showing below. It's important to add this line. It cleans things up before we exit our program.
最后,我们要做的就是像下面演示的那样,在KillGLWindow()的尾部添加KillFont()。添加这行代码是很重要的呢,在他完成清理工作之后我们将退出的程序。


        if (!UnregisterClass("OpenGL",hInstance))                        // Are We Able To Unregister Class
        {
                MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
                hInstance=NULL;                                                                        // Set hInstance To NULL
        }

        KillFont();
}


That's it... Everything you need to know in order to use Bitmap Fonts in your own OpenGL projects. I've searched the net looking for a tutorial similar to this one, and have found nothing. Perhaps my site is the first to cover this topic in easy to understand C code? Anyways. Enjoy the tutorial, and happy coding!
这些就在你的OpenGL工程中建立一个位图字体所需要了解的内容了。我已经搜在网上搜过了,没有发现任何与本课相似的教程。或许我的站是第一个涉及这个题目(使用易懂的C代码创建位图字体)的站呢。
恩,去享受这教程吧,祝你写代码时有个好心情。

Jeff Molofee (NeHe)


[Terry: 我也花了大约2天多的时间才完成这一课的翻译工作的。为了方便对照起见,我保留了原文;我基本上是按照原文逐段翻译的,嗯,我觉得我基本上领会了作者的意图,但是可能在表达上还存在着一些疏漏,还望各位同人斧正(请发mail给我,或者,在blog上面发表评论) ;呵呵,再者,小弟我毕竟才疏学浅,没什么实际的经验,所以以后还想想各位前辈请教。 话不多说,万望各位遵守,free的网络精神,切勿,将本文用于任何形式的商业用途,或者,以营利为目的的任何行为。由各位读者的行为所引起的一切后果,译者将不负任何责任。]
最后重申-----------------
我想我需要说明的就是,这个lesson13的译版也算是我这些天来的成果,希望各位尊重原作者和译者,转载时请全文转载,注明出处和作者还有译者,小弟我会倍感欣慰。小弟初次为文难免会有不少疏漏之处还望各位斧正。
希望各位可以从中获益,大家共同努力共同进步,我们的网络精神就是free,呵呵。
祝大家安好。
                                                           戴瑞DaiRui(Terry)






我的译版还有待改进。
欢迎各位给我来mail,呵呵,我会尽力回复的。恩,呵呵今天我已经收到了Aman JIANG (江超宇)
的回信了呢,呵呵。恩由于我忙于备考,回复可能不会很及时的,恩,还有我的那个Blog也可能停止更新了。不过呢,我会尽力的,以后还有很多时间的呢 :)


Terry留于返校前的凌晨~~~~~~~~
[/Terry:本文完成于2004年10月7日1时22分,假期结束了,我明天将返校。]


139

主题

2005

帖子

2057

积分

金牌会员

Rank: 6Rank: 6

积分
2057
QQ
发表于 2004-10-7 13:36:00 | 显示全部楼层

Re:NeHe OpenGL Tutorial lesson 13[原创]

支持一下~

1万

主题

1万

帖子

2万

积分

管理员

中级会员

Rank: 9Rank: 9Rank: 9

积分
20686
发表于 2004-10-7 14:10:00 | 显示全部楼层

Re:NeHe OpenGL Tutorial lesson 13[原创]

好东西!支持!:)

3

主题

23

帖子

29

积分

注册会员

Rank: 2

积分
29
发表于 2004-10-8 10:05:00 | 显示全部楼层

Re:NeHe OpenGL Tutorial lesson 13[原创]

喜欢这种自言自语的方式,翻译。
因为能够知道翻译者的理解过程!!
可惜自己不怎么用OPENGL,以后用到了这些都是好资料呀!

19

主题

106

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2004-10-11 15:42:00 | 显示全部楼层

Re:NeHe OpenGL Tutorial lesson 13[原创]

感谢各位的支持,过些时间,会再出个修订版本,呵呵~~~~

希望大家多提意见~~~~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-22 17:36

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表