Crash at glEnableVertexAttribArray

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?