Curious "void *" parameter for some GL functions

For some functions in OpenGL, you must specify the byte offset, for example, in glVertexAttribPointer() , for the step. First, I would suggest that it would be a normal numerical value, such as an integer. But after checking, I realized that it needs to be distinguished to void* (more precisely GLvoid* ). My question is: what is the intended meaning of void* and why should it be used to offset the byte?

+6
source share
3 answers

glVertexAttribPointer () is an older function from Vertex Buffer objects.

Before VBO, your vertex data will be stored in arrays on the client side, and you will need to pass a pointer to the data in OpenGL before you can draw.

When VBO appeared, they reprofiled this function, allowing the use of a pointer for an integer offset.

eg. void* offset = (void*)offsetof(vertexStructName, vertexMemberName);

+5
source

Some OpenGL functions, such as glDrawElements , accept a context-sensitive GLvoid * parameter. In older GLs, pre Vertex Buffers, the programmer passed an array of integer indices directly to glDrawElements , for example:

 const GLuint indexes[] = { ... }; glDrawElements(GL_TRIANGLES, numIndexes, GL_UNSIGNED_INT, indexes); 

This is called an immediate mode schedule.

When vertex and index buffers were introduced, the OpenGL architecture panel decided that they should reuse existing interfaces, thereby giving a new context-dependent meaning to this last pointer parameter void glDrawElements , glVertexAttribPointer and several other similar functions.

With index buffers, the rendering data is already on the GPU, so the void pointer parameter means an offset in the buffer. For example: the first index to render. Following the new use of glDrawElements :

 size_t firstIndex = ... size_t indexDataSize = sizeof(GLuint); glDrawElements(GL_TRIANGLES, numIndexes, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(firstIndex * indexDataSize)); 

This applies to all old functions that have been repurposed on modern OpenGL, for example glDrawElementsInstanced , glDrawElementsBaseVertex , glDrawRangeElements , etc.

Now in the specific case of glVertexAttribPointer :

 void glVertexAttribPointer(GLuint index​, GLint size​, GLenum type​, GLboolean normalized​, GLsizei stride​, const GLvoid * pointer​); 

The const GLvoid * pointer​ parameter represents the offset in bytes from the beginning of the vertex to this element. Again, this was saved like this because the function existed before Vertex / Index Buffers and was reassigned to work with them, whereas in the days of immediate mode you passed an array of vertices as a pointer parameter.

So, in the old days, glVertexAttribPointer will be used a little differently:

 const vec3 positions[] = { ... }; glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, positions); 

And in modern GL you should use:

 struct Vert { vec3 position; vec3 normal; }; size_t offset; offset = offsetof(Vert, position); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, reinterpret_cast<const GLvoid *>(offset)); offset = offsetof(Vert, normal); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, reinterpret_cast<const GLvoid *>(offset)); 
+3
source

It is called a void pointer, and it can point to any type, such as char *, but it is slightly different. First, you must remember that a pointer is just a number, an address to the right place, nothing more. In order to use the data indicated by the void pointer, you must explicitly use it for the correct type, they cannot be dereferenced directly. They allow you to skip type checking and should be avoided.

Another difference that I see is clarity of intent. When you see a char * pointer, you cannot be sure that it will point to a char / char array. It may be something else, it is very situational: I have seen cases where it was confusing, sometimes it is obvious; on the other hand, the intent of void pointers is clear: it can really be anything, and you have to look at the application context to find the type.

Another thing is pointer arithmetic, AFAIR in the case of void pointers, which it does not define by standard.

I assume that the void pointers in OpenGL are used to make the API more general, giving more control over drivers (this makes it easy to change floating-point types by half the settings). But this requires only assumptions, confirmation.

0
source

Source: https://habr.com/ru/post/973205/


All Articles