1

I am try to do some offscreen rendering jobs in Qt5.3 and I want to use QOpenGLFramebufferObject::toImage to output each pictures(I want to output a few pictures when render() draws different things).

Following the instructions of this, I succeeded in offscreen rendering my first pic and outputing it. So to future on, I write an example as the following code and here is a package in Google. I can get the first fbo content(and its output file correctly, but from the second time, the fbo was not re-render() and it always output the same pictures). So I want to know what should I do after I finish one time offscreen render to make sure the next time would be correct in qt? Or is there anyone could tell me how to set animation correctly in QOffscreenSurface?

qtestofffscreen.h:

#ifndef QTESTOFFSCREEN_H
#define QTESTOFFSCREEN_H

#include <QOffscreenSurface>
#include <QWindow>
#include <QtGui/QOpenGLFunctions_3_3_Core>
#include <QImage>
#include <QGLFramebufferObject>
#include <QOpenGLPaintDevice>
#include <QOpenGLFunctions>
#include <QMutex>
#include <QMutexLocker>

class QTestOffScreen : public QOffscreenSurface,
                   protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT

public:
explicit QTestOffScreen(
        QScreen* targetScreen = nullptr,
        const QSize& size = QSize (1, 1));
~QTestOffScreen();

virtual void render();
virtual void initialize();
void renderNow();
void setAnimating(bool animating);

bool event(QEvent *) override;

void renderLater();
int  counts;

private:
QGLFramebufferObject *fbo;
bool m_animating;
bool m_update_pending;

QOpenGLContext *m_context;
QOpenGLPaintDevice *m_device;

QSize m_size;

QMutex mutex;

signals:
void doneImg(int index);
};

#endif // QTESTOFFSCREEN_H

qtestofffscreen.cpp:

#include "qtestoffscreen.h"
#include <QTime>
#include <QDebug>
#include <QCoreApplication>
#include <QOpenGLFramebufferObject>

QTestOffScreen::QTestOffScreen(QScreen *targetScreen,
                               const QSize &size):
    QOffscreenSurface(targetScreen),
    m_size(size),
    fbo(Q_NULLPTR),
    m_context(Q_NULLPTR),
    m_device(Q_NULLPTR),
    counts(100)
{
    requestedFormat().setVersion(3,3);
    setFormat(requestedFormat());
    create();

    m_context = new QOpenGLContext(this);
    m_context->setFormat(format());

    if (m_context->create())
    {
        m_context->makeCurrent(this);
        m_context->functions()->initializeOpenGLFunctions();
    }else
    {
        delete m_context;
        m_context = Q_NULLPTR;
        throw ("Still wrong here");
    }

    //To make sure m_context was initialized
    //in first time entering renderNow()
    delete m_context;
    m_context = Q_NULLPTR;
}

QTestOffScreen::~QTestOffScreen()
{
    delete m_context;
    delete m_device;
    if (fbo)
        delete fbo;
}

void QTestOffScreen::render()
{
    glClearColor(0.0f,0.0f,0.0f,1.0f);
    glClear(GL_COLOR_BUFFER_BIT
          | GL_DEPTH_BUFFER_BIT
          | GL_STENCIL_BUFFER_BIT
          | GL_TEXTURE_BIT);

    glViewport(0,0,1920,1080);
    glOrtho(0,1920,0,1080,0,1);

    glColor3f(1.0,0.0,0.0);

    float tmp = float(qrand()%1000);
    float count = (float)counts * 10.0f;

    glLineWidth(3.0f);
    glBegin(GL_LINE_LOOP);
        glVertex2f(count ,count );
        glVertex2f(count + 100,count);
        glVertex2f(count + 50,count + 100);
    glEnd();

    qDebug()<<QString("current tmp is %1").arg(count);

}

void QTestOffScreen::initialize()
{

    if (!fbo)
    {
        fbo = new QGLFramebufferObject(1920,1080,GL_TEXTURE_2D);
    }

    fbo->bind();
}

void QTestOffScreen::renderNow()
{
    bool needsInitialize = false;
    if (!m_context)
    {
        m_context = new QOpenGLContext(this);
        m_context->setFormat(requestedFormat());
        m_context->create();

        if (m_context->isValid())
        {
            qDebug()<<"Right Here when creating m_context in renderNow";
        }

        needsInitialize = true;
    }

    if ( !m_context->makeCurrent(this) )
    {
        qDebug()<<"This fails in makeCurrent";
    }

    if (needsInitialize)
    {
        initializeOpenGLFunctions();
        initialize();
    }

        render();

        qDebug()<<counts;
        counts--;
        fbo->toImage().save(QString::number(counts) + QString(".png"));


    m_context->doneCurrent();

    if (counts >= 0)
    {
        m_update_pending = false;
        emit doneImg(counts);
    }
}

void QTestOffScreen::setAnimating(bool animating)
{
    m_animating = animating;

    m_update_pending = false;

    if (m_animating)
        renderLater();
}

bool QTestOffScreen::event(QEvent *event)
{
    switch (event->type())
    {
    case QEvent::UpdateRequest:
        m_update_pending = true;
        renderNow();
        return true;
    default:
        return QOffscreenSurface::event(event);
    }
}

void QTestOffScreen::renderLater()
{
    if (!m_update_pending)
    {
        m_update_pending = true;
        QCoreApplication::postEvent(this,new QEvent(QEvent::UpdateRequest));
    }
}

void QTestOffScreen::generateImg(QImage *tmp_img_pointer)
{
    GLint viewPort[4]={0};
    glGetIntegerv(GL_VIEWPORT,viewPort);

    int win_width,win_height;
    win_width = 1920;
    win_height = 1080;

    GLubyte *colorArr=new GLubyte[win_width*win_height*3];

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glReadBuffer (GL_FRONT);

    int tmp_x,tmp_y;
    tmp_x = 0;
    tmp_y = 0;

    glReadPixels(tmp_x,tmp_y,win_width,win_height,
                 GL_RGB,GL_UNSIGNED_BYTE,colorArr);

    int winrows = tmp_img_pointer->height();
    int wincols = tmp_img_pointer->width ();


    for(int ii=0; ii < winrows * wincols * 3; ii ++)
    {
        if((colorArr[ii] <0)|(colorArr[ii] >255))
        { colorArr[ii] = 255; }
    }


    for(int j=0;j<winrows;j++)
        for(int i=0;i<wincols;i++)
        {
            int index=(j*wincols+i)*3;
            QRgb value=qRgb(colorArr[index+2],
                            colorArr[index+1],
                            colorArr[index  ]);
            tmp_img_pointer->setPixel(i,winrows-j-1,value);
        }
    delete colorArr;
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "qtestoffscreen.h"
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QTestOffScreen *scr;

private slots:
    void ReceiveCurrentIndex(int);
};

#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QSurfaceFormat format;
    format.setSamples(1);
    format.setRenderableType(QSurfaceFormat::OpenGL);

    scr = new QTestOffScreen();

    connect(scr,SIGNAL(doneImg(int)),this,SLOT(ReceiveCurrentIndex(int)));

    scr->setFormat(format);

    scr->setAnimating(true);//Start rendering animation here.

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::ReceiveCurrentIndex(int)
{
    Sleep(100);

    scr->renderLater();
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
MartinChan
  • 11
  • 1
  • 4
  • You need to bind the `fbo` before rendering and release it before you grab the image. Currently you only bind it once (through `initialize`) . – Botje Nov 08 '17 at 10:58
  • @Botje Thanks firstly and I changed my code like [this](https://drive.google.com/file/d/1FRGbtjR6q6SQGvq614WIgaATNCNz9sSX/view?usp=sharing) but it didn't work ,I believe it still has some problems in QOpenGL context setting stuffs. – MartinChan Nov 09 '17 at 03:07

0 Answers0