QPixmap runs over my glScissor(...) setting

101 Views Asked by At

I apologize if this isn't exact. I'm doing the best I can to copy code by hand from one computer to another, and the destination computer doesn't have a compiler (don't ask).

Header file

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H

#include <qopenglwidget.h>

class MyOpenGlWidget : public QOpenGLWidget
{
    Q_OBJECT

public:
    explicit MyOpenGlWidget(QWidget *parent = 0, Qt::WindowFlags f = Qt::WindowFlags());
    virtual ~MyOpenGlWidget();

protected:
    // these are supposed to be overridden, so use the "override" keyword to compiler check yourself
    virtual void initializeGL() override;
    virtual void resizeGL(int w, int h) override;
    virtual void paintGL() override;
private:
    QPixmap *_foregroundPixmap;
}

#endif 

Source file

QOpenGLFunctions_2_1 *f = 0;


MyOpenGlWidget::MyOpenGlWidget(QWidget *parent, Qt::WindowFlags f) :
    QOpenGLWidget(parent, f)
{
    _foregroundPixmap = 0;
    QPixmap *p = new QPixmap("beveled_texture.tiff");
    if (!p->isNull())
    {
        _foregroundPixmap = p;
    }
}

MyOpenGlWidget::~MyOpenGlWidget()
{
    delete _foregroundPixmap;
}

void MyOpenGlWidget::initializeGL()
{
    // getting a deprecated set of functions because such is my work environment 
    // Note: Also, QOpenGLWidget doesn't support these natively.
    f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_2_1>();

    f->glClearColor(0.0f, 1.0f, 0.0f, 1.0f);    // clearing to green
    f->glEnable(GL_DEPTH_TEST);
    f->glEnable(GL_CULL_FACE);  // implicitly culling front face
    f->glEnable(GL_SCISSOR_TEST);

    // it is either copy the matrix and viewport code from resizeGL or just call the method
    this->resizeGL(this->width(), this->height());
}

void MyOpenGlWidget::resizeGL(int w, int h)
{
    // make the viewport square
    int sideLen = qMin(w, h);
    int x = (w - side) / 2;
    int y = (h - side) / 2;

    // the widget is 400x400, so this random demonstration square will show up inside it
    f->glViewport(50, 50, 100, 100);
    f->glMatrixMode(GL_PROJECTION);
    f->glLoadIdentity();
    f->glOrtho(-2.0f, +2.0f, -2.0f, +2.0f, 1.0f, 15.0f);    // magic numbers left over from a demo
    f->glMatrixMode(GL_MODELVIEW);

    // queue up a paint event
    // Note: QGLWidget used updateGL(), but QOpenGLWidget uses update().
    this->update();
}

void MyOpenGlWidget::paintGL()
{
    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // I want to draw a texture with beveled edges the size of this widget, so I can't 
    // have the background clearing all the way to the edges
    f->glScissor(50, 50, 200, 200);     // more magic numbers just for demonstration

    // clears to green in just scissored area (unless QPainter is created)
    f->glClearColor(0.0f, 1.0f, 0.0f, 1.0f);

    // loading identity matrix, doing f->glTranslatef(...) and f->glRotatef(...)

    // pixmap loaded earlier in another function
    if (_foregroundPixmap != 0)
    {
        // QPixmap apparently draws such that culling the back face will cull the entire 
        // pixmap, so have to switch culling for duration of pixmap drawing
        f->glCullFace(GL_FRONT);

        QPainter(this);
        painter.drawPixmap(0, 0, _foregroundPixmap->scaled(this->size()));

        // done, so switch back to culling the front face
        f->glCullFace(GL_BACK);
    }
QOpenGLFunctions_2_1 *f = 0;

void MyOpenGlWidget::initializeGL()
{
    // getting a deprecated set of functions because such is my work environment 
    // Note: Also, QOpenGLWidget doesn't support these natively.
    f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_2_1>();

    f->glClearColor(0.0f, 1.0f, 0.0f, 1.0f);    // clearing to green
    f->glEnable(GL_DEPTH_TEST);
    f->glEnable(GL_CULL_FACE);  // implicitly culling front face
    f->glEnable(GL_SCISSOR_TEST);

    // it is either copy the matrix and viewport code from resizeGL or just call it directly
    this->resizeGL(this->width(), this->height());
}

void MyOpenGlWidget::resizeGL(int w, int h)
{
    // make the viewport square
    int sideLen = qMin(w, h);
    int x = (w - side) / 2;
    int y = (h - side) / 2;

    // the widget is 400x400, so this random demonstration square will show up inside it
    f->glViewport(50, 50, 100, 100);
    f->glMatrixMode(GL_PROJECTION);
    f->glLoadIdentity();
    f->glOrtho(-2.0f, +2.0f, -2.0f, +2.0f, 1.0f, 15.0f);    // magic numbers left over from a demo
    f->glMatrixMode(GL_MODELVIEW);

    // queue up a paint event
    // Note: QGLWidget used updateGL(), but QOpenGLWidget uses update().
    this->update();
}

void MyOpenGlWidget::paintGL()
{
    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // I want to draw a texture with beveled edges the size of this widget, so I can't 
    // have the background clearing all the way to the edges
    f->glScissor(50, 50, 200, 200);     // more magic numbers just for demonstration

    // clears to green in just scissored area (unless QPainter is created)
    f->glClearColor(0.0f, 1.0f, 0.0f, 1.0f);

    // loading identity matrix, doing f->glTranslatef(...) and f->glRotatef(...), drawing triangles

    // done drawing, so now draw the beveled foreground
    if (_foregroundPixmap != 0)
    {
        // QPixmap apparently draws such that culling the back face will cull the entire 
        // pixmap, so have to switch culling for duration of pixmap drawing
        f->glCullFace(GL_FRONT);

        QPainter(this);
        painter.drawPixmap(0, 0, _foregroundPixmap->scaled(this->size()));

        // done, so switch back to culling the front face
        f->glCullFace(GL_BACK);
    }
}

The problem is this code from paintGL():

QPainter(this);

As soon as a QPainter object is created, the glScissor(...) call that I made earlier in the function is overrun and some kind of glClearColor(...) call is made (possibly from QPainter's constructor) that clears the entire viewport to the background color that I set just after glScissor(...). Then the pixmap draws my beveled texture just fine.

I don't want QPainter to overrun my scissoring.

The closest I got to an explanation was two QPainter methods, beginNativePainting() and endNativePainting(). According to the documentation, scissor testing is disabled between these two, but in their example they re-enable it. I tried using this "native painting" code, but I couldn't stop QPainter's mere existence from ignoring GL's scissoring and clearing my entire viewport.

Why is this happening and how do I stop this?

Note: This work computer has network policies to prevent me from going to entertainment sites like imgur to upload "what I want" and "what I get" pictures, so I have to make due with text.

1

There are 1 best solutions below

0
On

Why is this happening

The OpenGL context is a shared resource and you have to share it with other players.

and how do I stop this?

You can't. Just do the proper thing and set viewport, scissor rectangle and all the other drawing related state at the right moment: Right before you are going to draw something that relies on these settings. Don't set them aeons (in computer terms) before, somewhere in some "initialization" or a reshape handler. And be expected that in drawing code any function you call that makes use of OpenGL will leave some garbage behind.