OpenGL Vertex Buffer Object


#1

Howdy,

I’m trying a simple test to create a VBO in JUCE with the code below, most of which was taken from the JuceDemo. My triangle does get displayed but only on the first call to renderOpenGL(), after that it does not appear.

Could someone please tell me what I’m doing wrong?

Thanks,

Bird

[code]
enum { PositionSlot, ColorSlot };

void OpenglCanvas::newOpenGLContextCreated ()
{
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Glew didn’t initialize
jassert(0);
Logger::writeToLog(“ERROR::Glew failed to initialize”);
}

float verts[] = {
    -0.5f, -0.5f,  1,1,0, // Yellow
    +0.0f, +0.5f,  1,0,1, // Magenta
    +0.5f, -0.5f,  0,1,1, // Cyan
};

GLuint vboHandle;
GLsizeiptr vboSize = sizeof(verts);
GLsizei stride = 5 * sizeof(float);
GLenum usage = GL_STATIC_DRAW;
GLvoid* colorOffset = (GLvoid*) (sizeof(float) * 2);

glGenBuffers(1, &vboHandle);
glBindBuffer(GL_ARRAY_BUFFER, vboHandle);
glBufferData(GL_ARRAY_BUFFER, vboSize, verts, usage);
glVertexAttribPointer(PositionSlot, 2, GL_FLOAT, GL_FALSE, stride, 0);
glVertexAttribPointer(ColorSlot, 3, GL_FLOAT, GL_FALSE, stride, colorOffset);
glEnableVertexAttribArray(PositionSlot);
glEnableVertexAttribArray(ColorSlot);

}

void OpenglCanvas::renderOpenGL ()
{
OpenGLHelpers::clear (Colours::black.withAlpha (1.0f));
{
MessageManagerLock mm (Thread::getCurrentThread());
if (! mm.lockWasGained())
return;
}

glDrawArrays(GL_TRIANGLES, 0, 3);	

}[/code]


#2

GL has about a million different settings, all of which need to be initialised correctly before you draw anything. Welcome to the world of openGL!


#3

Hi Jules,

I’m pretty sure this should work without any other opengl calls.

I found that If I set OpenGLContext::setComponentPaintingEnabled() to false then there’s no problem. But if it’s set to true then the triangle won’t render after the first call to paint().
Heres’ a bare bones test component without using Glew, in case you think this is a problem with JUCE that you need to look into.

[code]#define GL_ARRAY_BUFFER 0x8892
#define GL_STATIC_DRAW 0x88E4

class testVBO : public Component,
public OpenGLRenderer,
public Timer
{

public:
enum { PositionSlot, ColorSlot };

public:
testVBO ()
{
openGLContext.setRenderer (this);
// if setComponentPaintingEnabled is true then the triangle
// does not render again after paint() has been called
openGLContext.setComponentPaintingEnabled (false);
openGLContext.attachTo (*this);
}
~testVBO () {openGLContext.detach();}

void mouseDown (const MouseEvent & e){}
void mouseDrag (const MouseEvent & e) {}
void resized () {}
void timerCallback () {}
void paint (Graphics & g) {}
void openGLContextClosing () {}

void newOpenGLContextCreated ()
{
	float verts[] = {
		-0.5f, -0.5f,  1,1,0, // Yellow
		+0.0f, +0.5f,  1,0,1, // Magenta
		+0.5f, -0.5f,  0,1,1, // Cyan
	};

	int vboSize = sizeof(verts);
	GLsizei stride = 5 * sizeof(float);
	GLenum usage = GL_STATIC_DRAW;
	GLvoid* colorOffset = (GLvoid*) (sizeof(float) * 2);

	openGLContext.extensions.glGenBuffers(1, &vboHandle);
	openGLContext.extensions.glBindBuffer(GL_ARRAY_BUFFER, vboHandle);
	openGLContext.extensions.glBufferData(GL_ARRAY_BUFFER, vboSize, verts, usage);
	openGLContext.extensions.glVertexAttribPointer(PositionSlot, 2, GL_FLOAT, GL_FALSE, stride, 0);
	openGLContext.extensions.glVertexAttribPointer(ColorSlot, 3, GL_FLOAT, GL_FALSE, stride, colorOffset);
	openGLContext.extensions.glEnableVertexAttribArray(PositionSlot);
	openGLContext.extensions.glEnableVertexAttribArray(ColorSlot);
}
void renderOpenGL ()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	{
		MessageManagerLock mm (Thread::getCurrentThread());
		if (! mm.lockWasGained())
			return;
	}
	glDrawArrays(GL_TRIANGLES, 0, 3);  
}

private:
OpenGLContext openGLContext;
GLuint vboHandle;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (testVBO)

}; // end class testVBO[/code]


#4

It’s no good treating this like a juce problem - when your render function is called, the GL context’s state is totally undefined, and it’s your responsibility to set it up appropriately for your drawing operations.


#5

Well, the thing is that I think I do have the state setup correctly since it renders perfectly as long the my gl component was compiled with OpenGLContext::setComponentPaintingEnabled () set to false. When setComponentPaintingEnable() is true then OpenGLContext::paint() is called and that’s when it things stop working .

-Bird


#6

huh? You just call glDrawArrays without setting any state at all!

If you’re using the component rendering, then before calling that function, the juce code will just have finished doing a massive amount of complicated rendering, and like I said, it will have left the context in an undefined state.


#7

[quote]
huh? You just call glDrawArrays without setting any state at all![/quote]

The array buffers are setup in newOpenGLContextCreated(). AFAIK, you don’t need to set any other opengl state to render them.

-Bird


#8

yeah, apart from the matrix, blend mode, shader program, mask settings, and about a thousand other things.


#9

yeah, apart from the matrix, blend mode, shader program, mask settings, and about a thousand other things.[/quote]

I was referring to this simple example, where the initial opengl defaults are sufficient to obtain a render. I tried re-setting some state in renderOpenGL() and the triangle still disappears after calling the component render. I’m guessing the VBO handle has also become invalid after component rendering and if that’s the case then VBO and component rendering are incompatible since having to regenerate the VBO on every render call will defeat the purpose of using it.

Sorry to bother you.

-Bird

[code]void OpenglCanvas::renderOpenGL ()
{
OpenGLHelpers::clear (Colours::black.withAlpha (1.0f));
{
MessageManagerLock mm (Thread::getCurrentThread());
if (! mm.lockWasGained())
return;
}

glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LESS);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_TEXTURE_2D);

// Set the viewport to be the entire window
glViewport(0, 0, getWidth(), getHeight());

// Set the clipping volume
glOrtho(-100.0f, getWidth(), -100.0f, getWidth(), -200.0f, 200.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

openGLContext.extensions.glBindBuffer(GL_ARRAY_BUFFER, vboHandle);
openGLContext.extensions.glEnableVertexAttribArray(PositionSlot);
openGLContext.extensions.glEnableVertexAttribArray(ColorSlot);

glDrawArrays(GL_TRIANGLES, 0, 3);  

}[/code]