OpenGL VBOs and Shaders

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
yadsmood
In need of some credit
In need of some credit
Posts: 2
Joined: Fri May 11, 2012 11:41 pm

OpenGL VBOs and Shaders

Post by yadsmood »

I am trying to write a basic program to draw 3 triangles using 2 vertex buffer objects, a fragment shader and a vertex shader. My trouble is that whenever I try to run my program it segfaults when calling glGetString(GL_VERSION).

Here is the stack trace from gdb:
#0 0xb772c336 in glGetString () from /usr/lib/mesa/libGL.so.1
#1 0x0805095d in getGLversion () at GLSL_helper.cpp:88
#2 0x0804f395 in BasicGLPane::prepare3DViewport (this=0x80e59f8) at main.cpp:181
#3 0x0804f1b9 in BasicGLPane (this=0x80e59f8, parent=0x80d87d0, args=0xbffff2b0) at main.cpp:162
#4 0x0804ee61 in MyApp::OnInit (this=0x807e148) at main.cpp:136
#5 0x0804fa20 in wxAppConsole::CallOnInit (this=0x807e148) at /usr/include/wx-2.8/wx/app.h:76
#6 0xb77e69e0 in wxEntry(int&, wchar_t**) () from /usr/lib/libwx_baseu-2.8.so.0
#7 0xb77e6be7 in wxEntry(int&, char**) () from /usr/lib/libwx_baseu-2.8.so.0
#8 0x0804ecf9 in main (argc=1, argv=0xbffff444) at main.cpp:126

Here is my code:

main.cpp

Code: Select all

#include "wx/wx.h"
#include "wx/sizer.h"
#include "wx/glcanvas.h"
#include "main.h"
 
// include OpenGL
#ifdef __WXMAC__
#include "OpenGL/glu.h"
#include "OpenGL/gl.h"
#else
#include <GL/glu.h>
#include <GL/gl.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include "GLSL_helper.h"

/* the vertex data */
GLfloat vertexPos[] = {
 -0.5, -0.5, 0.0, 1.0,
 0, 0.5, 0.0, 1.0,
 0.5, -0.5, 0.0, 1.0,

0.6, 0.5, 0.0, 1.0,
0.6, -0.5, 0.0, 1.0,
0.1, 0.5, 0.0, 1.0,

-0.6, 0.5, 0.0, 1.0,
-0.6, -0.5, 0.0, 1.0,
-0.1, 0.5, 0.0, 1.0,
};

/* the color data */
static GLfloat vertexCol[] = {
 1.0, 0.0, 1.0,  
 1.0, 0.0, 1.0, 
1.0, 0.0, 0.0,

 1.0, 0.0, 0.0, 
 1.0, 0.0, 0.0, 
 1.0, 0.0, 0.0, 

 1.0, 0.0, 1.0, 
  1.0, 0.0, 1.0, 
  1.0, 0.0, 1.0, 
};

//position and color data handles
GLuint triBuffObj, colBuffObj;

//flag and ID to toggle on and off the shader
int shade = 1;
int ShadeProg;

//Handles to the shader data
GLint h_aPosition;
GLint h_aColor;

/* initialize the geomtry (including color)*/
void InitGeom() {
  glGenBuffers(1, &triBuffObj);
  glGenBuffers(1, &colBuffObj);

  glBindBuffer(GL_ARRAY_BUFFER, triBuffObj);
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPos), vertexPos, GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, colBuffObj);
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertexCol), vertexCol, GL_STATIC_DRAW);
}


/*function to help load the shader */
int InstallShader(const GLchar *vShaderName) {
	GLuint VS; //handles to shader object
	GLint vCompiled, linked; //status of shader
	
	VS = glCreateShader(GL_VERTEX_SHADER);
	
	//load the source
	glShaderSource(VS, 1, &vShaderName, NULL);
	
	//compile shader and print log
	glCompileShader(VS);
	/* check shader status requires helper functions */
	printOpenGLError();
	glGetShaderiv(VS, GL_COMPILE_STATUS, &vCompiled);
	printShaderInfoLog(VS);
	
	if (!vCompiled) {
		printf("Error compiling the shader %s", vShaderName);
		return 0;
	}
	 
	//create a program object and attach the compiled shader
	ShadeProg = glCreateProgram();
	glAttachShader(ShadeProg, VS);
	
	glLinkProgram(ShadeProg);
	/* check shader status requires helper functions */
	printOpenGLError();
	glGetProgramiv(ShadeProg, GL_LINK_STATUS, &linked);
	printProgramInfoLog(ShadeProg);

	glUseProgram(ShadeProg);
	
	/* get handles to attribute data */
	h_aPosition = safe_glGetAttribLocation(ShadeProg, "aPosition");
	h_aColor = safe_glGetAttribLocation(ShadeProg,	"aColor");

	printf("sucessfully installed shader %d\n", ShadeProg);
	return 1;
	
}

 
class MyApp: public wxApp
{
    virtual bool OnInit();
    
    wxFrame *frame;
    BasicGLPane * glPane;
public:
    
};
 
IMPLEMENT_APP(MyApp)
 
 
bool MyApp::OnInit()
{
    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    frame = new wxFrame((wxFrame *)NULL, -1,  wxT("Hello GL World"), wxPoint(50,50), wxSize(400,200));
	
    int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0};
    
    glPane = new BasicGLPane( (wxFrame*) frame, args);
    sizer->Add(glPane, 1, wxEXPAND);
	
    frame->SetSizer(sizer);
    frame->SetAutoLayout(true);

    frame->Show();
    
    return true;
} 
 
BEGIN_EVENT_TABLE(BasicGLPane, wxGLCanvas)
EVT_PAINT(BasicGLPane::render)
END_EVENT_TABLE()
 
 
 
BasicGLPane::BasicGLPane(wxFrame* parent, int* args) :
    wxGLCanvas(parent, wxID_ANY, args, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
	m_context = new wxGLContext(this);
   
    // To avoid flashing on MSW
   SetBackgroundStyle(wxBG_STYLE_CUSTOM);
   
   wxGLCanvas::SetCurrent(*m_context);
   prepare3DViewport();
    
}
 
BasicGLPane::~BasicGLPane()
{
	delete m_context;
}
 
void BasicGLPane::resized(wxSizeEvent& evt)
{
//	wxGLCanvas::OnSize(evt);
	
    Refresh();
}
 
/** Inits the OpenGL viewport for drawing in 3D. */
void BasicGLPane::prepare3DViewport()
{
   getGLversion();
	//install the shader
	if (!InstallShader(textFileRead((char *)"GLSL_Lab1.glsl"))) 
	{
		printf("Error installing shader!\n");
   }
 
   InitGeom();
	
	// Start Of User Initialization
	glClearColor (1.0f, 1.0f, 1.0f, 1.0f);								
	// Black Background
 	glClearDepth (1.0f);	// Depth Buffer Setup
 	glDepthFunc (GL_LEQUAL);	// The Type Of Depth Testing
	glEnable (GL_DEPTH_TEST);// Enable Depth Testing
	
}
 
int BasicGLPane::getWidth()
{
    return GetSize().x;
}
 
int BasicGLPane::getHeight()
{
    return GetSize().y;
}
 
 
void BasicGLPane::render( wxPaintEvent& evt )
{
    if(!IsShown()) return;
    
    wxGLCanvas::SetCurrent(*m_context);
    wxPaintDC(this); // only to be used in paint events. use wxClientDC to paint outside the paint event
    
    prepare3DViewport();
	
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			
	//Start our shader	
 	glUseProgram(ShadeProg);

	//data set up to access the vertices and color
  	safe_glEnableVertexAttribArray(h_aPosition);
 	glBindBuffer(GL_ARRAY_BUFFER, triBuffObj);
	safe_glVertexAttribPointer(h_aPosition, 4, GL_FLOAT, GL_FALSE, 0, 0);
  	safe_glEnableVertexAttribArray(h_aColor);
 	glBindBuffer(GL_ARRAY_BUFFER, colBuffObj);
	safe_glVertexAttribPointer(h_aColor, 3, GL_FLOAT, GL_FALSE, 0, 0);

	//actually draw the data
	glDrawArrays(GL_TRIANGLES, 0, 9);	
													
	//clean up 
	safe_glDisableVertexAttribArray(h_aPosition);
	safe_glDisableVertexAttribArray(h_aColor);
	//disable the shader
	glUseProgram(0);	
    
    glFlush();
    SwapBuffers();
}
GLSL_helper.cpp

Code: Select all

/*
 *  GLSL_helper.cpp
 */

#include "GLSL_helper.h"

int printOglError (const char *file, int line) {
	/* Returns 1 if an OpenGL error occurred, 0 otherwise. */
	GLenum glErr;
	int    retCode = 0;
	
	glErr = glGetError ();
	while (glErr != GL_NO_ERROR) {
		printf ("glError in file %s @ line %d: %s\n", file, line, gluErrorString (glErr));
		retCode = 1;
		glErr = glGetError ();
    	}
	return retCode;
}

void printShaderInfoLog (GLuint shader)
{
	GLint     infologLength = 0;
	GLint     charsWritten  = 0;
	GLchar *infoLog;
	
	printOpenGLError ();  // Check for OpenGL errors
	glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &infologLength);
	printOpenGLError ();  // Check for OpenGL errors
	
	if (infologLength > 0) {
		infoLog = (GLchar *)malloc (infologLength);
		if (infoLog == NULL) {
			puts ("ERROR: Could not allocate InfoLog buffer");
			exit (1);
        	}
		glGetShaderInfoLog (shader, infologLength, &charsWritten, infoLog);
		printf ("Shader InfoLog:\n%s\n\n", infoLog);
		free (infoLog);
    	}
	printOpenGLError();  // Check for OpenGL errors
}

/* Print out the information log for a program object */
void printProgramInfoLog (GLuint program)
{
	GLint     infologLength = 0;
	GLint     charsWritten  = 0;
	GLchar *infoLog;
	
	printOpenGLError ();  // Check for OpenGL errors
	glGetProgramiv (program, GL_INFO_LOG_LENGTH, &infologLength);
	printOpenGLError ();  // Check for OpenGL errors
	
	if (infologLength > 0)
    	{
		infoLog = (GLchar *)malloc (infologLength);
		if (infoLog == NULL)
        	{
			puts ("ERROR: Could not allocate InfoLog buffer");
			exit (1);
        	}
		glGetProgramInfoLog (program, infologLength, &charsWritten, infoLog);
		printf ("Program InfoLog:\n%s\n\n", infoLog);
		free (infoLog);
    	}
	printOpenGLError ();  // Check for OpenGL errors
}

//A helper routine to make it easier to set uniform variables in the shader
GLint getUniLoc(GLuint program, const GLchar *name) {
	GLint loc;
	
	loc = glGetUniformLocation(program, name);
	
	if (loc ==1) {
		printf("No such uniform named %s\n", name);
	}
	
	printOpenGLError();
	return loc;
}

void getGLversion() {
	int major, minor;
	
	major = minor =0;
	const char *verstr = (const char *)glGetString(GL_VERSION);
	
	if ((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) !=2)) {
		printf("Invalid GL_VERSION format %d %d\n", major, minor);
	}
	if( major <2) {
		printf("This shader example will not work due to opengl version, which is %d %d\n", major, minor);
		exit(0);
	}
}

char *textFileRead(char *fn) {
	
	
	FILE *fp;
	char *content = NULL;
	
	int count=0;
	
	if (fn != NULL) {
		fp = fopen(fn,"rt");
		
		if (fp != NULL) {
			
			fseek(fp, 0, SEEK_END);
			count = ftell(fp);
			rewind(fp);
			
			if (count > 0) {
				content = (char *)malloc(sizeof(char) * (count+1));
				count = fread(content,sizeof(char),count,fp);
				content[count] = '\0';
			}
			fclose(fp);
		}
	}
	return content;
}

int textFileWrite(char *fn, char *s) {
	
	FILE *fp;
	int status = 0;
	
	if (fn != NULL) {
		fp = fopen(fn,"w");
		
		if (fp != NULL) {
			
			if (fwrite(s,sizeof(char),strlen(s),fp) == strlen(s))
				status = 1;
			fclose(fp);
		}
	}
	return(status);
}
I am compiling using the command:
g++ main.cpp GLSL_helper.cpp -g -o gl `wx-config --libs --cxxflags --gl-libs` -DGL_GLEXT_PROTOTYPES -lglut -lGL -lGLU

I am on Ubuntu 10.04 with wxWidgets version 2.8.

Any help would be much appreciated.
Radek
Super wx Problem Solver
Super wx Problem Solver
Posts: 286
Joined: Sun Sep 11, 2011 7:17 am

Re: OpenGL VBOs and Shaders

Post by Radek »

I haven't analyzed your code thoroughly but I have taught the hard way that:

Your very first OpenGL call in a wxWidgets program must be made from the OnPaint handler of your OpenGL window.

You get a GP fault otherwise for some reason. Once you have made the first call, subsequent calls can be made from anywhere. It's enough to make sure that you have set the OpenGL context. As far as your code is concerned, prepare3DViewport() is called from the BasicGLPane ctor - much sooner than the window gets its first OnPaint event. You get a GP fault on the first OpenGL call from prepare3DViewport(). I am using the following schema:

(1) The BasicGLPane needs an OnEraseBackground, OnPaint and OnSize handlers. It also needs an InitDone bool variable.
(2) Make the OnEraseBackground handler empty - suppress flickering.
(3) The OnPaint handler

Code: Select all

if( !InitDone )
{
  <set current context>
  <iinitialize OpenGL>
  InitDone = true;
  <send OnSize event to yourself>
}

<render>
(4) The OnSize handler

Code: Select all

if( InitDone )
{
  <set current context>
  <set viewport, etc.>
}
else Skip();
The OnSize handler is needed because the handler needs to make OpenGL calls but you get OnSize event before getting the first OnPaint. You need to block OpenGL processing in OnSize until you get your first OnPaint. Then you can set viewport, coordinate system and other things. You will send an OnSize event you yourself during initialization so that render will have viewport and coordinate system ready.
yadsmood
In need of some credit
In need of some credit
Posts: 2
Joined: Fri May 11, 2012 11:41 pm

Re: OpenGL VBOs and Shaders

Post by yadsmood »

Your suggestions got it working. Thank you so much.
Post Reply