tags:

views:

148

answers:

4

I found this in the PowerVR mesh drawing code and I don't really know how to read it.

&((unsigned short*)0)[3 * mesh.sBoneBatches.pnBatchOffset[batchNum]]

What is going on here? Is this a reference to void cast as an unsigned short pointer and then offset by (3*mesh(etc...) + batchNum)? It's breaking my brain.

It's found in the context of a glDrawElements call:

glDrawElements(GL_TRIANGLES, i32Tris * 3, GL_UNSIGNED_SHORT, 
               &((unsigned short*)0)[3 * mesh.sBoneBatches.pnBatchOffset[batchNum]]);
+2  A: 

It's computing a byte offset -- 3 * mesh.sBoneBatches.pnBatchOffset[batchNum] is the index. Using 0 as the pointer means that the address will be just the offset value, nothing else.

brool
In essence, it's `3 * mesh.sBoneBatches.pnBatchOffset[batchNum] * sizeof(unsigned short)` (though with a different type), assuming that `unsigned short[]` arrays are aligned naturally with no padding.
ephemient
I dont get it . Shouldn't "((unsigned short*)0)[...]" dereference a null pointer, thus leading in unexpected behavior ?
Samuel_xL
@TheSamFrom1984: No, because dereferencing is not needed to take the address. This is a common trick in C, and is theoretically illegal in C++, but generally works anyways.
ephemient
A: 

Its an obfuscated way of computing

sizeof(unsigned short) * 3 * mesh.sBoneBatches.pnBatchOffset[batchNum]

but since it doesn't actually save any characters, its not a very good obfuscation

Chris Dodd
Only one caveat - it returns a pointer to address N, not N as a number.
Arkadiy
+6  A: 

Let's go from the inside out.

(unsigned short*)0

This is casting 0 to an unsigned short pointer. This will be used for computing a memory offset, computed in terms of the size of an unsigned short.

3 * mesh.sBoneBatches.pnBatchOffset[batchNum]

This is, presumably, the offset in memory of some batch of triangles. A triangle is composed of 3 shorts, so it looks like they are storing an offset in terms of numbers of triangles, and then multiplying by 3 to get the number of shorts.

((unsigned short*)0)[3 * mesh.sBoneBatches.pnBatchOffset[batchNum]]

This is now using that 0 pointer to find the memory location of the given offset. This would normally return the value of that memory location, but they want a pointer to pass into glDrawElements, so the use the & operator to get a pointer to that memory location:

&((unsigned short*)0)[3 * mesh.sBoneBatches.pnBatchOffset[batchNum]]
Brian Campbell
why isn't the applicaiton crashing at step 3 ? (attempt to get the value of a bad memory location)
Samuel_xL
t_scho
It didn't know about this particularity of the language. Doesn't seem "natural" to me. Thanks.
Samuel_xL
That was very helpful, thank you. One more question, is a 0 pointer the same concept as a void pointer?
spencewah
No, but C mandates that the NULL pointer converts to an integral 0 and vice versa, and C++ mandates that NULL is represented by 0.
ephemient
+1  A: 

Really, this kind of hack is due to OpenGL expressing offsets inside Buffer Objects through the pointer argument of glDrawElements.

glDrawElements(mode, count, type, void* indices)

indices represents either a client-side memory pointer or a server-side memory offset based on the binding of GL_ELEMENT_ARRAY_BUFFER_ARB

It's interesting to dig a bit deeper... From the VBO specification:

Is it legal C to use pointers as offsets?

We haven't come to any definitive conclusion about this. [...]

Varying opinions have been expressed as to whether this is legal, although no one could provide an example of a real system where any problems would occur.

Bahbar