I think GClements gave a nice explanation to ‘DrawElements’ functionality. I don’t know what version of OpenGL you’re using, but I’ll assume when you tried the code you made in your initial post, you were trying to do it in 3.3 core or above.
I’ve only been learning 3.3 core, so I’ll write about it from that perspective, maybe it’ll help. As GClements said, the last argument in glDrawElements --3.3 core-- is an offset to the first element location (the first element you want to send for drawing, I mean) referenced in the currently bound element array buffer object (the state holding the currently bound element array buffer object is maintained by VAO’s, which is why you bind a VAO before calling a drawing command like glDrawElements in your program). Here’s what it says in 2.8.3 of the 3.3 core spec (DrawElementsOneInstance is equivalent to DrawElements in the spec, it’s written as DrawElementsOneInstance for spec. writing purposes):
The command ‘void DrawElementsOneInstance( enum mode, sizei count, enum type, const void *indices )’ … constructs a sequence of geometric primitives by successively transferring the count elements whose indices are stored in the currently bound element array buffer (see section 2.9.7) at the offset defined by --indices-- to the GL.
(I added the dashes to indicate that means the “indices” arugment. Same thing in later quote I mention.)
So in 3.3 core, that last argument is like an index argument.
I’ve never tried OpenGL in specifically OpenGL 2, but I took a look at the 2.1 spec. Looks like the last argument to the DrawElements function actually wants an array of indices, unlike 3.3 core, which just wants a single index. Here’s what it says in 2.8 of the 2.1 spec:
The command ‘void DrawElements( enum mode, sizei count, enum type, void *indices );’ constructs a sequence of geometric primitives using the count elements whose indices are stored in --indices–.
Interestingly, looks like OpenGL 2 wants that argument to be an array. As GClements puts it, in this case, the function may treat that last argument as something you pass a pointer to client memory (which makes sense, given that you would pass an array you define in your program [which resides in what’s called your client], and in passing an array in C/C++ you’re technically passing a pointer to the first element of the array [C/C++ element in this sense, not OpenGL element]). I’m not really sure what GClements means about having “no buffer bound to that target”, I’ve never tried OpenGL 2. In 3.3 core, I’ve found I must bind a VAO whose state includes reference to a bound element array buffer object. But nonetheless, I can see from the spec there’s indication of passing an array in OpenGL 2.
So ya, looking form the specs, there seems to be a difference in DrawElements functionality in OpenGL 2 and OpenGL 3.3 core, but this may be because of the idea of having a core profile in OpenGL 3 (OpenGL 2 doesn’t have the notion of core or compatibility profiles). I glanced at the OpenGL 3.3 compatibility spec, looks like it mentions the “array” thing like in the GL 2 spec. I guess in general, the compatibility profile for 3.3 allows you to either pass an array or an index depending on whether a certain buffer object is bound (again, not sure what specifically, guessing in 3.3, it must involve whether a VAO is bound or not before the glDrawElements call). And the core profile, in attempting to be more modern, doesn’t allow that “array” passing stuff.
Overall, what I’m seeing from the specs, in OpenGL 2, for DrawElements, you pass an array. In 3.3 core, you must pass an index. So I can see how if you tried to pass an array like you did in 3.3 core, you wouldn’t get the same results as in OpenGL 2. In fact, since passing an array is like passing a pointer, 3.3 core would probably just be interested in the first element of the array you passed and not care about the rest of the array.
And In 3.3 compatibility, I think you’re able to do both: either pass an array or pass an index, depending on some certain conditions. Hope that helps with clarification.