## With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

No credit card required

# Assembling Primitives from Vertices

The 3D shape of an object is known as its geometry. In OpenGL, the geometry of an object constitutes a set of primitives that are either triangles, points, or lines. These primitives are defined using an array of vertices, and the vertices are connected according to the primitive’s topology. OpenGL ES supports seven topologies, as depicted in Figure 2-2.

Recall the one line of code in HelloArrow from Chapter 1 that tells OpenGL to render the triangles to the backbuffer:

`glDrawArrays(GL_TRIANGLES, 0, vertexCount);`

The first argument to this function specifies the primitive topology: `GL_TRIANGLES` tells OpenGL to interpret the vertex buffer such that the first three vertices compose the first triangle, the second three vertices compose the second triangle, and so on.

In many situations you need to specify a sequence of adjoining triangles, in which case several vertices would be duplicated in the vertex array. That’s when `GL_TRIANGLE_STRIP` comes in. It allows a much smaller set of vertices to expand to the same number of triangles, as shown in Table 2-1. In the table, v is the number of vertices, and p is the number of primitives. For example, to draw three triangles using `GL_TRIANGLES`, you’d need nine vertices (3p). To draw them using `GL_TRIANGLE_STRIP`, you’d need only five (p + 2).

Table 2-1. Primitive counts

TopologyNumber of primitivesNumber of vertices
GL_POINTSvp
GL_LINESv / 22p
GL_LINE_LOOPvp
GL_LINE_STRIPv - 1p + 1
GL_TRIANGLESv / 33p
GL_TRIANGLE_STRIPn - 2p + 2
GL_TRIANGLE_FANn - 1p + 1

Another way of specifying triangles is `GL_TRIANGLE_FAN`, which is useful for drawing a polygon, a circle, or the top of a 3D dome. The first vertex specifies the apex while the remaining vertices form the rim. For many of these shapes, it’s possible to use `GL_TRIANGLE_STRIP`, but doing so would result in degenerate triangles (triangles with zero area).

For example, suppose you wanted to draw a square shape using two triangles, as shown in Figure 2-3. (Incidentally, full-blown OpenGL has a `GL_QUADS` primitive that would come in handy for this, but quads are not supported in OpenGL ES.) The following code snippet draws the same square three times, using a different primitive topology each time:

```const int stride = 2 * sizeof(float);

float triangles[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 1}, {1, 0}, {0, 0} };
glVertexPointer(2, GL_FLOAT, stride, triangles);
glDrawArrays(GL_TRIANGLES, 0, sizeof(triangles) / stride);

float triangleStrip[][2] = { {0, 1}, {0, 0}, {1, 1}, {1, 0} };
glVertexPointer(2, GL_FLOAT, stride, triangleStrip);
glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(triangleStrip) / stride);

float triangleFan[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 0} };
glVertexPointer(2, GL_FLOAT, stride, triangleFan);
glDrawArrays(GL_TRIANGLE_FAN, 0, sizeof(triangleFan) / stride);```

Triangles aren’t the only primitive type supported in OpenGL ES. Individual points can be rendered using `GL_POINTS`. The size of each point can be specified individually, and large points are rendered as squares. Optionally, a small bitmap can be applied to each point; these are called point sprites, and we’ll learn more about them in Chapter 7.

OpenGL supports line primitives using three different topologies: separate lines, strips, and loops. With strips and loops, the endpoint of each line serves as the starting point for the following line. With loops, the starting point of the first line also serves as the endpoint of the last line. Suppose you wanted to draw the border of the square shown in Figure 2-3; here’s how you could do so using the three different line topologies:

```const int stride = 2 * sizeof(float);

float lines[][2] = { {0, 0}, {0, 1},
{0, 1}, {1, 1},
{1, 1}, {1, 0},
{1, 0}, {0, 0} };
glVertexPointer(2, GL_FLOAT, stride, lines);
glDrawArrays(GL_LINES, 0, sizeof(lines) / stride);

float lineStrip[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0} };
glVertexPointer(2, GL_FLOAT, stride, lineStrip);
glDrawArrays(GL_LINE_STRIP, 0, sizeof(lineStrip) / stride);

float lineLoop[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 0} };
glVertexPointer(2, GL_FLOAT, stride, lineLoop);
glDrawArrays(GL_LINE_LOOP, 0, sizeof(lineLoop) / stride);
```

## With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

No credit card required