# glDrawRangeElement issue.

This topic is 4249 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

i'm not coding in C++. Instead i'm using blitzmax. However, i doubt it's the source of the problem. Case Key_1 does as expected and renders the quad. Case Key_2 does as expected and renders the top corner. However case Key_3 only renders the left upper half. Instead it's suppost to render the bottom right corner of the quad. Can someone help me out here?
GLGraphics 800,600
glewInit()

Local	fltVertex#[] =[ -1.0 , 1.0 , 0.0 ,    1.0 , 1.0,  0.0 ,    -1.0, -1.0, 0.0 ,    1.0, -1.0, 0.0 ]
Local	fltColor#[] = [ 1.0 ,  0.0 , 0.0 ,    0.0 , 1.0,  0.0 ,     0.0,  0.0, 1.0 ,    1.0,  1.0, 0.0 ]
'              Red                      Green              Blue                  Yellow
Local	shtElements:Short[] = [ 0:Short,  1:Short, 2:Short, 1:Short, 3:Short , 2:Short ]

glMatrixMode(GL_PROJECTION);				'		// Select The Projection Matrix
glLoadIdentity();							'// Reset The Projection Matrix

'// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0 ,Float(GraphicsWidth())/GraphicsHeight(),0.1 ,100.0 );

glMatrixMode(GL_MODELVIEW);						'// Select The Modelview Matrix

glClearColor( 0.0, 0.0 , 0.0 , 0.0 )

glEnable(GL_DEPTH_TEST);					'	// Enables Depth Testing

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

glEnableClientState(GL_VERTEX_ARRAY)
glEnableCLientState(GL_Color_Array)
glVertexPointer(3, GL_FLOAT , 0 , Varptr(fltVertex[0]) )
glColorPointer(3,  GL_FLOAT , 0 , Varptr(fltColor[0]) )

Local KeyInput = KEY_1
While Not KeyHit(KEY_A)

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			'// Clear The Screen And The Depth Buffer
glLoadIdentity();							'// Reset The Current Modelview Matrix

glTranslatef( 0.0 , 0.0, -5.0 )

If KeyHit(KEY_1)
Keyinput = KEY_1
ElseIf KeyHit(Key_2)
keyinput = KEY_2
ElseIf KeyHit(Key_3)
keyinput = KEY_3
EndIf

Select KeyInput

Case KEY_1
glDrawRangeElements(GL_TRIANGLES, 0,5,6, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )
Case Key_2
glDrawRangeElements(GL_TRIANGLES, 0,2,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )
Case Key_3
glDrawRangeElements(GL_TRIANGLES, 3,5,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )

End Select

Flip()

Wend

gldisableClientState(GL_VERTEX_ARRAY)
gldisableCLientState(GL_Color_Array)



##### Share on other sites
Quote:
 Original post by Drey Case KEY_1 glDrawRangeElements(GL_TRIANGLES, 0,5,6, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) ) Case Key_2 glDrawRangeElements(GL_TRIANGLES, 0,2,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) ) Case Key_3 glDrawRangeElements(GL_TRIANGLES, 3,5,3, GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )

Well I don't know the language, but shouldn't the last parameter to glDrawRangeElements in case Key_3 be Varptr(shtElements[3])?

Remember, glDraw*Elements will start dereferncing from the pointer you provide irrespective of the range.

##### Share on other sites
First, your call for case 3 is identical to that of case 2, except the range of index values. So if case 2 draws the top half then so should case 3.

Second, you start and end values are the maximum and minimum values in the index array. For case 3, you say that no indices are outside the range [3, 5]. But clearly every index except the second last index is outside this range. I assume the call for case 3 would looks something like this (adjust the syntax for your language).
glDrawRangeElements(GL_TRIANGLES,                               1,    // Smallest value in the range of interest (index 3 to 5, see below) is 1.                               3,    // Largest index in the range of interest is 3.                               3,    // Draw 3 indices, making one triangle.               GL_UNSIGNED_SHORT,               Varptr(shtElements[3])    // Start drawing at index 3, which means index 3 to 5 since the number of indices to draw is 3.);

For the same reason, case 1 and 2, while not wrong in the sense that you're lying to OpenGL about the smallest and largest index value, are not really correct. Case 1 should have smallest and largest index set to 0 and 3, respectively, and case 2, 0 and 2.

Now while writing mu reply it seems like you misunderstand the start and end values. Seems like you think these values are represent what part of the index array to use, but they are not. OpenGL is perfectly capable of calculating those values itself from the start pointer and the number of indices to draw. What it's not capable of is to determine what the values of those indices are, i.e. the content of the index array.

##### Share on other sites
OK, but changing the pointers like that isn't an good idea for VBOs though or should i use gBufferSubData for every range change? Kinda kills the purpose though. How will i control regions with VBO?

##### Share on other sites
Quote:
 Original post by DreyOK, but changing the pointers like that isn't an good idea for VBOs though ...

Why do you thisnk that?

You are just providing an offset from the start of your index array basically. There is no additional cost in providing &indices[n] and &indices[0] ... the GPU just starts reading from a different memory address.

##### Share on other sites
because my orginal design idea was to have prepare the VBO once ( with glbindbuffer ) and then call on regions of the array as needed. So the array loaded was going to be the WHOLE mesh, and i was giong to call on glDraw"Range"Elements to render different parts under different matrices. It would have only taken one command before for VBO..now it seems like i have to do a few..which defeats the purpose somewhat.

##### Share on other sites
But you don't have to change any arrays, and what we're telling you to do is what you want to do. If you want OpenGL to draw 3 vertices, starting at the 3:rd index, then you pass a pointer (or offset, since you use VBO) to the 3:rd index, and set the size to 3.

Range in glDrawRangeElements does not refer to drawing a sub range of the index array. It tells OpenGL what the range of the index values, the values in the index array, is. For the purpose of only drawing certain parts of the object, then glDrawElements is just fine. glDrawRangeElements doesn't provide anything but the chance of a more optimized rendering. It doesn't provide anything that can't be done with glDrawElements.

##### Share on other sites
Oh, i understand that. I'm just worried about my VBOs working correctly now.

glGenBuffers 1, Varptr(intVertexBuffer)
glBindBuffer(GL_ARRAY_BUFFER, intVertexBuffer)
glBufferData(GL_ARRAY_BUFFER, SizeOf(fltVertex), Varptr(fltVertex[0]), GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0 )

in bufferdata i'll have to change to Varptr(fltVertex[3]) for this example. I was trying to avoid calling bindbuffer again. The idea was to do something like this.
Mesh.BeginRender() //if in VBO mode, binds buffers.  If in VA mode, sets pointersLoops for Num Of RefMesh  Loops for RefMesh.SegementUpdateList       // Model Transform matrix       Segement.Position.toMatrixLoad()      //       Mesh.Render( Segement.ElementRange )  // Range object containing starting and ending in the arrayEnd LoopMesh.EndRender()

It's rough peusocode, but it conveys the idea mostly.
I know it's not a big deal in VA(change pointers) but it is in VBO. Is there a way to get the same effect without rebinding?

##### Share on other sites
Unless what you're telling us is not whta you actually want, then the answer we have given you is the solution to your problem.

Create the VBO by uploading the mesh data once, and only once. No need to touch it any more. When drawing sub parts of the mesh, adjust the starting address passed to glDraw(Range)Elements.

That's all there is. Really.

##### Share on other sites
I had a post typed up but now i really understand what's goin on now. I can bind everything like normal except the indices array. I was binding that as well. That's where all this confusion came from. I guess it isn't really too bad a bottleneck to have the indice array stream from the RAM and nothing else.

I was passing a null as a pointer once i had the indice array loaded

							glGenBuffers 1, Varptr(intVertexBuffer)				glBindBuffer(GL_ARRAY_BUFFER, intVertexBuffer)				glBufferData(GL_ARRAY_BUFFER, SizeOf(fltVertex), Varptr(fltVertex[0]), GL_STATIC_DRAW)				glBindBuffer(GL_ARRAY_BUFFER, 0 )								glGenBuffers(1,  Varptr(intElementBuffer) )				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, intElementBuffer)				glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeOf(shtElements), Varptr(shtElements[0]), GL_STATIC_DRAW)				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 )

Then i will have 3 modes. ALL VBO(including indices, non animated or non seperatable items), Partical VBO mode(likely excluding indice binding), and a VA mode. (if i'm understanding this correctly)

Thanks guys! :-D

##### Share on other sites
Still not sure you understand it. You speak of streaming the index arrays from main memory, but what we're talking about doesn't include any streaming. At all. Not even of the index array. It only includes adding an integer to the last parameter to glDraw(Range)Elements and nothing else.

##### Share on other sites

This is my old testing implimentation without the new changes. Note the render method if vbo is true and the null pointer. Are you saying put an integer where Null is on DrawElements?

	Method BeginRender()				glEnableClientState(GL_Vertex_Array)				If fltColor			glEnableClientState(GL_Color_Array)		EndIf				If VBO					glBindBuffer(GL_ARRAY_BUFFER, intVertexBuffer)			glVertexPointer(3, GL_FLOAT , 0, Null)							If fltColor							glBindBuffer(GL_ARRAY_BUFFER, intColorBuffer)				glColorPointer(3, GL_Float , 0, Null)							EndIf 							glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, intElementBuffer)						Else					glVertexPointer(3, GL_FLOAT , 0 , Varptr(fltVertex[0]) )						If fltColor				glColorPointer(3,  GL_FLOAT , 0 , Varptr(fltColor[0]) )			EndIf			glLockArraysEXT(0, shtElements.length) 		EndIf				End Method		Method Render()			If VBO					glDrawElements(GL_TRIANGLES, shtElements.length , GL_UNSIGNED_SHORT, Null)						Else	'using VA					glDrawElements(GL_TRIANGLES, shtElements.length , GL_UNSIGNED_SHORT , Varptr(shtElements[0]) )									EndIf	End Method

From the tutorials i've seen. You pass a null pointer when VBO binding..i'm assuming you can do this because it's not loading data off of ram like in VAs. If you look at the render method and if VBO is true. You see i don't need a pointer to anything because it's loaded in the Vram(i'm guessing). So i use a null. In the case of VA, i do need to pass a pointer. So i'm saying i could have Vertices, Normals etc on Vram. If I put indices on Vram..how can i control the pointer? The pointer address is the ram address.

##### Share on other sites
The last parameter can have two different meanings.

• When VBO is NOT used, that is, "regular" vertex arrays are in use, it is a pointer to the first index in the index array you want to draw. If you want to start drawing at index 8 (just an example), you can call glDrawElements like this:
glDrawElements(..., &myIndexArray[8]);

You offset the start by 8 indices.

• When VBO is in use, the last parameter is the offset from the start of the buffer. If you pass a null pointer, wich has the value 0, it means you want to start taking indices from the beginning, plus an offset of 0.

To start drawing at index 8, just like in the last example, you provide the corresponding offset.
glDrawElements(..., reinterpret_cast<void *>(8 * sizeof(GLushort)));

Don't know what the corresponding code to convert an arbitrary integer to a pointer is, but this is how it looks in C++. Basically, you provide the offset in bytes. The eighth index is located at a byte offset of 8 times the size of an index in bytes. For example, for 16 bit indices, the byte offset would be 8*2=16 bytes.

That's how you do it, both for regular VA and VBO.

##### Share on other sites
Sir..thank you so very much. :)

In blitzmax it's "int ptr(value)"

It's a rather nice langage and it's multiplatform.