By using the move-draw style subroutines, it is possible to draw any of the primitive geometric figures in GL (except curves and surfaces). However, because these primitives are drawn so often, GL provides subroutines to draw them. The following sections explain GL high-level drawing:
Most of the high-level subroutine names follow a pattern. If the geometric figures they draw are filled, the original subroutine name has a lowercase f appended to it. For example, the rect subroutine draws a rectangular outline, while rectf draws a filled (solid) rectangle. The parameters to the subroutines can be short integers (16 bits), long integers (32 bits), or floating-point numbers (32 bits). Floating point is the default, but if the parameter type is a short integer, there is a lowercase s suffix. If the parameter type is a long integer, the subroutine name takes a lowercase i suffix. As with the v subroutine, only the least significant 24 bits of the long integer are considered .
arc | |
Draws a circular arc. | |
arcf | |
Draws a pie-shaped filled circular arc. | |
circ | |
Draws a circle. | |
circf | |
Draws a filled circle. | |
polf | |
Draws a filled polygon. | |
poly | |
Draws a polygon. | |
polygonlist | |
Draws multiple, disjointed polygons. | |
polylinelist | |
Draws multiple, disjointed polylines. | |
rect | |
Draws a rectangle. | |
rectf | |
Draws a filled rectangle. | |
sbox | |
Draws a screen-aligned rectangle. | |
sboxf | |
Draws a filled screen-aligned rectangle. | |
splf | |
Draws a shaded filled polygon. |
GL provides two types of rectangle subroutines: filled and unfilled. Filled rectangles are just rectangular polygons, and unfilled rectangles are rectangular outlines. In both types of subroutines, only the x and y coordinates of the corners of the rectangle are given, and the z coordinate is assumed to be zero. The rectangle is assumed to be aligned with the x and y axes.
The following table lists the six different forms of the rectangle subroutine.
Forms of the Rectangle Subroutine | ||
Parameter type | Filled | Unfilled |
short integer | rectfs | rects |
long integer | rectfi | recti |
floating point | rectf | rect |
The parameters to all six versions of the rect rectangle subroutines are the same: rect(x1, y1, x2, y2). The point defined by the x1, y1 parameters is one corner of the rectangle and that defined by the x2, y2 parameters is the opposite corner. Because the rectangle is assumed to be aligned with the axes, the coordinates of the other corners are defined by the x1, y2 and y1, x2 parameters, respectively. The syntax is as follows:
void rect(Coord x1, Coord y1, Coord x2, Coord y2)
Rectangles can undergo three-dimensional geometric transformations, and the resulting figure need not appear to be a rectangle. (For example, imagine rotating the rectangle about the x axis so that one end is farther from you and then viewing it in perspective. On the screen, the rotated rectangle appears to be a trapezoid.) Rectangles drawn with the rect subroutine (and also circles, arcs, and other 2-D figures) can be positioned anywhere in world space with the use of the routines described in "Working With Coordinate Systems".
It is important to understand that the matrix manipulation routines (for instance, translate, rotate, and scale) execute considerably slower than the drawing subroutines such as the begin-end style subroutines. Therefore, it is almost always more efficient to draw the desired rectangle in its final position with the subroutines bgnpolygon and endpolygon, rather than using the rect subroutine with translate, rotate, and scale. Performance considerations do not necessarily apply to circles and arcs, in part because these are more complex figures and are unique in the convenience they provide.
The following example program draws a chess board with black and white squares on a green background using the rect subroutine. In addition, to demonstrate the unfilled rectangle subroutines, there is a red line outlining the board.
#include <gl/gl.h>
main() { Int32 i, j;
prefposition(100, 500, 100, 500); winopen("chessboard"); color(GREEN); clear(); for (i = 0; i < 8; i = i+1) for (j = 0; j < 8; j = j+1) { if (odd(i+j)) color(WHITE); else color(BLACK); rectfi(100 + i*25, 100 + j*25, 124 + i*25, 124 + j*25); } color(RED); recti(97, 97, 302, 302); sleep(3); }
odd(n) /* returns 1 if n is odd; 0 otherwise. */ Int32 n; { return n&1; }
The sbox subroutine draws a two-dimensional, screen-aligned rectangle using the current color, writemask, linestyle, and linestyle repeat. Only these attributes, not the normal line attributes, are used. Most of the lighting/shading/viewing pipeline is bypassed.
Forms of the sbox Subroutine | ||
Parameter type | Filled | Unfilled |
short integer | sboxfs | sboxs |
long integer | sboxfi | sboxi |
floating point | sboxf | sbox |
void sbox(Coord x1, Coord y1, Coord x2, Coord y2)
The sboxf subroutine draws a filled rectangle.
When you use the sbox subroutine, you must not use lighting, backfacing, depth-cueing, z buffering, Gouraud shading, or alphablending.
Like rectangles, circles are two-dimensional figures, and lie in the x-y plane, with z coordinates equal to zero. If they are viewed at an angle, circles will be appear to be ellipses.
The parameters for the circle subroutines include the center point, defined by the x, y parameters, and the radius. Like rectangles, circles are either filled or unfilled, and the center coordinates and radius are specified in integers, short integers, or floating-point numbers.
The following table lists the six different forms of the circ subroutine. The parameters to all six subroutines are the same: circ(x, y, radius).
Forms of the Circle Subroutine | ||
Parameter type | Filled | Unfilled |
short integer | circfs | circs |
long integer | circfi | circi |
floating point | circf | circ |
Circles are drawn with 80 equally spaced points, either as a closed line (for unfilled circles), or as a polygon (for filled circles). If your application draws many tiny circles, it is a good idea to write a circle primitive that uses fewer line segments, and which can therefore be drawn much more quickly. A similar problem can arise for very large circles. If they are magnified enough, you can see the individual straight line segments. However, circles drawn with 80 segments look smooth over a wide range of sizes. The syntax is as follows:
void circ(Coord x, Coord y, Coord radius)
The following example program, bullseye, draws an archery target using filled circles:
#include <gl/gl.h>
main() {
prefposition(100, 500, 100, 500); winopen("bullseye"); ortho2(-1.0, 1.0, -1.0, 1.0); color(BLACK); clear(); color(GREEN); circf(0.0, 0.0, 0.9); color(YELLOW); circf(0.0, 0.0, 0.7); color(BLUE); circf(0.0, 0.0, 0.5); color(CYAN); circf(0.0, 0.0, 0.3); color(RED); circf(0.0, 0.0, 0.1); sleep(3); }
Arcs are also two-dimensional figures, and like circles and rectangles, GL assumes they lie in the plane z = 0. When viewed at an angle, arcs appear to be segments of ellipses. Arcs can be either filled or unfilled. As shown in the Unfilled Arc figure, these are simply segments of circles, whereas filled arcs, shown in the Filled Arc figure, look like sections of a pie.
Arcs are defined by a center (x, y), a radius, a starting angle, and an ending angle. The angles are measured from the positive x axis in a counterclockwise (right-hand rule) direction. Negative angles are measured clockwise. Both angles are expressed as integers in tenths of degrees, so a 90 degree angle is expressed as 900.
An arc is always drawn counterclockwise from the starting angle to the ending angle, so if startang = 0 and endang = 100, a 10-degree arc is be drawn. If the starting angle is 100 and the ending angle is 0, a 350-degree arc is drawn.
The circular portions of the arcs drawn are approximated by straight lines, and a full 360-degree arc consists of 80 segments. If your application draws many tiny arcs, it is a good idea to write an arcs primitive that uses fewer line segments and that can therefore be drawn much more quickly. A similar problem can arise for very large arcs. If they are magnified enough, you can easily see the individual straight line segments. However, arcs drawn with 80 segments look reasonably good over a wide range of sizes.
Arcs subroutines come in the same six forms as subroutines for circles and rectangles as shown in the following table:
Forms of the Arc Subroutine | ||
Parameter type | Filled | Unfilled |
short integer | arcfs | arcs |
long integer | arcfi | arci |
floating point | arcf | arc |
The parameter order for all six versions of the arc subroutine is x, y, radius, startang, endang. The syntax is as follows:
void arc(Coord x, Coord y, Coord radius, Angle startang, Angle endang)
The following example program, piechart, draws a pie chart using filled arcs:
#include <gl/gl.h>
main() {
prefposition(100, 500, 100, 500); winopen("piechart"); ortho2(-1.0, 1.0, -1.0, 1.0); color(BLACK); clear(); color(RED); arcf(0.0, 0.0, 0.9, 0, 800); color(GREEN); arcf(0.0, 0.0, 0.9, 800, 1200); color(YELLOW); arcf(0.0, 0.0, 0.9, 1200, 2200); color(MAGENTA); arcf(0.0, 0.0, 0.9, 2200, 3400); color(BLUE); arcf(0.0, 0.0, 0.9, 3400, 0); sleep(3); }
GL has two sets of subroutines that take arrays of vertex coordinates and draw filled and unfilled polygons. These subroutines draw exactly the same figures as the move-draw (or polygon move and polygon draw) subroutines, but are often more convenient to use.
Filled polygons are drawn by the polf subroutine, and polygon outlines are drawn by the poly subroutine. The following table is a complete list of the polygon and filled polygon subroutines.
Forms of the Polygon Subroutines | ||
Parameter type | 2-D | 3-D |
short integer | poly2s | polys |
long integer | poly2i | polyi |
floating point | poly2 | poly |
short integer | polf2s | polfs |
long integer | polf2i | polfi |
floating point | polf2 | polf |
Both the polf and the poly subroutines take two parameters. The first parameter, n, is the number of vertices in the polygon, and the second, parray, is a two-dimensional array containing the coordinates. The syntax for the polf and poly subroutines is as follows:
void polf(Int32 n, Coord parray[][3])
void poly(Int32 n, Coord parray[][3])
This example program draws a hexagon using the polf subroutine:
#include <gl/gl.h>
Int32 parray[6][2] = {{200,100},{100,300},{200,500}, {400,500},{500,300},{400,100}};
main() {
prefposition(100, 600, 100, 600); winopen("hexagon"); color(BLACK); clear(); color(GREEN); polf2i(6, parray); sleep(3); }