Example #1
0
void GLWidget::setupVertexAttribs()
{
    m_vertexBuffer.bind();
    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();

    f->glEnableVertexAttribArray(0);
    f->glVertexAttribPointer(
                0,              //index
                3,              //size
                GL_FLOAT,       //type
                GL_FALSE,       //normalized?
                0,              //stride
                0 );            //array buffer offset

    m_vertexBuffer.release();
    m_normalBuffer.bind();

    f->glEnableVertexAttribArray(1);
    f->glVertexAttribPointer(
                1,              //index
                3,              //size
                GL_FLOAT,       //type
                GL_FALSE,       //normalized?
                0,              //stride
                0 );            //array buffer offset


    m_normalBuffer.release();
}
Example #2
0
void Mesh::create()
{
    if(isCreated()) { return; }

    m_vao.create();
    m_vao.bind();

    m_vbo.create();
    m_vbo.bind();
    m_vbo.allocate(m_data.constData(), m_data.size() * sizeof(MeshVertex));

    m_vbo.bind();
    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
    f->glEnableVertexAttribArray(0);
    f->glEnableVertexAttribArray(1);
    f->glEnableVertexAttribArray(2);
    f->glEnableVertexAttribArray(3);
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), 0);
    f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
    f->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
    f->glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void *>(8 * sizeof(GLfloat)));
    m_vbo.release();

    m_vao.release();

    m_isCreated = true;
}
Example #3
0
void GlCube::initGL()
{
    m_vao_constraints.create();
    m_vbo_constraints.create();
    m_ibo_constraints.create();

    m_vao_constraints.bind(); CE();

    m_vbo_constraints.bind();  CE();
    m_vbo_constraints.setUsagePattern(QOpenGLBuffer::UsagePattern::StaticDraw);  CE();

    m_ibo_constraints.bind(); CE();
    m_ibo_constraints.setUsagePattern(QOpenGLBuffer::UsagePattern::StaticDraw);  CE();

    QOpenGLFunctions * f = QOpenGLContext::currentContext()->functions();
    GLsizei stride = sizeof(GLfloat) * 7;
    f->glEnableVertexAttribArray(0); CE();
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)(0)); CE();
    f->glEnableVertexAttribArray(1); CE();
    f->glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, stride, (void*)(sizeof(GLfloat) * 3)); CE();

    m_vao_constraints.release(); CE();
    m_vbo_constraints.release(); CE();
    m_ibo_constraints.release(); CE();

    fillBuffers();
}
Example #4
0
//clockwise 4 vertex uv TL TR BL BR
void CubeFace::create(float x1,float y1, float x2,float y2,float x3,float y3,float x4,float y4)
{
    QOpenGLFunctions f = QOpenGLFunctions(QOpenGLContext::currentContext());

    //creat the vertexes
    float CubeFaceVertices[] =
    {
        // Positions // Texture Coords

         1,-1,  0,  x3, y3,
         1, 1,  0,  x2, y2,
        -1, 1,  0,  x1, y1,

        -1, 1,  0,  x1, y1,
        -1,-1,  0,  x4, y4,
         1,-1,  0,  x3, y3,

    };
    m_buffer->bind();
    m_buffer->allocate(CubeFaceVertices, sizeof(CubeFaceVertices));
    m_vao->bind();
    f.glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    f.glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    f.glEnableVertexAttribArray(0);
    f.glEnableVertexAttribArray(1);
    m_vao->release();
    m_buffer->release();
}
Example #5
0
void CompasWidget::setupVertexAttribs(){
	m_logoVbo.bind();
	QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
	f->glEnableVertexAttribArray(0);
	f->glEnableVertexAttribArray(1);
	f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
	f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
	m_logoVbo.release();
}
Example #6
0
void CompasWidget::setupVertexAttribs2(){
	m_vbo2->bind();
	m_program2->enableAttributeArray(0);
	m_program2->enableAttributeArray(1);
	QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
	f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (const void *)(36 * 3 * sizeof(GLfloat)));
	m_vbo2->release();
}
void GLRasterTexture::setupVertexAttribs()
{
    m_vbo.bind();
    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
    f->glEnableVertexAttribArray(0);
    f->glEnableVertexAttribArray(1);
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat),
                             0);
    f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, DATA_DIMENSIONS * sizeof(GLfloat),
                             reinterpret_cast<void *>(3 * sizeof(GLfloat)));
    m_vbo.release();
}
Example #8
0
void CGLWidget::setupVertexAttribs()
{
    m_vbo.bind();
    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
    f->glEnableVertexAttribArray(0);
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0,  (void*)0);
    m_vbo.release();

    m_uvBuff.bind();
    f->glEnableVertexAttribArray(1);
    f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
    m_uvBuff.release();
}
Example #9
0
void ViewportWidget::SetupVertexAttributes(QOpenGLBuffer* vbo)
{
	if (!vbo)
		return;

	vbo->bind();
	QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
	f->glEnableVertexAttribArray(0);
	f->glEnableVertexAttribArray(1);
	f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0);
	f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
	vbo->release();
}
void DrawableTerrain::initGL()
{
    m_vao_constraints.create(); CE();
    m_vbo_constraints.create(); CE();
    m_ibo_constraints.create(); CE();

    m_vao_constraints.bind(); CE();

    m_vbo_constraints.bind();  CE();
    m_vbo_constraints.setUsagePattern(QOpenGLBuffer::UsagePattern::StaticDraw);  CE();

    m_ibo_constraints.bind(); CE();
    m_ibo_constraints.setUsagePattern(QOpenGLBuffer::UsagePattern::StaticDraw);  CE();

    QOpenGLFunctions * f = QOpenGLContext::currentContext()->functions();
    f->glEnableVertexAttribArray(0); CE();
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)(0)); CE();
    // Texture coordinate
//    f->glEnableVertexAttribArray(1); CE();
//    const int sz = 3*sizeof(GLfloat);
//    f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void*)(sz)); CE();

    m_vao_constraints.release(); CE();
    m_vbo_constraints.release(); CE();
    m_ibo_constraints.release(); CE();

    fillBuffers();
}
void ScreenAlignedQuad::draw(QOpenGLFunctions &gl)
{
    m_vertices->bind();
    gl.glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 0, nullptr);
    gl.glEnableVertexAttribArray(0);
	gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
Example #12
0
void GLShaderTextured::draw(unsigned int mode, const QMatrix4x4& transformMatrix, GLfloat *textureCoords, GLfloat *vertices, int nbVertices)
{
	if (!m_texture) {
		qDebug("GLShaderTextured::draw: no texture defined. Doing nothing");
		return;
	}

	QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
	m_program->bind();
	m_program->setUniformValue(m_matrixLoc, transformMatrix);
	m_texture->bind();
	m_program->setUniformValue(m_textureLoc, 0); // Use texture unit 0 which magically contains our texture
	f->glEnableVertexAttribArray(0); // vertex
	f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
	f->glEnableVertexAttribArray(1); // texture coordinates
	f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
	f->glDrawArrays(mode, 0, nbVertices);
	f->glDisableVertexAttribArray(0);
	m_program->release();
}
Example #13
0
void Grid::initVertexArray()
{
    vao.create();
    vao.bind();
	vbo.bind();
	QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
	f->glEnableVertexAttribArray(0);
	f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	vbo.release();
	vao.release();
}
Example #14
0
void OpenGLVideo::render(const QRectF &target, const QRectF& roi, const QMatrix4x4& transform)
{
    DPTR_D(OpenGLVideo);
    Q_ASSERT(d.manager);
    VideoShader *shader = d.manager->prepareMaterial(d.material);
    shader->update(d.material);
    shader->program()->setUniformValue(shader->matrixLocation(), transform*d.matrix);
    // uniform end. attribute begin
    if (target.isValid())
        d.geometry.setRect(target, d.material->normalizedROI(roi));
    else
        d.geometry.setRect(d.rect, d.material->normalizedROI(roi));

    // normalize?
#if 1
    shader->program()->setAttributeArray(0, GL_FLOAT, d.geometry.data(0), 2, d.geometry.stride());
    shader->program()->setAttributeArray(1, GL_FLOAT, d.geometry.data(1), 2, d.geometry.stride());
#else
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
    static QGLFunctions *glf = new QGLFunctions();
    glf->initializeGLFunctions();
#else
    QOpenGLFunctions *glf = QOpenGLContext::currentContext()->functions();
#endif
    glf->glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, d.geometry.stride(), d.geometry.data(0));
    glf->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, d.geometry.stride(), d.geometry.data(1));
#endif
    char const *const *attr = shader->attributeNames();
    for (int i = 0; attr[i]; ++i) {
        shader->program()->enableAttributeArray(i); //TODO: in setActiveShader
    }

   glDrawArrays(d.geometry.mode(), 0, d.geometry.vertexCount());

   // d.shader->program()->release(); //glUseProgram(0)
   for (int i = 0; attr[i]; ++i) {
       shader->program()->disableAttributeArray(i); //TODO: in setActiveShader
   }

   d.material->unbind();
}
QOpenGLBuffer* GLImageProcessor::buildQuadTextured() const 
{
	QOpenGLBuffer* lpvbo = new QOpenGLBuffer();

	typedef struct
	{
		float xyz[3];
		float uv[2];
	} VertexUV;

	VertexUV Vertices[] =
	{
		{ { -1.0f, -1.0f, 0.0f }, { 0.0f, 0.0f } },
		{ { -1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f } },
		{ { 1.0f, 1.0f, 0.0f }, { 1.0f, 1.0f } },
		{ { 1.0f, -1.0f, 0.0f }, { 1.0f, 0.0f } }
	};

	const size_t BufferSize = sizeof(Vertices);
	const size_t VertexSize = sizeof(Vertices[0]);
	const size_t UVOffset = sizeof(Vertices[0].xyz);

	// Setup our vertex buffer object.
	lpvbo->create();
	lpvbo->bind();
	lpvbo->allocate(Vertices, BufferSize);

	lpvbo->bind();

	QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
	f->glEnableVertexAttribArray(0);
	f->glEnableVertexAttribArray(1);
	f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, VertexSize, 0);
	f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, VertexSize, reinterpret_cast<void *>(UVOffset));

	lpvbo->release();

	return lpvbo;
}
Example #16
0
void GlCircle::initGL()
{
    m_vao_constraints.create();
    m_vbo_constraints.create();
    m_ibo_constraints.create();

    m_vao_constraints.bind(); CE();

    m_vbo_constraints.bind();  CE();
    m_vbo_constraints.setUsagePattern(QOpenGLBuffer::UsagePattern::StaticDraw);  CE();

    m_ibo_constraints.bind(); CE();
    m_ibo_constraints.setUsagePattern(QOpenGLBuffer::UsagePattern::StaticDraw);  CE();

    QOpenGLFunctions * f = QOpenGLContext::currentContext()->functions();
    f->glEnableVertexAttribArray(0);
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)(0));

    m_vao_constraints.release(); CE();
    m_vbo_constraints.release(); CE();
    m_ibo_constraints.release(); CE();

    fillBuffers();
}
Example #17
0
void QtViewRenderer::initialize()
{
	QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();

	unsigned char* pixels;
	int width, height;
	m_atlas->getTexDataAsRGBA32(&pixels, &width, &height);
	QImage img(pixels, width, height, QImage::Format::Format_ARGB32);
	m_fontTexture = std::make_unique<QOpenGLTexture>(img);

	m_atlas->setTexID(m_fontTexture->textureId());

	const GLchar* vertex_shader =
		"#version 330\n"
		"uniform mat4 ProjMtx;\n"
		"layout (location = 0) in vec2 Position;\n"
		"layout (location = 1) in vec2 UV;\n"
		"layout (location = 2) in vec4 Color;\n"
		"out vec2 Frag_UV;\n"
		"out vec4 Frag_Color;\n"
		"void main()\n"
		"{\n"
		"	Frag_UV = UV;\n"
		"	Frag_Color = Color;\n"
		"	gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
		"}\n";

	const GLchar* fragment_shader =
		"#version 330\n"
		"uniform sampler2D Texture;\n"
		"in vec2 Frag_UV;\n"
		"in vec4 Frag_Color;\n"
		"out vec4 Out_Color;\n"
		"void main()\n"
		"{\n"
		"	Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
		"}\n";

	m_shader = std::make_unique<QOpenGLShaderProgram>();
	m_shader->addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertex_shader);
	m_shader->addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragment_shader);
	m_shader->link();

	m_locationTex = m_shader->uniformLocation("Texture");
	m_locationProjMtx = m_shader->uniformLocation("ProjMtx");

	m_VAO = std::make_unique<QOpenGLVertexArrayObject>();
	m_VAO->create();
	m_VAO->bind();

	m_VBO = std::make_unique<QOpenGLBuffer>(QOpenGLBuffer::VertexBuffer);
	m_VBO->create();
	m_VBO->setUsagePattern(QOpenGLBuffer::StreamDraw);
	m_VBO->bind();
	
	f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(DrawList::DrawVert), (GLvoid*)offsetof(DrawList::DrawVert, pos));
	f->glEnableVertexAttribArray(0);

	f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(DrawList::DrawVert), (GLvoid*)offsetof(DrawList::DrawVert, uv));
	f->glEnableVertexAttribArray(1);

	f->glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DrawList::DrawVert), (GLvoid*)offsetof(DrawList::DrawVert, col));
	f->glEnableVertexAttribArray(2);
	
	m_VBO->release();
	
	m_EBO = std::make_unique<QOpenGLBuffer>(QOpenGLBuffer::IndexBuffer);
	m_EBO->create();
	m_EBO->setUsagePattern(QOpenGLBuffer::StreamDraw);
	
	m_VAO->release();
}
Example #18
0
void QSGDistanceFieldGlyphCache::saveTexture(GLuint textureId, int width, int height) const
{
    QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions();

    GLuint fboId;
    functions->glGenFramebuffers(1, &fboId);

    GLuint tmpTexture = 0;
    functions->glGenTextures(1, &tmpTexture);
    functions->glBindTexture(GL_TEXTURE_2D, tmpTexture);
    functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    functions->glBindTexture(GL_TEXTURE_2D, 0);

    functions->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
    functions->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
                                      tmpTexture, 0);

    functions->glActiveTexture(GL_TEXTURE0);
    functions->glBindTexture(GL_TEXTURE_2D, textureId);

    functions->glDisable(GL_STENCIL_TEST);
    functions->glDisable(GL_DEPTH_TEST);
    functions->glDisable(GL_SCISSOR_TEST);
    functions->glDisable(GL_BLEND);

    GLfloat textureCoordinateArray[8];
    textureCoordinateArray[0] = 0.0f;
    textureCoordinateArray[1] = 0.0f;
    textureCoordinateArray[2] = 1.0f;
    textureCoordinateArray[3] = 0.0f;
    textureCoordinateArray[4] = 1.0f;
    textureCoordinateArray[5] = 1.0f;
    textureCoordinateArray[6] = 0.0f;
    textureCoordinateArray[7] = 1.0f;

    GLfloat vertexCoordinateArray[8];
    vertexCoordinateArray[0] = -1.0f;
    vertexCoordinateArray[1] = -1.0f;
    vertexCoordinateArray[2] =  1.0f;
    vertexCoordinateArray[3] = -1.0f;
    vertexCoordinateArray[4] =  1.0f;
    vertexCoordinateArray[5] =  1.0f;
    vertexCoordinateArray[6] = -1.0f;
    vertexCoordinateArray[7] =  1.0f;

    functions->glViewport(0, 0, width, height);
    functions->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
    functions->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);

    {
        static const char *vertexShaderSource =
                "attribute vec4      vertexCoordsArray; \n"
                "attribute vec2      textureCoordArray; \n"
                "varying   vec2      textureCoords;     \n"
                "void main(void) \n"
                "{ \n"
                "    gl_Position = vertexCoordsArray;   \n"
                "    textureCoords = textureCoordArray; \n"
                "} \n";

        static const char *fragmentShaderSource =
                "varying   vec2      textureCoords; \n"
                "uniform   sampler2D         texture;       \n"
                "void main() \n"
                "{ \n"
                "    gl_FragColor = texture2D(texture, textureCoords); \n"
                "} \n";

        GLuint vertexShader = functions->glCreateShader(GL_VERTEX_SHADER);
        GLuint fragmentShader = functions->glCreateShader(GL_FRAGMENT_SHADER);

        if (vertexShader == 0 || fragmentShader == 0) {
            GLenum error = functions->glGetError();
            qWarning("QSGDistanceFieldGlyphCache::saveTexture: Failed to create shaders. (GL error: %x)",
                     error);
            return;
        }

        functions->glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        functions->glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        functions->glCompileShader(vertexShader);

        GLint len = 1;
        functions->glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &len);

        char infoLog[2048];
        functions->glGetShaderInfoLog(vertexShader, 2048, NULL, infoLog);
        if (qstrlen(infoLog) > 0)
            qWarning("Problems compiling vertex shader:\n %s", infoLog);

        functions->glCompileShader(fragmentShader);
        functions->glGetShaderInfoLog(fragmentShader, 2048, NULL, infoLog);
        if (qstrlen(infoLog) > 0)
            qWarning("Problems compiling fragment shader:\n %s", infoLog);

        GLuint shaderProgram = functions->glCreateProgram();
        functions->glAttachShader(shaderProgram, vertexShader);
        functions->glAttachShader(shaderProgram, fragmentShader);

        functions->glBindAttribLocation(shaderProgram, 0, "vertexCoordsArray");
        functions->glBindAttribLocation(shaderProgram, 1, "textureCoordArray");

        functions->glLinkProgram(shaderProgram);
        functions->glGetProgramInfoLog(shaderProgram, 2048, NULL, infoLog);
        if (qstrlen(infoLog) > 0)
            qWarning("Problems linking shaders:\n %s", infoLog);

        functions->glUseProgram(shaderProgram);
        functions->glEnableVertexAttribArray(0);
        functions->glEnableVertexAttribArray(1);

        int textureUniformLocation = functions->glGetUniformLocation(shaderProgram, "texture");
        functions->glUniform1i(textureUniformLocation, 0);
    }

    functions->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    {
        GLenum error = functions->glGetError();
        if (error != GL_NO_ERROR)
            qWarning("glDrawArrays reported error 0x%x", error);
    }

    uchar *data = new uchar[width * height * 4];

    functions->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);

    QImage image(data, width, height, QImage::Format_ARGB32);

    QByteArray fileName = m_referenceFont.familyName().toLatin1() + '_' + QByteArray::number(textureId);
    fileName = fileName.replace('/', '_').replace(' ', '_') + ".png";

    image.save(QString::fromLocal8Bit(fileName));

    {
        GLenum error = functions->glGetError();
        if (error != GL_NO_ERROR)
            qWarning("glReadPixels reported error 0x%x", error);
    }

    functions->glDisableVertexAttribArray(0);
    functions->glDisableVertexAttribArray(1);

    functions->glDeleteFramebuffers(1, &fboId);
    functions->glDeleteTextures(1, &tmpTexture);

    delete[] data;
}