Drawing edges of triangles

I am trying to get a grip on modern OpenGL and have a question about drawing triangles with edges to show a mesh. After some initial bafflement I have determined that geometry shaders are not present. The following snippet gets what I want on the screen and uses one buffer for the element table:

glPolygonOffset(2.0f, 2.0f);
glDrawElements(GL_TRIANGLES, numelmi, GL_UNSIGNED_INT, off);

glUniform3fv(t->uni_color, 1, black);
for (i=0; i<numelmi; i+=3) {
    glDrawElements(GL_LINE_LOOP, 3, GL_UNSIGNED_INT, off);
    off += 3*sizeof(GLuint*);

but it calls glDrawElements a zillion times which doesn’t look right. Is it possible to inform OpenGL that all the LINE_LOOPs are 3 lines long before the glDrawElements?

An alternative would be to create a new element buffer for LINEs and call glDrawElements once. This adds a chunk of extra code and uses more memory on the graphics card both of which I would like to avoid. It seems to me to be a fairly common task that probably has a simple solution. Many thanks for any pointers.

You can use primitive restarting (glEnable() with GL_PRIMITIVE_RESTART (OpenGL 3.1+) or GL_PRIMITIVE_RESTART_FIXED_INDEX (OpenGL 4.3+)), which allows you to use the same element buffer for both triangles and line loops. Although there may be a performance penalty for this.

Another option would be to use the same element array for drawing a single line strip, with the alpha of every third vertex set to zero so that the invalid lines (between the last vertex of each triangle and the first vertex of the next triangle) can be discarded by using flat shading and an alpha test. You would still need an extra element buffer for the missing edges (between the last and first vertex of each triangle), but that would only need to have one third of the edges.

Or you could have a buffer containing all of the edges but rendered as a line strip rather than individual lines (again, using alpha to disable the segments between distinct triangles). That would only require four indices per triangle rather than six.

Assuming that you’re using shaders, you don’t actually need to store alpha values for the vertices, as the alpha can be calculated in the vertex shader from gl_VertexID.