Lesson 1
Graphic Font:
In this lesson, we will teach you how to draw 3D graphic fonts that can be transformed like normal 3D models.
This lesson continues with the content of the previous lesson. In Lesson 13th, we learned how to use bitmap fonts. In this lesson, we will learn how to use contour fonts.
Creating a contour font is similar to creating a bitmap font in Lesson 13th. However, the outline font looks cool 100 times! You can specify the font size of the contour. The contour font can be moved in 3D mode on the screen, and the contour font can have a certain thickness! Instead of 2D characters in the plane. With the contour font, you can convert any font in your computer to a 3D font in OpenGL, and add a proper normal. When there is light, the characters will be well illuminated.
A small comment. This code is specially written for windows. It uses the WGL function of windows to create fonts. Obviously, the Apple system has AGL, the X system has Glx to support the same operation. Unfortunately, I cannot guarantee that the Code is also easy to use. If any code that can display text on the screen and is independent from the platform, please let me know, I will rewrite a tutorial on font.
We started from the typical code of Lesson 1 and added the stdio. h header file for standard input/output operations. In addition, the stdarg. h header file is used to parse text and convert variables into text. Add the math. h header file so that we can use the sin and cos functions to move text on the screen.
In addition, we need to add two variables. Base will save the number of the first display list we created. Each character must have its own display list. For example, the character 'a' is 65 in the display list, 'B' is 66, and 'C' is 67. Therefore, the character 'a' should be saved to the base + 65 position in the display list.
Let's add another variable called rot. Use the sin and cos functions to rotate text on the screen. We also use it to change the color of the text.
Gluint base; // the starting position of the display list for the font.
Glfloat rot; // rotation font
Glyphmetricsfloat GMF [256] is used to save information about the position and direction of each list corresponding to the 256 profile fonts displayed in the list. We use GMF [num] to select letters. Num is the number of the display list we want to know. In the code later, I will explain how to check the width of each character so that the text is automatically located in the center of the screen. Remember, the width of each character can be different. Glyphmetrics greatly simplifies our work.
Glyphmetricsfloat GMF [256]; // records information of 256 characters
The following code is similar to creating a bitmap font. Like Lesson 13, we only use the wglusefontoutlines function to replace the wglusefontbitmaps function.
Base = glgenlists (256); // create 256 display lists
Wglusefontoutlines (HDC, // set the handle of the device description table in the current window
0, // create the ASCII value of the first character in the font of the display list
255, // number of characters
Base, // name of the first display list
That's not all however. we then set the deviation level. the closer to 0.0f, the smooth the font will look. after we set the deviation, we get to set the font thickness. this describes how thick the font is on the Z axis. 0.0f will produce a flat 2D looking font and 1.0f will produce a font with some depth.
The parameter wgl_font_polygons tells OpenGL to create a solid font using polygons. if we use wgl_font_lines instead, the font will be wireframe (made of lines ). it's also important to note that if you use gl_font_lines, normals will not be generated so lighting will not work properly.
The last parameter GMF points to the address buffer for the display list data.
0.0f, // the smoothness of the font. The smaller the font size, the smoother the font size. the smoother the font size, the smoother the font size.
0.2f, // The distance highlighted in the z direction
Wgl_font_polygons, // use polygon to generate characters. Each vertex has an independent normal.
GMF); // the address of an array that receives the glyph metric data. Each array element is filled with the data of its corresponding display list characters.
}
The following code is pretty simple. it deletes the 256 display lists from memory starting at the first list specified by base. i'm not sure if windows wocould do this for you, but it's better to be safe than sorry :)
Glvoid killfont (glvoid) // Delete the display list
{
Gldeletelists (base, 256); // Delete 256 display lists
}
Below is my excellent GL text program. You can call this code by calling glprint ("the text to be written. The text is stored in the string text.
Glvoid glprint (const char * FMT,...) // customize the GL output font Function
{
The first line below defines a variable called length. We use this variable to query the length of a string. The second line creates an array of 256 characters, which stores the desired text string. The third row creates a pointer to a variable list. We pass this variable list while passing the string. If we also pass variables when passing text, this Pointer Points to them.
Float length = 0; // query the length of a string
Char text [256]; // Save the string we want
Va_list AP; // pointer to a variable list
The following two lines of code check whether there is any content to be displayed. If there is nothing, there will be nothing on the screen.
If (FMt = NULL) // if there is no input, return
Return;
The next three lines of code convert all characters in the text into their character numbers. Finally, the text and conversion symbols are stored in a string called "text. I will explain more details about the characters in the future.
Va_start (AP, FMT); // analyze variable parameters
Vsprintf (text, FMT, AP); // write the parameter value to the string
Va_end (AP); // end analysis
Thanks to Jim Williams for his suggestions on the following code. In the past, I used to place text in the center by hand, but his approach was much better.
Starting from a loop, we will check characters in the text one by one. We can use strlen (text) to get the length of the text. After the loop is set, we will increase the length value by adding the length of each character. After the loop ends, the value saved in length is the length of the entire string. Therefore, if we want to write "hello", assuming that the length of each character is 10 units, we add the length of the first letter to the value of length 10. Then, we check the length of the second letter. The length is also 10, so the length is changed to 10 + 10 (20 ). After checking all five letters, the length value is 50 (5*10 ).
The code that gives the length of each character Is GMF [Text [loop]. gmfcellincx. Remember, GMF stores information about each of our display lists. If the loop is equal to 0, text [loop] is the first character in our string. If the loop is equal to 1, text [loop] is the second character in our string. Gmfcellincx tells us the length of the selected character. Gmfcellincx indicates the real distance from the last character drawn to the right, so that the characters do not overlap. At the same time, this distance is the width of the characters we want. You can also use the gmfcelllncy command to get the character height. This is convenient if you draw text in the vertical direction rather than in the horizontal direction.
For (unsigned int loop = 0; loop <(strlen (text); loop ++) // find the length of the entire string
{
Length + = GMF [Text [loop]. gmfcellincx;
}
Finally, we get the calculated length and convert it to a negative number (because we need to move the text left from the center of the screen to place the entire text in the middle of the screen ). Then we divide the length by 2. We don't want to move the length of the entire text. We only need half of it!
Gltranslatef (-length/2, 0.0f, 0.0f); // place the string to the leftmost
Then we press gl_list_bit into the attribute stack, which will prevent gllistbase from affecting other display lists in our program.
Glpushattrib (gl_list_bit); // press the display list attribute into the attribute stack.
Gllistbase (base); // set the basic value of the displayed list to 0.
Now that OpenGL knows where the character is stored, We can display the text on the screen. Glcalllists calls multiple display lists to display the entire text on the screen at the same time.
The following code is used for subsequent work. First, it tells OpenGL that we will display the content in the display list on the screen. The strlen (text) function is used to calculate the length of the text we want to display on the screen. Then OpenGL needs to know the maximum value of the list that we can send to it. We still cannot send strings with a length greater than 255. So we use unsigned_byte. (0-255 is used to represent the characters we need ). Finally, we pass the string text to tell OpenGL what to display.
Maybe you want to know why the characters do not overlap with each other. At that time, because the display list of each character knows that the right side of the character is there, after writing a character, OpenGL automatically moves to the right of the character you just wrote, when you write a word or draw an object, it starts from the last position of GL to the right of the last character.
Finally, we will bring up the gl_list_bit attribute stack to restore GL to the state before we set the base using gllistbase (base.
Glcalllists (strlen (text), gl_unsigned_byte, text); // call the display list to draw a string
Glpopattrib (); // The property stack is displayed.
}
The following is the drawing code. We start by clearing the screen and deep cache. We call glloadidentity () to reset everything. Then we move the coordinate system to ten units on the screen. The outline font performs very well in perspective mode. The deeper you move the text into the screen, the smaller the text will open. The closer the text is to you, the bigger it looks.
You can also use the glscalef (x, y, z) command to operate the contour font. If you want to double the font size, you can use glscalef (1.0f, 2.0f, 1.0f). 2.0f to apply it to the Y axis, which tells OpenGL to plot the height of the displayed list to twice the original height. If 2.0f is applied to the X axis, the text width will be twice the original width.
Int drawglscene (glvoid) // This process includes all the drawing code
{
Glclear (gl_color_buffer_bit | gl_depth_buffer_bit); // clear the screen and depth Cache
Glloadidentity (); // reset the current model observation matrix
Gltranslatef (0.0f, 0.0f,-10.0f); // move to a unit on the screen
After moving to the screen, we want the text to be rotated. The following three lines of code are used to rotate the screen on three axes. I multiply the rot by different numbers so that the rotation speed varies in each direction.
Glrotatef (rot, 1.0f, 0.0f, 0.0f); // rotate along the X axis
Glrotatef (rot * 1.5f, 0.0f, 1.0f, 0.0f); // rotate along the Y axis
Glrotatef (rot * 1.4f, 0.0f, 0.0f, 1.0f); // rotate along the Z axis
The following is an exciting color loop. As usual, we use the unique incremental variable (ROT ). Color changes cyclically by using COs and sin. I divide the rot by different numbers so that each color increases at a different speed. The final result is very good.
// Set the color based on the font position
Glcolor3f (1.0f * float (COS (ROT/20366f), 1.0f * float (sin (ROT/25366f )), 1.0f-0.5f * float (COS (ROT/172.16f )));
Write text to the screen in my favorite part. I use the same function to write bitmap fonts to the screen. Write the text on the screen. All you need to do is glprint ("the text you want to write "). Very simple.
In the following code, we want to write nehe, space, break number, space, and then the result of dividing the rot value by 50 (to slow down the counter ). If the number is greater than 999.99, the fourth number on the left will be removed (only three digits on the left of the decimal point must be displayed ). Only two digits to the right of the decimal point are displayed.
Glprint ("nehe-% 3.2f", rot/50); // output text to the screen
Then increase the rotation variable to change the color and rotate the text.
Rot + = 0.5f; // Add a rotation variable
Return true; // success
}
At the end of this lesson, you should have learned to use contour fonts in your OpenGL program. Just like lesson 13th, I used to search for a similar tutorial on the Internet, but I still couldn't find it. Maybe my website is the first website that involves this topic and explains it easily and easily. Enjoy this tutorial, happy coding!