Display text opengl learning

In this lesson we talk about how to display text.
OpenGL is not available for text display function, and, OpenGL did not bring their own special character. Therefore, to display text, it must rely on functions provided by the operating system.
A variety of popular graphical operating systems such as Windows and Linux, provides a number of features to enable easy in OpenGL program display text.
The most common way is, we are given a character, gives a display numbered list, and then install the operating system to the display list specified by the OpenGL commands to draw the characters. When the need to draw the characters, we only need to call this list can be displayed.
However, Windows and Linux systems, this method generates the display list is different (though similar). As I personally, only programming experience is not used Linux system on Windows systems, so this lesson we only for Windows systems.
OpenGL version "! Hello, World"
finished the lesson, my feeling is: very simple display text, display text is very complex. Seemingly simple features, but it is hidden behind the unfathomable mystery.
Oh, do not start to be frightened, let's start with "Hello, World!" To start.
As already said, to show character, you need through the operating system, the action of drawing characters attached to the display list, and then we can call the displayed list drawn characters.
If the text we want to display all ASCII characters, a total of only 0-127 of the 128 possible, so you can put all the characters are pre-installed corresponding to the display list, and then call these appear in the list when needed.
Windows system, you can use wglUseFontBitmaps function to generate the bulk of the display list of characters for display. Function has four parameters:
The first parameter is the HDC, Windows GDI learned friend should be familiar with this. If you did not learn, it does not matter, as long as the know call wglGetCurrentDC function, you can get a HDC up. Specific situation can be seen in the code below.
The second parameter indicates the character of the first to be produced, because we want to produce the display list of characters 0-127, so here fill 0.
The third parameter indicates the total number of characters to be generated, because we want to produce the display list of characters 0-127, a total of 128 characters, so here fill 128.
The fourth parameter indicates the number of the display list corresponding to the first character. Here, if filling 1000, the first character drawing command will be loaded into the display list No. 1000, the second character drawing command will be loaded into the display list No. 1001, and so on. We can first use glGenLists application displays a list of 128 consecutive number, and then displays a list of the first number fill in here.
Need some explanation, because wglUseFontBitmaps system is Windows-specific functions, so before use the header file: #include <windows.h>.
Now let's look at the specific code:
#include <windows.h>

// ASCII characters in a total of only 0-127, a total of 128 kinds of characters
#define MAX_CHAR 128

void drawString(const char* str) {
static int isFirstCall = 1;
static GLuint lists;

if( isFirstCall ) { // 如果是第一次调用,执行初始化
                     // 为每一个ASCII字符产生一个显示列表
     isFirstCall = 0;

     // 申请MAX_CHAR个连续的显示列表编号
     lists = glGenLists(MAX_CHAR);

     // 把每个字符的绘制命令都装到对应的显示列表中
     wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
 }
 // 调用每个字符对应的显示列表,绘制每个字符
for(; *str!='/0'; ++str)
     glCallList(lists + *str);

}

Once the display list has been in existence (unless you call glDeleteLists destroyed), so we only need the first call initialization, since you can easily call these display lists to draw the characters.
When drawing characters, you can first use glColor specified color, then glRasterPos specified location, and finally call the display list to draw.
the display void (void) {
the glClear (GL_COLOR_BUFFER_BIT);

 glColor3f(1.0f, 0.0f, 0.0f);
 glRasterPos2f(0.0f, 0.0f);
 drawString("Hello, World!");

 glutSwapBuffers();

}

Specify the font
before generating the display list, Windows allows you to select fonts.
I made a selectFont function to achieve it, we can look at the code.
void SelectFont (int size, int charset, const char * face) {
the HFONT hFont = CreateFontA (size, 0, 0, 0, FW_MEDIUM, 0, 0, 0,
charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face) ;
the hFONT hOldFont = (the hFONT) the SelectObject (wglGetCurrentDC (), hFont);
the DeleteObject (hOldFont);
}

void display(void) {
selectFont(48, ANSI_CHARSET, “Comic Sans MS”);

 glClear(GL_COLOR_BUFFER_BIT);

 glColor3f(1.0f, 0.0f, 0.0f);
 glRasterPos2f(0.0f, 0.0f);
 drawString("Hello, World!");

 glutSwapBuffers();

}

The most important part is that the argument over many CreateFont function, Windows GDI learned friend should not be unfamiliar. GDI not learned friends, who are interested, then you can looking through the MSDN documentation themselves. Here I am not going to speak carefully these parameters, the following content or causing :(
If you need to select the font in your own programs, then the function selectFont written down, after calling glutCreateWindow, you can use selectFont function before calling wglUseFontBitmaps specify the font. three function parameters indicate the font size, character set (English font can be used ANSI_CHARSET, Simplified Chinese fonts can be used GB2312_CHARSET, Traditional Chinese fonts can be used CHINESEBIG5_CHARSET, Chinese for Windows systems, can also be expressed directly DEFAULT_CHARSET default characters), the font name.
results shown in Figure:
http://blog.programfan.com/upfile/200805/20080505132624.gif
display Chinese
principle, display Chinese and English display no different, the same character is to be displayed to do to display the list, and then make the call.
but there is a problem, very few letters, only a few hundred at most, to create a display list for each letter, there is no problem. but the characters have much more, if each character has produced a the display list, which is not cut The occasion.
We can not establish at initialization a display list for each character, you can only create it each time you draw a character when we need to draw a character, creating a display corresponding to the list, such as the drawing is completed, then it is destroyed.
there is also often involves the issue of Chinese garbled, I do not quite understand the question, but the version circulated on the internet, using the MultiByteToWideChar this function, basically did not garbled, so I am ready to use this function :)
Usually we use strings in C language which, if mixed Chinese and English words, such as "this is Chinese characters.", The English characters only one byte, and the Chinese characters occupy two bytes. With MultiByteToWideChar function, can be transformed into all of the characters are two bytes (at the same time solve the garbage problem mentioned earlier :)).
Code is transformed as follows:
// calculating the number of characters
// if it is double-byte characters (such as Chinese characters), a two-byte character considered
// a character or a byte count
len = 0;
for ( 0 = I; STR [I] = '/ 0';! I ++)
{
IF (IsDBCSLeadByte (STR [I]))
++ I;
++ len;
}

// mixing wide character into character
wstring = (wchar_t *) the malloc ((len +. 1) * the sizeof (wchar_t));
the MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, STR, -1, wstring, len);
wstring [len] = L '/ 0';

// release memory after use to remember
free (wstring);

Plus the previously mentioned wglUseFontBitmaps function to display the Chinese characters.
drawCNString void (const char * STR) {
int len, I;
wchar_t * wstring;
the HDC wglGetCurrentDC the hDC = ();
GLuint glGenLists List = (. 1);

 // 计算字符的个数
 // 如果是双字节字符的(比如中文字符),两个字节才算一个字符
 // 否则一个字节算一个字符
 len = 0;
for(i=0; str[i]!='/0'; ++i)
 {
    if( IsDBCSLeadByte(str[i]) )
         ++i;
     ++len;
 }

 // 将混合字符转化为宽字符
wstring = (wchar_t*)malloc((len+1) * sizeof(wchar_t));
 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len);
wstring[len] = L'/0';

 // 逐个输出字符
for(i=0; i<len; ++i)
 {
     wglUseFontBitmapsW(hDC, wstring[i], 1, list);
     glCallList(list);
 }

 // 回收所有临时资源
free(wstring);
 glDeleteLists(list, 1);

}

Note that I used wglUseFontBitmapsW function instead wglUseFontBitmaps. wglUseFontBitmapsW are wide-character version wglUseFontBitmaps function, it believes characters are two bytes. As used here MultiByteToWideChar, in fact, each character is two bytes, it should wglUseFontBitmapsW.
the display void (void) {
the glClear (GL_COLOR_BUFFER_BIT);

 selectFont(48, ANSI_CHARSET, "Comic Sans MS");
 glColor3f(1.0f, 0.0f, 0.0f);
 glRasterPos2f(-0.7f, 0.4f);
 drawString("Hello, World!");

 selectFont(48, GB2312_CHARSET, "楷体_GB2312");
 glColor3f(1.0f, 1.0f, 0.0f);
 glRasterPos2f(-0.7f, -0.1f);
 drawCNString("当代的中国汉字");

 selectFont(48, DEFAULT_CHARSET, "华文仿宋");
 glColor3f(0.0f, 1.0f, 0.0f);
 glRasterPos2f(-0.7f, -0.6f);
 drawCNString("傳統的中國漢字");

 glutSwapBuffers();

}

The effect is as:
http://blog.programfan.com/upfile/200805/20080505132632.gif
texture font
Put the text into the texture has many advantages, for example, can be arbitrarily modify the size of the characters (without having to specify the font).
Texture with text on one side waving flags, the text also with the wind. This technique is often used in the "Three Kingdoms" series of games, such as Guan Yu's troops, floating on an "off" character on the banner, Zhang Fei forces, on a floating "Zhang" word, Cao Cao's camp on the banner, on floating a "Cao" word on the banner. Three people is so great, it is impossible for each surname are making a banner texture alone, if we can put the text onto the texture, you can solve this problem. (See the following examples: Draw side "Cao" Union Jack)
how to put the text into the texture of it? Natural idea is this: "If you display a list of previously used, which can be drawn directly into the texture, so much the better." However, "to draw texture" to be involved in the content of this technology can be a lot, enough for us to take a special lesson devoted to explain. Here we are not drawn directly into the texture, but with a little simple ways: first drawn characters, a pixel, then glCopyTexImage2D copy pixels texture.
glCopyTexImage2D glTexImage2D and usage is similar (see Section 11), but the former is drawn directly copied to the pixels good texture, which is transferred from memory to the texture data. To use the code as follows:
// first character drawn,
glRasterPos2f (XXX, XXX);
drawCNString ( "OFF");

// number assigned texture
glGenTextures (1, & texID);

// Specify the current texture
glBindTexture (GL_TEXTURE_2D, texID);

The pixel data as a texture //
// Copy screen rectangular area of pixels (0, 0) to (64, 64) to texture
glCopyTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 64, 64, 0);

// Set the texture parameters
glTexParameteri (GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER, GL_LINEAR);

Then, we can like a normal texture as do the. When draw various objects, to specify the appropriate texture coordinates.

There is a need to pay special attention to details. Look at the above code, specify the location of the text, written glRasterPos2f (XXX, XXX); here to say something about how to calculate the display coordinates.
Let us first talk from the calculation of the size of the text. We all know that even the same character in the same font, size may be different, especially in the English alphabet, and some fonts in uppercase letters and lowercase letters O l is the same width (such as Courier New), some fonts in capital letters O relatively wide, while the lower case letters l narrow (such as Times New Roman), usually wider than kanji letters.
In order to calculate the width of the text, Windows provides a special function GetCharABCWidths, it calculates the width of a series of consecutive characters ABC. The so-called ABC width, including the a, b, c three quantities, a denotes the width of the character to the left of the blank, b represents an actual width of the character, c denotes the width of the blank to the right of the character, the value obtained by adding the entire three character width occupied width . If you only need to obtain the total width GetCharWidth32 function may be used. If you want to support Chinese characters, you should use a wide-character version, GetCharABCWidthsW and GetCharWidth32W. Before use with MultiByteToWideChar function, the width of an ordinary character string into a string, just like the previous wglUseFontBitmapsW above.
Width resolved, we look at height. Originally, in the time specified font size is specified, then s, all characters are highly s, only different widths. However, if we use glRasterPos2i (-1, -1) beginning from the bottom left corner to display characters, in fact, can not get :( complete character. We know that at the time of writing the letters can be divided on the lower three columns, which when the draw came out only on two columns are visible, the following column is gone, the letter g is particularly evident as shown below:.
http://blog.programfan.com/upfile/200805/20080505132638.gif

Therefore, the need to draw up a position shifted a bit, specifically, a highly mobile field below. This height is the number of pixels it? This I do not know what a good way to calculate, based on my experience, moving one-eighth of the entire character height is more appropriate. Such as the character size is 24, then the mobile three pixels.
Also note, OpenGL 2.0 the previous version, usually require the textures must be a power of two, so we should set the height of the font is an integer power of 2, such as 16, 32, 64, it will be more so with Convenience.
Now let us sort out ideas. The first step is converted into the form of a string of a wide character, and to use wglUseFontBitmapsW GetCharWidth32W function. Then set the font size, font width is calculated next, calculates the actual position of the drawing. Then generates a display list, use the display list drawn character, destroy the list. The last number is assigned a texture, copy the character pixels to texture.
Oh, the content has a lot of, let's look at the code.
64 FONT_SIZE #define
#define texture_size FONT_SIZE

GLuint drawChar_To_Texture(const char* s) {
wchar_t w;
HDC hDC = wglGetCurrentDC();

 // 选择字体字号、颜色
 // 不指定字体名字,操作系统提供默认字体
 // 设置颜色为白色
 selectFont(FONT_SIZE, DEFAULT_CHARSET, "");
 glColor3f(1.0f, 1.0f, 1.0f);

 // 转化为宽字符
 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, s, 2, &w, 1);

 // 计算绘制的位置
 {
    int width, x, y;
     GetCharWidth32W(hDC, w, w, &width);     // 取得字符的宽度
     x = (TEXTURE_SIZE - width) / 2;
     y = FONT_SIZE / 8;
     glWindowPos2iARB(x, y); // 一个扩展函数
 }

 // 绘制字符
 // 绘制前应该将各种可能影响字符颜色的效果关闭
 // 以保证能够绘制出白色的字符
 {
     GLuint list = glGenLists(1);

     glDisable(GL_DEPTH_TEST);
     glDisable(GL_LIGHTING);
     glDisable(GL_FOG);
     glDisable(GL_TEXTURE_2D);

     wglUseFontBitmaps(hDC, w, 1, list);
     glCallList(list);
     glDeleteLists(list, 1);
 }

 // 复制字符像素到纹理
 // 注意纹理的格式
 // 不使用通常的GL_RGBA,而使用GL_LUMINANCE4
 // 因为字符本来只有一种颜色,使用GL_RGBA浪费了存储空间
 // GL_RGBA可能占16位或者32位,而GL_LUMINANCE4只占4位
 {
     GLuint texID;
     glGenTextures(1, &texID);
     glBindTexture(GL_TEXTURE_2D, texID);
     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE4,
         0, 0, TEXTURE_SIZE, TEXTURE_SIZE, 0);
     glTexParameteri(GL_TEXTURE_2D,
         GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D,
         GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    return texID;
 }

}
For convenience, I use a location glWindowPos2iARB this expansion function draw. If a system does not support OpenGL this extension, you need to use more code to implement similar functionality. In order to facilitate this extension call, I used GLEE. Details of the case can be seen in this tutorial Lesson 14, that last example. GL_ARB_window_pos expansion has become part of the standard OpenGL version 1.3, but almost all can now use the question cards After properly installing drivers support at least OpenGL 1.4, so do not worry does not support.
In addition, the space occupied by the problem should also be considered. Usually, we are using GL_RGBA texture format, OpenGL texture will be saved for each pixel in the red, green, blue, alpha four values, usually, a pixel will need 16 or 32 bits can be saved, that is, 2 bytes or 4 bytes to save only one pixel. Our character only "draw" and "draw" two states, so one bit is enough, in front with 16 or 32, wasting a lot of space. GL_LUMINANCE4 ease the way is to use this format, it does not save the individual red, green and blue colors, but these three colors together referred to as "brightness", save only the texture of this brightness, a pixel with only four bits stored luminance, than the original 16, 32 to save a lot. Note that this format does not save the alpha value, if the alpha value from the texture fetch, it always returns 1.0.
Examples of applications texture font: waving flag
(Hint: This section requires some mathematical knowledge)
with textures, as long as we draw a square, set the appropriate texture coordinates, you can easily display the image texture (see Lesson Eleven ), because there is actually a character texture image, so we also showed character. And, with changes in the size of the square, the size of the characters will vary.
Direct paste texture, too simple. Now we come to the point of challenge: a painting of Cao Cao army flag fluttering. The following picture, cool, right? Ha ha.
http://blog.programfan.com/upfile/200805/20080505132643.jpg

The effect is good, but it is not so easy to accomplish, then we have a little bit of explanation.

In order to accomplish the above results, we need to have the following knowledge:

  1. It is connected by a plurality of quadrangular (substantially rectangular), making the effect of fluttering
  2. Using light, calculating normal vector
  3. The texture blending into it
    because you want to use light, normal vector is indispensable. Here we get three points by the normal vector of the plane of the three points are not collinear.
    From a mathematical point of view, the principle is very simple. Three points v1, v2, v3, can be reduced v2 v1, v3 Save v1, v2 and v1 to obtain from the vector s1 and s2 from v1 to v3. Then the vector cross product for s1 and s2, s1 and s2 to obtain a plane perpendicular to the vector lies, i.e., normal vectors.
    For ease of use, the normal vectors should be scaled to unit length, this is very simple to calculate the magnitude of a vector, each component of the vector is then divided by this model can be.

#include <math.h>

// set the normal vector
// three points not on the same straight line in a plane can be determined
// to calculate the normal vector of the plane, and then assigned to the OpenGL
void setNormal (const GLfloat, V1 [. 3],
const GLfloat, V2 [. 3 ],
const GLfloat, V3 [. 3]) {
// first, according to the coordinates of three points, two vectors is calculated subtracting
const GLfloat, S1 [] = {
V2 [0] -V1 [0], V2 [. 1] -V1 [ . 1], V2 [2] -V1 [2]};
const GLfloat, S2 [] = {
V3 [0] -V1 [0], V3 [. 1] -V1 [. 1], V3 [2] -V1 [2] };

 // 两个向量叉乘得到法线向量的方向
 GLfloat n[] = {
     s1[1]*s2[2] - s1[2]*s2[1],
     s1[2]*s2[0] - s1[0]*s2[2],
     s1[0]*s2[1] - s1[1]*s2[0]
 };

 // 把法线向量缩放至单位长度
 GLfloat abs = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
 n[0] /= abs;
 n[1] /= abs;
 n[2] /= abs;

 // 指定到OpenGL
 glNormal3fv(n);

}
Good, and the waving of flags has already done, and for now the last step, the texture affixed to the banner.
Careful friends may think such a question: when clearly drawn characters used are white, into the texture is white, that "Cao" is how the word is displayed in yellow it?
This is to say that the use of texture. After we saw the eleventh class in "Getting Started texture" texture is considered inevitable by-pixel color on a picture to replace the original color. In fact, this is just the simplest kind of texture usage, it may be more complicated but there are other practical uses.
Here we must mention a function: glTexEnv *. From OpenGL 1.0 to OpenGL 1.5, OpenGL versions of each function has been modified, and now its function has become very powerful (but also very complicated, if you want to explain all, I'm afraid we have to spend a whole class of space a).
The simplest usage is:
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

It specifies the use of texture "in place", i.e. to replace the original color with the texture color.
Another use we use here:
GLfloat, Color [] = {1.0f, 1.0f, 0.0f, 1.0f};
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);

Wherein the second row use the specified texture as "hybrid", which is similar to the OpenGL mixing function, but the source and destination factor factor is fixed, it can not be specified manually. The final color is produced: * Constant Color texture color + (1.0-color texture) * original color. Constant color is specified by the third line as a yellow.
Because our texture was inside the text, only black and white colors. If the texture is black in a certain position, apply the above formula, the result is found in the original color, do not change; if the texture is white in a position, apply the above formula, found that the result is a constant color. Therefore, the color of the text decided by the constant color. We specify a constant color, it specifies the color of the text.

The main knowledge that these, in conjunction with previous lessons have said view transform (observation point set), the light (the light source, material), and animations, such as waving flags, even if finished.
Oh, the code has been relatively large, and space is limited, the full version is not made up here, but inside the annex have a source code flag.c.
Buffering mechanism
after the joy out of the finish banner, let us return to the two-dimensional character of the problem up.
As mentioned earlier because of the large number of Chinese characters, not just to each character are generated when initializing a display list. However, you have to re-generate the display list if every Chinese character display, the efficiency can not be justified. A good way is to save up and displays a list of frequently used Chinese characters, when you need to display Chinese characters, Chinese characters if the display list has been saved, you no longer need to re-generate. If there are many characters are required to produce the display list, take up too much capacity, it displays a list of recently deleted part is not used in order to free up some space to accommodate the new display list.
Operating system principles learned friend should think of it, yes, this memory-replacement algorithm is the same. But small-capacity memory speed, hard disk (virtual memory) is slow but large capacity, need to find a mechanism to achieve the highest possible performance. This is the memory replacement algorithm.
Common memory replacement algorithm there are several, here we have a simple choice. That is, randomly select a display list and delete, vacated a position to install the new display list.
Also say, as we do not directly use the display list to display Chinese characters, and use textures. Because the texture is more flexible and faster according to the list of experiments, the texture than the display. A display list can store only one character, but as long as the texture is large enough, you can save a lot of character. Suppose the height of characters is 32, the width is not more than 32, if the texture is 256 * 256, then it can save 8 rows and 8 columns, a total of 64 characters.
We do function:

  1. Initialization of buffering mechanism
  2. Buffering mechanism exit
  3. According to a text character, returns the corresponding texture coordinates. If the character is not in itself a texture, it should first character added to the texture (if the texture has not fit, you delete a), and then return to the texture coordinates.
    To improve the performance caching mechanism, you should use the more efficient replacement algorithm, but this has been far beyond the scope of the OpenGL. If you have time you can also look at what the linux source code, you should find a good replacement algorithm.
    Even if we use the most simple replacement algorithm, the complete code still has nearly 200 lines, in fact, these are the basic algorithm, with OpenGL relationship is not too large. Still due to space limitations, only given in the Annex, not posted here. File named ctbuf.h and ctbuf.c, in the use of these two files are added to the project, and call the function to ctbuf.h declared.
    Here we give only part of the code to call.
    #include "ctbuf.h"

void display(void) {
static int isFirstCall = 1;

if( isFirstCall ) {
     isFirstCall = 0;
     ctbuf_init(32, 256, "黑体");
 }

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 glEnable(GL_TEXTURE_2D);
 glPushMatrix();
 glTranslatef(-1.0f, 0.0f, 0.0f);
 ctbuf_drawString("美好明天就要到来", 0.1f, 0.15f);
 glTranslatef(0.0f, -0.15f, 0.0f);
 ctbuf_drawString("Best is yet to come", 0.1f, 0.15f);
 glPopMatrix();

 glutSwapBuffers();

}

Note that we use to achieve the texture character display, so the size of the text will change as the window size. The initial Hello, World program would not have such an effect, because it's the size of the font hard and fast rules, as the texture is more flexible.
Large section of the text display

With buffering mechanism, text display speed will be much faster than without a buffer, so that we can also consider a large segment of the display text.
Substantially, the foregoing function has ctbuf_drawString can quickly display a longer string, but it has two disadvantages.
The first drawback is that will not wrap until landscape in the end.
The second drawback is that even if the character on the screen outside, can try to find the character in the buffer, if not found, will re-create this character.

Let's take a look at the first question, a new line. The so-called wrap in fact, move the cursor to the beginning of the next line, if you know the location of the beginning of each line, then only a short code can be achieved.
However, OpenGL display text and will not be saved when the location of each beginning of the line, so that we need to do it yourself.
The second question is about performance, if the character itself is not displayed, it displays a list of produce and texture as it is a waste, if it is to accommodate the display lists or texture, but the buffer other useful characters or texture to display a list of deleted, it would be more harm than good.
So, to determine whether the character is displayed is also very important. Like our browser, if a large web page display, in fact, it is only necessary to draw the most part.
In order to solve the above two issues, we'll write a separate module. Initialization of the specified size of the display area, the number of characters per line, the number of characters per row, whether inside the module needs to wrap judgment, and the judgment of each character really needs to be displayed.

Observe can be found, the lyrics into multiple lines, only the necessary lines to appear, from start to finish will not show up.
Code mainly in C language algorithms and basic skills, with OpenGL does not matter much. Or as usual, the main code into the annex, the file name textarea.h and textarea.c, to be used with the previous ctbuf.h and ctbuf.c when used together.
Here are only a part of the code to call.

g_string = char * const
"" Metal Gear Solid "(Metal Gear Solid) the end of the song lyrics / the n-"
// lyrics lot of very long
"because ........ / the n-"
"wonderful upcoming / n";

textarea_t* p_textarea = NULL;

void display(void) {
static int isFirstCall = 1;

if( isFirstCall ) {
     isFirstCall = 0;
     ctbuf_init(24, 256, "隶书");
     p_textarea = ta_create(-0.7f, -0.5f, 0.7f, 0.5f,
         20, 10, g_string);
     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 }

 glClear(GL_COLOR_BUFFER_BIT);

 // 显示歌词文字
 glEnable(GL_TEXTURE_2D);
 ta_display(p_textarea);

 // 用半透明的效果显示一个方框
 // 这个框是实际需要显示的范围
 glEnable(GL_BLEND);
 glDisable(GL_TEXTURE_2D);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
 glRectf(-0.7f, -0.5f, 0.7f, 0.5f);
 glDisable(GL_BLEND);

 // 显示一些帮助信息
 glEnable(GL_TEXTURE_2D);
 glPushMatrix();
 glTranslatef(-1.0f, 0.9f, 0.0f);
 ctbuf_drawString("歌词显示程序", 0.1f, 0.1f);
 glTranslatef(0.0f, -0.1f, 0.0f);
 ctbuf_drawString("按W/S键实现上、下翻页", 0.1f, 0.1f);
 glTranslatef(0.0f, -0.1f, 0.0f);
 ctbuf_drawString("按ESC退出", 0.1f, 0.1f);
 glPopMatrix();

 glutSwapBuffers();

}
Outline font
fact, the above we talked about so much, they talk about a kind of font, that is, pixel font, in addition to the outline font. So, this appears to have a very long course, in fact, talk about the half of the "display text," the subject. It has estimated could not stand up, in fact I can not be written. Long ......
So, the lesson right here. Kind of anticlimactic feeling :(
Summary

This lesson can not say much. List is as follows:

  1. To Hello, World began, indicating that English characters (ASCII character) how to draw.
  2. It gives a function to set the font selectFont.
  3. We talked about how to display Chinese characters.
  4. We talked about how to save character to the texture.
  5. It gives a great example of drawing side "Cao" Union Jack. (Annex flag.c)
  6. Explained the buffering mechanism, in fact, with memory replacement algorithm principle is the same. We give a simple caching implementation, using a random replacement algorithm. (Made of modules, accessories ctbuf.h, ctbuf.c, invoked the example can be found in the body of this lesson)
  7. By buffering mechanism to achieve a large segment of the display text. The main attention is wrapping process, there is only display the necessary lines. (Made of modules, accessories textarea.h, textarea.c, invoked the example can be found in the body of this lesson)
    The last two modules although they are given in the form of attachment, but the principle I think I've made myself clear, and these content with OpenGL does not matter much, mainly related professional knowledge, or C language basic skills. The main principle is to allow everyone to find out, just annex the code as a reference.
    To talk about my feelings: very simple display text, display text is very complex. In addition to the basic display list, OpenGL texture common sense, more will be involved in all areas of mathematics, data structures and algorithms, operating systems, and so on. A large program usually have to implement some text special effects, just a few calls to display a list of course does not work, requires a lot of knowledge to support.
    A sudden increase in the threshold of this lesson, I do not know if this is still not the "Getting Started", and I hope you do not flinch Oh. I wish you all happy.
Published 46 original articles · won praise 3 · Views 1419

Guess you like

Origin blog.csdn.net/weixin_42076938/article/details/105308515