Help understanding glMultiDrawElements input datastructures

Hi

TL;DR : I hardly understand the datastructure required to invoke glMultiDrawElements, could you tell me where I am wrong?

I want to draw quads (based on GL_TRIANGLE_FAN) that share vertices between each other. I want to use glMultiDrawElements and would like to avoid repeating and ordering them them manually to fit the glMultiDrawArrays function requirements (which would also require to have points of a triangle fan contiguous).

Given the left side example, I am willing to build quads as follow

elementCount : {4, 4}
elementIndices : {{P0, P1, P2, P3}, {P3, P2, P5, P4}}

Here is how I try to do it (in Java with JOGL)

I first register vertices, normals and colors with FloatBuffers. I think I do this properly since I can use glMultiDrawArrays properly with other cases where vertices are repeated and contiguous.

Then I invoke glMultiDrawElements as follow :

glMultiDrawElements(glGeometryType, elementsCountBuffer, GL.GL_UNSIGNED_INT, elementsIndicesBuffer, elementsIndicesBuffer.capacity());

where elementsCountBuffer is filled with a 1D array as follow :

IntBuffer elementCountBuffer = Buffers.newDirectIntBuffer(elementsCount); // int[] elementsCount
elementCountBuffer.rewind();

and elementsIndicesBuffer is filled with a 2D array as follow :

PointerBuffer elementIndicesBuffer = PointerBuffer.allocateDirect(size(elementsIndices)); // int[][] elementsIndices, where size(array) returns #row x #columns

for (int i = 0; i < elementsIndices.length; i++) {
  // Each i is the ID of a GL_TRIANGLE_FAN

  for (int j = 0; j < elementsIndices[i].length; j++) {
    // Each j is the index of a vertex to use in the vertex/normal/color buffers to draw the ith triangle fan
    elementIndicesBuffer.put(elementsIndices[i][j]);
  }
}
elementIndicesBuffer.rewind();

I am almost sure I do this wrong because the man page of the function states that the last argument - drawcount - should describe the length of the two buffer, hence that they should be equals .

As the purpose of this function is to draw multiple elements based on vertices that may be shared among these elements, I wonder how elementIndicesBuffer could be anything else than a 2D array? Otherwise, if it is a 1D array, how can I register in it the list of indices for the first triangle fan, then second triangle fan, etc?

Thanks!

Now before we begin, I should say this: I don’t know Java programming. I use OpenGL through C++. So what I’m saying relative to JOGL will be based on a cursory examination of its documentation relative to what the C API for OpenGL is. So take this with a grain of salt.

In compatibility OpenGL (which you appear to be using), you can read index data from CPU storage directly. To invoke a glDrawElements call, you need to provide two things: the number of vertices to consume from the index buffer, and a pointer to the index data you’re reading. If you want to start reading indices from the middle of some block of memory, you compute the offset from the start of the memory to the first index, take the pointer to the start of memory, and apply the offset to it. That’s the pointer you would pass in.

The glMultiDrawElements function executes multiple glDrawElements calls. So you pass it an array of its parameters. It gets an array of vertex counts. And for each vertex count in that array, there must be a corresponding pointer to some memory to read the indices from.

This is represented in JOGL by PointerBuffer. PointerBuffer is an array of pointers into other Buffer types.

So you put all of your indices into a big IntBuffer array. You now need to build an array of PointerBuffers that point into that array. Specifically, each pointer needs to point to the first index you want that draw to read from.

You insert such a pointer by using the PointerBuffer.referenceBuffer function. Particularly, the buffer+offset version.

So if you have 8 indices, and you want to issue two draws, with the first draw using the first 3 indices and the next draw using the next 5 indices, you need to do ptrBuff.referenceBuffer(0, indexBuf) and ptrBuff.referenceBuffer(3, indexBuf), in that order, where indexBuf is the buffer containing your indices. For your buffer of counts, you would just insert “3” and “5”, in that order.

Note: you really should use buffer objects to render. But I have even less of an idea how to help you out with that, because that would require shoving an integer into a PointerBuffer, as well as how to turn your Java “buffers” into actual buffer objects.

Thank you so much, this was exactly the thing to do, but none of the JOGL example I had read used this referenceBuffer method.

For those willing to build their java buffer for JOGL, here is a sample code, assuming an input int[][] elementsIndice, where each line is a list of indices (with possibly different number of points among elements).

PointerBuffer elementIndicesBuffer = PointerBuffer.allocateDirect(elementsIndices.length);//size(elementsIndices));
IntBuffer elementCountBuffer = Buffers.newDirectIntBuffer(elementsCount);

for (int i = 0; i < elementsIndices.length; i++) {
  IntBuffer elementDataBufferI =  Buffers.newDirectIntBuffer(elementsIndices[i]);
  elementDataBufferI.rewind();
  
  elementIndicesBuffer.referenceBuffer(elementDataBufferI);
  elementCountBuffer.put(elementsIndices[i].length);
}

elementCountBuffer.rewind();
elementIndicesBuffer.rewind();

Surprisingly, there is no need to bind any element buffer. Vertex, color and normal buffer must be bind. Then one simply invoke

glMultiDrawElements(GL.GL_TRIANGLE_FAN, elementCountBuffer, GL.GL_UNSIGNED_INT, elementsIndicesBuffer, elementCountBuffer.capacity());

@Alfonse_Reinheart one thing that surprises me a lot is the need for an elementCount buffer. In Java, all buffers I use have a capacity() method indicating the size, which allows inferring the number of vertices for a single element. Is this the same in C/C++?

C++ container classes have size and capacity methods. C arrays aren’t values. The size of an array can be obtained at compile time with the sizeof operator, but at run time they decay to a pointer to their first element (i.e. you can’t pass arrays to functions, only pointers), and there’s no way to determine the number of elements from a pointer. C functions which deal with arrays take a pointer and a length as separate parameters.