I’m trying to get a very basic VBO working in Qt to render some line segments. I had it working in JOGL, but moved over to C++ and was hoping to take advantage of Qt’s encapsulation for readability. I’m not sure, however, if I’m doing something wrong packing my data into the array as glEnableVertexAttribArray causes an unexpected crash.
This is the header file…
#ifndef PANELGL_H
#define PANELGL_H
#include <QGLWidget>
#include <QGLBuffer>
#include "shader.h"
#include "util.h"
#include "camera.h"
class PanelGL : public QGLWidget
{
public:
PanelGL();
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
QGLFormat defaultFormat();
Camera* camera;
QGLShaderProgram* getFlatShader() { return _flatShader; }
private:
bool _validShaders;
QGLShaderProgram* _flatShader;
QGLShaderProgram* _dummyShader;
};
struct LineSegment {
Point3 p1;
Point3 p2;
float r;
float g;
float b;
};
class LineRenderer
{
public:
LineRenderer(QVector<LineSegment> segments, float lineWidth);
void render(PanelGL* panel);
void loadVBOs(PanelGL* panel);
private:
bool _validVBOs;
float _lineWidth;
QVector<LineSegment> _segments;
QGLBuffer _segmentsVBO;
QGLBuffer _segmentColorsVBO;
void drawSegments(QGLShaderProgram* program);
};
#endif // PANELGL_H
And the actual code…
#include "panelgl.h"
#include "camera.h"
#include <QVarLengthArray>
#include <iostream>
using namespace std;
LineRenderer* mainGrid = NULL;
PanelGL::PanelGL() : QGLWidget(PanelGL::defaultFormat())
{
setMouseTracking(true);
_validShaders = false;
camera = new Camera();
if (mainGrid == NULL) {
int range[] = {-10,10};
int numSegments = range[1]-range[0]+1;
QVector<LineSegment> segments(numSegments);
for (int i = 0; i < numSegments; i++) {
segments[i].p1 = Point3(i, 0, 10);
segments[i].p2 = Point3(i, 0, -10);
segments[i].r = 0.4f;
segments[i].g = 0.4f;
segments[i].b = 0.4f;
}
mainGrid = new LineRenderer(segments, 2);
}
}
QGLFormat PanelGL::defaultFormat()
{
QGLFormat format;
format.setVersion(3,2);
format.setProfile(QGLFormat::CompatibilityProfile);
return format;
}
void PanelGL::initializeGL()
{
}
void PanelGL::paintGL()
{
glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
if (!_validShaders) {
_dummyShader = ShaderFactory::buildShader(this);
_flatShader = ShaderFactory::buildFlatShader(this);
_validShaders = true;
}
// render the grid
mainGrid->render(this);
glDisable(GL_DEPTH_TEST);
}
void PanelGL::resizeGL(int width, int height)
{
glViewport(0,0,width,height);
}
LineRenderer::LineRenderer(QVector<LineSegment> segments, float lineWidth)
{
_validVBOs = FALSE;
_segments = segments;
_lineWidth = lineWidth;
}
void LineRenderer::render(PanelGL* panel)
{
if (!_validVBOs) {
_segmentsVBO = QGLBuffer(QGLBuffer::IndexBuffer);
_segmentsVBO.create();
_segmentColorsVBO = QGLBuffer(QGLBuffer::IndexBuffer);
_segmentColorsVBO.create();
_validVBOs = TRUE;
}
loadVBOs(panel);
Camera* camera = panel->camera;
QMatrix4x4 cameraViewM = Camera::getViewMatrix(camera,panel->width(),panel->height());
QMatrix4x4 cameraProjM = Camera::getProjMatrix(camera,panel->width(),panel->height());
QMatrix4x4 cameraProjViewM = cameraProjM * cameraViewM;
QMatrix4x4 objToWorld;
QGLShaderProgram* flatShader = panel->getFlatShader();
glLineWidth(_lineWidth);
flatShader->bind();
int objToWorldLoc = flatShader->attributeLocation("objToWorld");
flatShader->setUniformValue(objToWorldLoc, objToWorld);
int cameraPVLoc = flatShader->attributeLocation("cameraPV");
flatShader->setUniformValue(cameraPVLoc, cameraProjViewM);
int overrideStrengthLoc = flatShader->attributeLocation("overrideStrength");
flatShader->setUniformValue(overrideStrengthLoc, 0.0f);
cout << "Rendering" << endl;
drawSegments(flatShader);
//drawSegments.call
flatShader->release();
}
void LineRenderer::drawSegments(QGLShaderProgram* program)
{
int numSegments = _segments.size();
_segmentsVBO.bind();
int edgeLocation = program->attributeLocation("vertex");
program->setAttributeArray(edgeLocation, 0, 3, 0);
program->enableAttributeArray(edgeLocation);
_segmentColorsVBO.bind();
int colorLocation = program->attributeLocation("color");
program->setAttributeArray(colorLocation, 0, 3, 0);
program->enableAttributeArray(colorLocation);
glDrawArrays(GL_LINES, 0, 2*numSegments);
//program->disableAttributeArray(edgeLocation);
//program->disableAttributeArray(colorLocation);
}
struct MyVertex {
GLfloat x,y,z; // position
MyVertex() : x(0), y(0), z(0){};
MyVertex(GLfloat x, GLfloat y, GLfloat z)
: x(x), y(y), z(z) {};
};
struct MyColor {
GLfloat r,g,b; // color
MyColor() : r(0), g(0), b(0){};
MyColor(GLfloat r, GLfloat g, GLfloat b)
: r(r), g(g), b(b) {};
};
void LineRenderer::loadVBOs(PanelGL* panel)
{
int numSegments = _segments.size();
QVarLengthArray<MyVertex> vertices(numSegments*2);
QVarLengthArray<MyColor> colors(numSegments*2);
for (int i = 0; i < numSegments; i++) {
vertices[i*2+0] = MyVertex(_segments[i].p1.x(), _segments[i].p1.y(), _segments[i].p1.z());
vertices[i*2+1] = MyVertex(_segments[i].p2.x(), _segments[i].p2.y(), _segments[i].p2.z());
colors[i*2+0] = MyColor(_segments[i].r, _segments[i].g, _segments[i].b);
colors[i*2+1] = MyColor(_segments[i].r, _segments[i].g, _segments[i].b);
}
_segmentsVBO.bind();
_segmentsVBO.setUsagePattern(QGLBuffer::DynamicDraw);
_segmentsVBO.allocate(vertices.data(), 3*2*numSegments*sizeof(float));
_segmentColorsVBO.bind();
_segmentColorsVBO.setUsagePattern(QGLBuffer::DynamicDraw);
_segmentsVBO.allocate(colors.data(), 3*2*numSegments*sizeof(float));
}
And this site shows the actual mapping it’s doing to GL functions: (here)
Am I off somewhere in my alignment?