Visual C++ 2015 Files
Visual C++ 6 Files (Old)
Contents
The purpose of this interactive program is to make it easier to learn OpenGL Geometric Primitives. There are ten geometric primitives in OpenGL, from a point to a polygon, and all are represented by vertices. This program will give you the flexibility to add and remove vertices in a certain order, and shows you how the choice of the primitive determines how the vertices are to be combined. It can be used in the following ways:
- Learn OpenGL Geometric Primitives through
- Interactive Program
- Source Code
- Documentation
- Learn some OpenGL functions designed to work with geometric primitives
- Draw primitives manually and generate their corresponding OpenGL C code
For information on how to compile and run the program, check the Usage section in the GLUT Window Template article.
Primitive | Options to change the shape, color, and other properties of the geometric primitive. |
Vertex | Options to generate vertices, increase\decrease generation rate, delete vertices, show\hide vertices, show\hide vertex number, increase\decrease vertex size, and change vertex color. |
Grid | Options to show\hide grid, turn on\off the option to automatically align vertices to grid, add\remove row to grid, add\remove column to grid, increase\decrease the line width of the lines forming the grid, and change the grid color. |
Generate Code | Generate OpenGL C code from your drawing. By default, the code is generated in a file called program.c. |
Back Color | Select the background color |
Left\Right | Change geometric primitive |
Up\Down | Change Primitive Color |
a | Turn On\Off auto-plotting on grid |
C\c | Add\Remove column to Grid |
d | Delete all vertices |
g | Show\Hide Grid |
h | Display help message |
L\l | Increase\Decrease Line Width |
n | Show\Hide Numbers |
p | Show\Hide vertices |
R\r | Add\Remove Row to Grid |
S\s | Increase\Decrease point size |
T\t | Increase\Decrease Generation Rate for vertices |
v | Generate Vertices |
W\w | Increase\Decrease Grid Line Width |
X\X | Increase\Decrease Vertex size |
z | Remove the last inserted vertex |
Left Button | Add a vertex |
Middle Button | Remove a vertex |
Right Button | Show menu for more options |
All geometric primitives are described in terms of vertices, which are coordinates that define the points themselves, endpoints of line segments, or corners of polygons.
In order to draw a vertex in OpenGL, we use the OpenGL function glVertex
. This function has the following variations:
void glVertex2d( GLdouble x, GLdouble y )
void glVertex2f( GLfloat x, GLfloat y )
void glVertex2i( GLint x, GLint y )
void glVertex2s( GLshort x, GLshort y )
void glVertex3d( GLdouble x, GLdouble y, GLdouble z )
void glVertex3f( GLfloat x, GLfloat y, GLfloat z )
void glVertex3i( GLint x, GLint y, GLint z )
void glVertex3s( GLshort x, GLshort y, GLshort z )
void glVertex4d( GLdouble x, GLdouble y, GLdouble z, GLdouble w )
void glVertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
void glVertex4i( GLint x, GLint y, GLint z, GLint w )
void glVertex4s( GLshort x, GLshort y, GLshort z, GLshort w )
We will be using glVertex2f
since we are drawing vertices with floating point coordinates x
and y
in 2D space.
This interactive program supports the following operations on vertices:
- Add a vertex using the mouse left button. The vertex coordinates are calculated from our mouse coordinates.
- Remove the last vertex we added with the mouse middle button or by hitting the 'z' key on the keyboard.
- Delete all vertices we have added by hitting the 'd' key on the keyboard or selecting the 'Vertex\Delete Vertices' menu item of the right click menu.
- Generate a random number of vertices with random coordinates by hitting the 'v' key on the keyboard or selecting the 'Vertex\Generate Vertices' menu item of the right click menu.
A primitive is an interpretation of a list of vertices into a certain shape. In OpenGL, we specify the list of vertices for a certain primitive by placing them in a glBegin
()\glEnd
() block as follows:
glBegin (mode);
glVertex* (...);
.....
glVertex* (...);
glEnd ();
where mode
is a symbolic constant representing the desired primitive. The mode
can be one of ten symbolic constants: GL_POINTS
, GL_LINES
, GL_LINE_STRIP
, GL_LINE_LOOP
, GL_TRIANGLES
, GL_TRIANGLE_STRIP
, GL_TRIANGLE_FAN
, GL_QUADS
, GL_QUAD_STRIP
, and GL_POLYGON
.
This interactive program supports primitives by:
- Maintaining a list of vertices.
- Giving the user the option to select the desired geometric primitive using the 'Primitive\Type' submenu of the right click menu or by pressing the Left and Right keys.
A point in OpenGL is simply represented by a single vertex. All internal calculations are done as if vertices are three-dimensional. Vertices specified as two-dimensional are assigned a z
coordinate equal to zero.
Treats each vertex as a single point. Vertex n defines a point n. N points are drawn.
glBegin(GL_POINTS);
glVertex2f(x1, y1);
glEnd();
Note that in all the samples for the primitives, the minimum number of vertices is used to demonstrate the usage of the primitive. For example, we specify a single vertex for a point, two vertices for a line segment, 3 vertices for a line strip, 6 vertices for a quad strip, and so on...
There will be two previews for every geometric primitive.
- The first preview shows a single instance of the geometric primitive. The purpose behind this is to describe what the primitive really is.
- The second preview shows the primitive using common points across all primitives. The purpose behind this is to show how using the same points results in a different shape when a different primitive is selected.
Use this function in order to set the size of a point in pixels. For example, to set the point size to 4 pixels, do the following:
glPointSize(4.0f);
This function is used in the interactive program to allow the user to change the vertex size or the primitive point size in case the primitive is a point.
In OpenGL, a line represents a line segment rather than the mathematical concept of unlimited lines. OpenGL makes it easy to interconnect lines together through their endpoints.
Treats each pair of vertices as an independent line segment. Vertices 2n-1 and 2n define a line n. N/2 lines are drawn.
glBegin(GL_LINES);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glEnd();
Draws a connected group of line segments from the first vertex to the last. Vertices n and n+1 define line n. N-1 lines are drawn.
glBegin(GL_LINE_STRIP);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glEnd();
Draws a connected group of line segments from the first vertex to the last, then back to the first. Vertices n and n+1 define line n. The last line however, is defined by vertices N and 1. N lines are drawn.
glBegin(GL_LINE_LOOP);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glEnd();
void glLineWidth(GLfloat width)
Use this function to set the line width in pixels. For example, to set the line width to 2 pixels, do the following:
glLineWidth(2.0f);
This function is used in the program to allow the user to change the width of the lines that form the grid or the primitive line width in case the primitive is a line.
void glLineStipple(GLint factor, GLushort pattern)
Use this function to create lines with a dotted or dashed pattern, called stippling. To use line stippling, we must first enable it by calling the function below
glEnable(GL_LINE_STIPPLE);
The "pattern" is a 16-bit value that represents the pattern of the line. Each bit in the 16 bits represents 1 pixel * factor on the line. If the factor is 1, then a bit represents 1 pixel. If it is 2, then a bit represents 2 pixels... If the value of the bit is 1, then the corresponding pixel(s) are on, otherwise (bit's value is 0) they're off.
Notice that the bit pattern used for stippling is used in reverse when drawing the line for performance reasons. Here is an example:
short pattern = 0x0BAD;
int factor = 1;
glLineStipple(factor, pattern);
glBegin(GL_LINES);
...
glEnd();
Here is how this pattern affects the line: the first pixel is on, second is off, third is on, forth is on, fifth is off, and so on...
HEX | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
BINARY | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
The line stipple functionality is used to apply an alternating pattern on the grid lines, and thus display less of the grid on the window in order to draw the attention of the user more to the primitive being drawn.
With the primitives mentioned above, we can draw any shape in 3D space. However, the shape can only be drawn in wireframe form (i.e. not filled with a color). In order to draw a solid surface, we need more than points and lines; we need polygons. A polygon is a closed shape that may or may not be filled with a color.
Treats each triplet of vertices as an independent triangle. Vertices 3n-2, 3n-1, and 3n define triangle n. N/3 triangles are drawn.
The simplest polygon possible is the triangle, with only three sides.
glBegin(GL_TRIANGLES);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glEnd();
Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertices. For odd n, vertices n, n+1, and n+2 define triangle n. For even n, vertices n+1, n, and n+2 define triangle n. N-2 triangles are drawn.
The advantage behind using the triangle strip is that after specifying the first three vertices for the initial triangle, you only need to specify a single point for each additional triangle. This would save a lot of data and time when drawing too many interconnected triangles to represent a more complex structure.
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glVertex2f(x4, y4);
glEnd();
Draws a connected group of triangles that fan around a central point. One triangle is defined for each vertex presented after the first two vertices. Vertices 1, n+1, and n+2 define triangle n. N-2 triangles are drawn.
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glVertex2f(x4, y4);
glEnd();
Treats each group of four vertices as an independent quadrilateral. Vertices 4n-3, 4n-2, 4n-1, and 4n define quadrilateral n. N/4 quadrilaterals are drawn.
glBegin(GL_QUADS);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glVertex2f(x4, y4);
glEnd();
Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair of vertices presented after the first pair. Vertices 2n-1, 2n, 2n+2, and 2n+1 define quadrilateral n. N/2-1 quadrilaterals are drawn.
glBegin(GL_QUAD_STRIP);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glVertex2f(x4, y4);
glVertex2f(x5, y5);
glVertex2f(x6, y6);
glEnd();
Draws a single, convex polygon. Vertices 1 through N define this polygon. A polygon is convex if all points on the line segment between any two points in the polygon or at the boundary of the polygon lie inside the polygon.
glBegin(GL_POLYGON);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glVertex2f(x3, y3);
glVertex2f(x4, y4);
glVertex2f(x5, y5);
glEnd();
The key feature about this interactive program is that it allows us to test for certain concepts and validate that they are true. For example, let's validate that the polygon is convex.
| Shape 1 | Shape 2 | Shape 3 |
Lines | | | |
Polygon | | | |
Although shape 1 and shape 3 seem to follow the rule of convex polygons, shape 2 seems to me non-convex since I can connect points 2 and 4 into a line segment that doesn't fall in the polygon. Can we say that the OpenGL Architecture Review board where wrong about what they described in the redbook? It might be something I'm missing... Please prove me wrong!
There are many useful functions related to polygons, but to keep things simple, we are here only concerned with the glPolygonMode
function.
Use this function in order to change how the polygon will be rendered. By default, the polygon is filled with the current color. However, we can disable filling the polygon and display its outline or the vertices forming it.
Parameter | Description | Values |
face | Specifies which face of polygons is affected by the mode change. | GL_FRONT
GL_BACK GL_FRONT_AND_BACK |
mode | Specifies the new drawing mode. GL_FILL is the default, producing filled polygons. GL_LINE produces polygon outlines, and GL_POINT only plots the points of the
vertices. | GL_FILL
GL_LINE GL_POINT |
In our interactive program, we use this function to help draw our polygons and their borders. To draw the polygon, we say:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_POLYGON);
glVertex2f(x1, y1);
...
glEnd();
To draw its border, we say:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_POLYGON);
glVertex2f(x1, y1);
...
glEnd();
The program basically consists of 4 visible components: Vertices, Primitives, Grid, and Background. Here is the functionality supported by the program that allows you to manipulate the view of these components.
- Vertices
- Increase\Decrease Vertex Size. Click 'X' to increase size and 'x' to decrease size. You can also select the +\- menu items under Vertex\Vertex size.
- Change the vertex Color. You can do this by selecting the Vertex\Vertex Color menu items.
- Show\Hide the vertices. Click the 'p' key or select the Show/Hide Points menu item under the Vertex submenu.
- Show\Hide the numbers associated with vertices. click the 'n' key or select the Show/Hide Numbers menu item under the Vertex submenu.
- Primitives
- Change the primitive Color. You can do this by selecting the Primitive\Color menu items or by pressing the Up and Down keys.
- Change point size if the primitive is a point. Click 'S' to increase size and 's' to decrease size. You can also select the +\- menu items under Primitive\Point size.
- Change line width in case the primitive is a line. Click 'L' to increase width and 'l' to decrease width. You can also select the +\- menu items under Primitive\Line width.
- Show\Hide the primitive border and change the border color if the primitive is a polygon. You can change border color and show\hide border using the menu items under Primitive\Polygon.
- Grid
- Increase\Decrease Grid Line Width. Click 'W' to increase width and 'w' to decrease width. You can also select the +\- menu items under Grid\Line width.
- Change the grid lines color. You can do this by selecting the Back Color menu items.
- Show\Hide the grid. Click the 'g' key or select the Show/Hide Grid menu item under the Grid submenu.
- Background
- Change the background color. You can do this by selecting the Back Color menu items.
Check the sample demo attached with this article to see a video of how the program works.
You can generate a random number of vertices with random colors. You can do so by selecting the Vertex\Generate Vertices menu item, or by pressing the 'v' key.
The number of vertices generated is random, but it is dependent on a maximum, which is the generation rate. To increase the probability of having more vertices, you can increase the generation rate. this can be done by selecting the +\- menu items under the Vertex\Generation Rate submenu.
One interesting way of using the vertices generation functionality is to create for example all the possible lines between points on the grid. For example, I can set the current primitive to GL_LINES
and keep on pressing the 'v' key until all the lines between all points are generated.
When auto-plotting is turned off, a vertex is placed in the exact position at which the user clicks the mouse button.
Auto-plotting Turned Off
However, when auto-plotting is turned on, the vertices are automatically aligned to the grid by placing them on the nearest line interesection on the grid. The below figure shows the same vertices drawn above, but with auto-plotting enabled.
Auto-plotting Turned On
The implementation of this functionality is very simple as it only revolves around the logic of rounding a floating point value to the nearest integer. Knowing that there is no round
function in standard C, I have implemented my own as shown below.
int round(double number)
{
return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
}
Here is the code of the mouse
callback function responsible of handling mouse clicks. The x
and y
coordinates are the mouse coordinates with respect to the window, where the unit is in pixels. Since in OpenGL we draw in world coordinates rather than mouse coordinates, we should convert x
and y
window coordinates to their corresponding world coordinates pointX
and pointY
. Notice how the pointX
and pointY
coordinates are rounded when autoPlot
is true
.
void mouse(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
float pointX, pointY;
pointX = (float)x/window_width * world_width;
pointY = (float)(window_height - y)/window_height * world_height;
if (autoPlot)
{
pointX = round(pointX);
pointY = round(pointY);
}
addVertex(&head, &tail, pointX, pointY, 0.0f);
glutPostRedisplay();
}
else if(button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
{
deleteVertex(&head, &tail);
glutPostRedisplay();
}
}
Auto-plotting also applies to vertices generated randomly. So when auto-plotting is off and vertices are generated, they are placed anywhere inside the window. However, when auto-plotting is on, the points are laid out on the grid.
void generateVertices()
{
int i;
int numberOfVertices = rand() % generationRate;
for(i = 0; i < numberOfVertices; i++)
{
float x, y;
if (autoPlot)
{
x = rand() % (int)world_width;
y = rand() % (int)world_height;
}
else
{
x = rand() % window_width;
y = rand() % window_height;
x = (float)x/window_width * world_width;
y = (float)(window_height - y)/window_height * world_height;
}
addVertex( &head, &tail, x, y, 0.0f);
}
glutPostRedisplay();
}
Suppose that you were drawing up something and you got out of space. It wouldn't be cool to clear things off by hitting the 'd' key, then re-try drawing a smaller version of your content.
This interactive program gives you the capability of expanding your drawing area by adding columns and\or rows. It also gives you the option of shrinking this area by removing columns and\or rows.
Let's say I want to draw a house using GL_LINE_STRIP
primitive. I start out by drawing, but the grid can't hold my content as shown below.
I can resolve this by expanding the grid as shown below. You can add a row by hitting the 'R' key; remove a row by hitting the 'r' key; add a column by hitting the 'C' key; remove a column by hitting the 'c' key.
Notice that this functionality can also be used to zoom in and zoom out of the drawing area.
So you've decided to be ultimately geeky and wanted to draw something useful geometrically using only the GL_LINES
primitive. You are so happy about it and you want to immortalize your work. It's simple. Right click, and select the 'Generate Code' menu item. This will generate the OpenGL C code required to render the vertices and the primitive that defines the relationship between them.
The generated code will be placed in a file called program.c. The program.c file would contain the OpenGL generated code for drawing the primitive. In case an extra file named skeleton.c is supplied, the program will read its contents, replace the first HTML comment it finds with the generated C code, and then write the results to the new file program.c file. So program.c would be a replica of the skeleton.c except that it has generated C code instead of the HTML comment. I have already supplied a skeleton.c file with the executable. You can replace this with your own.
My skeleton.c file contains the code for an OpenGL application that draws its contents using the drawObject
method. Thus, it would be logical to put the HTML comment inside this method.
void drawObject ()
{
<!-- Insert Geometric Primitives here -->
}
when we generate the program.c file, it would contain the same content as skeleton.c, except that the drawObject
method would now look like this.
void drawObject ()
{
glColor3f(0.00, 0.00, 1.00);
glBegin(GL_LINES);
glVertex2f(1.26, 0.96);
glVertex2f(1.72, 1.48);
... glEnd();
}
One important thing to note is that the world coordinates of your skeleton program must match the world coordinates of the interactive program, in order for your primitive to be displayed in your program in the same exact way as in the interactive program.
This article not only explains the OpenGL geometric primitives, but also provides you with an interactive program that allows you to check the concepts learned without having to write a piece of code. It even generates the code for you in case you ever needed it.
Hopefully, it would be useful to many people interested in graphics out there and worth the time invested. Let me know what you think!
Find it!
The easter egg is disabled in the GitHub version, so you'll see more functionality if you get the code from there.
02/22/2008: