I have a QOpenGLWidget class:
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLFunctions_4_3_Compatibility>
...
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
class GLWidget : public QOpenGLWidget, protected
QOpenGLFunctions_4_3_Compatibility
{
Q_OBJECT
public:
GLWidget(QWidget *parent = 0);
~GLWidget();
...
Inside initializeGL() I have calls to initialize shaders and buffers, and so on:
void GLWidget::initializeGL()
{
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);
initializeOpenGLFunctions();
QSurfaceFormat format;
format.setMajorVersion( 4 );
format.setMinorVersion( 3 );
format.setProfile( QSurfaceFormat::CompatibilityProfile );
context()->setFormat(format);
//glClearColor(0.8f, 0.9f, 1.0f, m_transparent ? 0 : 1);
glClearColor(0.0, 0.0, 0.0, 1.0);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
//LOAD OBJECTS
makeCurrent();
loadObjects();
//SHADER INIT (SIMPLE)
simple_shader = new QOpenGLShaderProgram;
simple_shader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert");
simple_shader->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/simple.frag");
simple_shader->bindAttributeLocation("vertex", 0);
simple_shader->link();
simple_shader->bind();
simple_proj_matrix_loc = simple_shader->uniformLocation("projMatrix");
simple_mv_matrix_loc = simple_shader->uniformLocation("mvMatrix");
simple_tex_loc = simple_shader->uniformLocation("texture");
simple_shader->release();
//BUFFER INIT (SIMPLE)
simple_vao.create();
simple_vao.bind();
simple_vbo.create();
simple_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
simple_vbo.bind();
simple_vbo.allocate(VertexPosUvData.constData(), VertexPosUvData.count() * sizeof(VertexPosUv));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexPosUv), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexPosUv), (void*)12);
simple_vbo.release();
simple_vao.release();
//--------------------------
My question is:
As this class is getting more complex with more shaders and buffers I need to organize everything into some better form. What is the best way to implement some sort of shader/buffer manager class so the functionality will be the same as now but in a different file. The problem is ofc with using opengl functions and sharing context.
Inside ::initializeGL() I want to have something like:
shader_manager.init_simple_shader();
shader_manager.init_simple_buffer();
Inside shader manager something like this:
void ShaderManager::init_simple_shader()
{
simple_vao.create();
simple_vao.bind();
simple_vbo.create();
simple_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
simple_vbo.bind();
... and so on with opengl functions that work exactly like in the parent class.
Related
I started using Qt5 a little while ago and I don't know how to set the position of my drawing in my window.
I have a Drawing class which is a QWidget and which contains my paintEvent() function and other functions; and a MainWindow class which contains some widgets. So in order to display my Qpainter, I have to include it in my layout, which is the main window layout, but the window doesn't adapt to the Qpainter at all; the dimensions of the buttons, sliders .. adapt so as to organize themselves and occupy all the space of my window, but they totally ignore my Qpainter and it partly disappears if I put at least 2 widgets.
Do you have any solutions to better manage the position of these elements?
main.cpp :
#include <QtGui>
#include <QApplication>
#include "mywidget.h"
int main( int argc, char **argv )
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
mywidget.h :
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QtGui>
#include <QWidget>
#include <QSlider>
#include <QScrollBar>
#include <QApplication>
#include <QGridLayout>
#include <QObject>
#include <QPoint>
#include <QLabel>
#include <QPolygon>
class Drawing : public QWidget
{
Q_OBJECT
public:
Drawing();
void paintEvent(QPaintEvent* e);
public slots:
void slide(int abscisse);
void rotate();
private:
QPoint o;
QPoint a;
QPoint b;
QPoint c;
QPoint d;
};
//--------------------------------------
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow();
private:
QSlider* m_slider1;
QSlider* m_slider2;
QGridLayout* m_layout;
Drawing* m_dessin;
};
#endif // MYWIDGET_H
mywidget.cpp :
#include "mywidget.h"
#include <iostream> //POUR LES TESTS
MainWindow::MainWindow() : QWidget()
{
setGeometry(330, 140, 840, 620);
m_slider1 = new QSlider(Qt::Horizontal, this);
m_slider1->setRange(150, 650);
m_slider1->setSliderPosition(400);
m_slider2 = new QSlider(Qt::Horizontal, this);
m_slider2->setSliderPosition(50);
m_layout = new QGridLayout;
m_layout->addWidget(new QLabel("Translation Horizontale"), 1, 0);
m_layout->addWidget(m_slider1, 2, 0);
m_layout->addWidget(new QLabel("Rotation"), 0, 1);
m_layout->addWidget(m_slider2, 1, 1);
m_dessin = new Drawing;
m_layout->addWidget(m_dessin, 0, 0);
setLayout(m_layout);
QObject::connect(m_slider1, SIGNAL(valueChanged(int)), m_dessin, SLOT(slide(int)));
QObject::connect(m_slider2, SIGNAL(valueChanged(int)), m_dessin, SLOT(rotate()));
}
//--------------------------------------------------------
Drawing::Drawing() : QWidget(), o(400, 150), a(o.x()-50 , o.y()-50), b(o.x()+50 , o.y()-50), c(o.x()+50 , o.y()+50), d(o.x()-50 , o.y()+50) {}
void Drawing::paintEvent(QPaintEvent *e) {
QPolygon poly;
poly << a << b << c << d;
QWidget::paintEvent(e); // effectue le comportement standard
QPainter painter(this); // construire
painter.setPen( QPen(Qt::white, 2) ); // personnaliser
painter.drawPolygon(poly); // dessiner
}
void Drawing::slide(int abscisse) {
if (a == QPoint(o.x()-50 , o.y()-50)) {
o.setX(abscisse);
a.setX(o.x()-50);
b.setX(o.x()+50);
c.setX(o.x()+50);
d.setX(o.x()-50);
}
else {
o.setX(abscisse);
a.setX(o.x());
b.setX(o.x()+75);
c.setX(o.x());
d.setX(o.x()-75);
}
update();
}
void Drawing::rotate() {
if (a == QPoint(o.x()-50 , o.y()-50)) {
a = QPoint(o.x() , o.y()+75);
b = QPoint(o.x()+75 , o.y());
c = QPoint(o.x() , o.y()-75);
d = QPoint(o.x()-75 , o.y());
}
else {
a = QPoint(o.x()-50 , o.y()-50);
b = QPoint(o.x()+50 , o.y()-50);
c = QPoint(o.x()+50 , o.y()+50);
d = QPoint(o.x()-50 , o.y()+50);
}
update();
}
Snapshots:
After having seen the snapshots of OP, I thought about what might been happen.
The layout of OP doesn't look that wrong.
I still believe that the layout plays only a minor role in OPs issue.
I tried to reproduce OPs issue with an even smaller MCVE of mine.
My testQGridLayout:
#include <QtWidgets>
class Drawing: public QFrame {
public:
Drawing(QWidget *pQParent = nullptr);
virtual ~Drawing() = default;
Drawing(const Drawing&) = delete;
Drawing& operator=(const Drawing&) = delete;
protected:
virtual void paintEvent(QPaintEvent *pQEvent) override;
};
Drawing::Drawing(QWidget* pQParent):
QFrame(pQParent)
{
setFrameStyle(Box | Plain);
}
void Drawing::paintEvent(QPaintEvent* pQEvent)
{
{ QPainter qPainter(this);
qPainter.drawText(QPoint(40, 40),
QString("Size: %1 x %2").arg(width()).arg(height()));
qPainter.setPen(Qt::red);
qPainter.drawRect(300, 100, 200, 200);
}
// call base class paint event to keep it working
QFrame::paintEvent(pQEvent);
}
class MainWindow: public QWidget {
public:
MainWindow(QWidget *pQParent = nullptr);
virtual ~MainWindow() = default;
MainWindow(const MainWindow&) = delete;
MainWindow& operator=(const MainWindow&) = delete;
private:
QGridLayout _qGrid;
Drawing _qDrawing;
QSlider _qSliderT;
QSlider _qSliderR;
};
MainWindow::MainWindow(QWidget *pQParent):
QWidget(pQParent),
_qSliderT(Qt::Horizontal),
_qSliderR(Qt::Horizontal)
{
resize(840, 620);
_qGrid.addWidget(&_qDrawing, 0, 0);
_qGrid.addWidget(new QLabel("Translation Horizontal"), 1, 0);
_qSliderT.setRange(150, 650);
_qSliderT.setSliderPosition(400);
_qGrid.addWidget(&_qSliderT, 2, 0);
_qGrid.addWidget(new QLabel("Rotation"), 1, 1);
_qSliderR.setSliderPosition(50);
_qGrid.addWidget(&_qSliderR, 2, 1);
setLayout(&_qGrid);
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
MainWindow qWinMain;
qWinMain.setWindowTitle("Test QGridLayout");
qWinMain.show();
// runtime loop
return app.exec();
}
Output:
Qt Version: 5.15.1
I made some changes to exclude what is a possible issue and what not.
I derived my Drawing from QFrame. Thus, it was easy to give it a visible border. As expected, my Drawing _qDrawing occupies only the space above the first slider (QSlider _qSliderT; in my case).
I added output of widget size to the Drawing::paintEvent() to see its size. Then I added the painting of a red rectangle. For that, I cared to cover a space which is partly inside the widget and partly below and right of it.
This is what I conclude:
As exposed in the OPs code, the layout should be the same.
OPs rectangle is always drawn at the same coordinates. Hence, it doesn't get visible until the Drawing grows large enough (with the main window).
The origin of the QPainter (i.e. QPoint(0, 0)) is the upper left corner of the widget. This can be changed by applying transformations but I couldn't see this in OPs code. (The effect of the sliders, I neglect for now.)
Though, there are still some things which are not clear to me:
The Drawing should clip the painting. Hence, I wonder, how OPs rectangle can appear over the rotate slider. Either, the OP used a span for the Drawing m_dessin, or the widget doesn't clip painting on the paint engine the OP uses. (The look is quite different than mine. Thus, it might be a different platform.)
The layout which can be seen in OPs snapshots doesn't match the exposed code. In OPs snapshot, the Drawing occupies all extra space resulting from growing the main window. This is only possible when QGridLayout::setRowStretch()/GridLayout::setColumnStretch() had been used (as recommended in my first comment). However, the exposed code doesn't contain them.
To check this out, I changed the layout in MainWindow::MainWindow():
MainWindow::MainWindow(QWidget *pQParent):
QWidget(pQParent),
_qSliderT(Qt::Horizontal),
_qSliderR(Qt::Horizontal)
{
resize(840, 620);
_qGrid.setRowStretch(0, 1);
_qGrid.setColumnStretch(0, 1);
_qGrid.addWidget(&_qDrawing, 0, 0, 1, 2);
_qGrid.addWidget(new QLabel("Translation Horizontal"), 1, 0);
_qSliderT.setRange(150, 650);
_qSliderT.setSliderPosition(400);
_qGrid.addWidget(&_qSliderT, 2, 0);
_qGrid.addWidget(new QLabel("Rotation"), 1, 1);
_qSliderR.setSliderPosition(50);
_qGrid.addWidget(&_qSliderR, 2, 1);
setLayout(&_qGrid);
}
Output:
Now, the layout seems to match the one of OPs snapshots.
Trying resize:
This looks exactly as it should:
the Drawing _qDrawing shrinks and grows with the main window size
the painting is clipped if the size of Drawing _qDrawing becomes too small to cover it.
Final Conclusion:
There is nothing wrong in OPs layout.
IMHO, OP is not yet fully clear about how coordinate systems apply in QPainter.
For this, I can warmly recommend an extra page of the Qt online doc., precisely dedicated to this topic:
Qt Doc.: Coordinate System
Continuation:
How to add a vertical slider:
class MainWindow: public QWidget {
public:
MainWindow(QWidget *pQParent = nullptr);
virtual ~MainWindow() = default;
MainWindow(const MainWindow&) = delete;
MainWindow& operator=(const MainWindow&) = delete;
private:
QGridLayout _qGrid;
Drawing _qDrawing;
QSlider _qSliderV;
QSlider _qSliderT;
QSlider _qSliderR;
};
MainWindow::MainWindow(QWidget *pQParent):
QWidget(pQParent),
_qSliderV(Qt::Vertical),
_qSliderT(Qt::Horizontal),
_qSliderR(Qt::Horizontal)
{
resize(840, 620);
_qGrid.setRowStretch(0, 1);
_qGrid.setColumnStretch(0, 1);
_qGrid.addWidget(&_qDrawing, 0, 0, 1, 2);
_qGrid.addWidget(&_qSliderV, 0, 2);
_qGrid.addWidget(new QLabel("Translation Horizontal"), 1, 0);
_qSliderT.setRange(150, 650);
_qSliderT.setSliderPosition(400);
_qGrid.addWidget(&_qSliderT, 2, 0);
_qGrid.addWidget(new QLabel("Rotation"), 1, 1, 1, 2);
_qSliderR.setSliderPosition(50);
_qGrid.addWidget(&_qSliderR, 2, 1, 1, 2);
setLayout(&_qGrid);
}
Output:
To achieve this specific layout, I placed the _qSliderV into column 2 and gave _qSliderR (and its label) a column span of 2 as well.
To illustrate this, I added a sketch of the resulting grid to the above snapshot:
Which behavior would you like for your Drawing widget?
By default it will be resized freely by the layout, you can change this by using QWidget::sizeHint() and QWidget::sizePolicy(). You'll find detailed information in Qt documentation about custom widgets and layouts.
i've created a custom progress bar, but when i call the SetValue() method the paintEvent method (overrided) is not called, so the progress bar show just the veryfirst value.
This is the Header grafica_progressbar.h
#ifndef GRAFICA_PROGRESSBAR_H
#define GRAFICA_PROGRESSBAR_H
#include <QWidget>
#include <QProgressBar>
#include <QPaintEvent>
#include <QPainter>
#include <QBrush>
#include <QStyle>
#include <QPen>
#include <QColor>
class grafica_ProgressBar : public QProgressBar
{
Q_OBJECT
public:
grafica_ProgressBar();
protected:
void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE;
};
#endif // GRAFICA_PROGRESSBAR_H
and this is the cpp grafica_progressbar.cpp
#include "grafica_progressbar.h"
grafica_ProgressBar::grafica_ProgressBar()
{
}
void grafica_ProgressBar::paintEvent(QPaintEvent *)
{
int tmpValue = value();
int TopPos = QStyle::sliderPositionFromValue(minimum(), maximum(), tmpValue, width());
QPainter p(this);
if (tmpValue<maximum()*0.85)
{
p.setPen(Qt::green);
p.setBrush(QBrush(Qt::green));
}
else
{
p.setPen(QColor(255,51,51));
p.setBrush(QColor(255,51,51));
}
p.drawRect(0,0,TopPos,height());
p.setPen(Qt::gray);
p.setBrush(QBrush(Qt::lightGray));
p.drawRect(TopPos, 0, width(), height()); //riempio tutto il resto di grigio
p.setPen(Qt::black);
p.setBrush(QBrush(Qt::black));
p.drawText(0,0, width(), height(), Qt::AlignCenter, QString::number(tmpValue ) + " bar");
}
and this is the first call into the userinterface costructor
TestProgres = new grafica_ProgressBar();
ui->gridLayout->addWidget(TestProgres);
TestProgres->setMaximum(400);
TestProgres->setValue(300);
if i try to call TestProgres->setValue(200) inside a button, i can't see any refresh.
So, where's the problem?
The code starts to work after a "clean, rebuilt & run" operation.
I've edited the code just for showing the correct value.
Thanks to all!
I have an QFrame within a QWidget, in my application. When I try to draw a draw a image within the QFrame, the image is inserted only when coordinates are (0,0) and if they are something like (100,100) the image is not drawn. I created a new class for the frame and implemented paintEvent(QPaintEvent *p) in it. Is there any thing I am doing here ?
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QFrame>
#include <QPainter>
#include "frame.h"
class frame;
namespace Ui {
class Widget;
}
class Widget : public QFrame
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
frame * f;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QFrame(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
f = new frame(ui->frame);
f->show();
}
Widget::~Widget()
{
delete ui;
}
frame.h
#ifndef FRAME_H
#define FRAME_H
#include <QObject>
#include <QWidget>
#include <QPainter>
class frame : public QWidget
{
Q_OBJECT
public:
explicit frame(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *p);
signals:
public slots:
};
#endif // FRAME_H
frame.cpp
#include "frame.h"
frame::frame(QWidget *parent) : QWidget(parent)
{
}
void frame::paintEvent(QPaintEvent *p)
{
QPainter* pPainter = new QPainter(this);
QImage img(":/left.png");
Q_ASSERT(!img.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
pPainter->drawImage(target, img,source);
QWidget::paintEvent(p);
QWidget::update();
}
If I use QRect target(0,0,20,10) in the above code the image is drawn.
testImage.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = testImage
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp\
widget.cpp \
frame.cpp
HEADERS += widget.h \
frame.h
FORMS += widget.ui
RESOURCES += \
src.qrc
DISTFILES +=
I am being stuck in this one for a long time, any idea will be helpful. I have tried Qt verions 5.6 and 5.8, similar result. And the OS is Lubuntu. The image resolution is 20*10. Thanks.enter image description here
Try like this:
void frame::paintEvent(QPaintEvent *p){
QPainter lPainter(this);
QPixmap lPixmap(":/left.png");
Q_ASSERT(!lPixmap.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
lPainter->drawPixmap(target, lPixmap);
QWidget::paintEvent(p);}
remove update form painEvent and try to use pixmap.
I have found a solution, I have subclassed QgraphicsView and reimplemented paint method in it,
void graphicsView::paintEvent(QPaintEvent *e)
{
QGraphicsView::paintEvent(e);
QPainter pPainter(this->viewport());
QImage img(":/images/x.png");
Q_ASSERT(!img.isNull());
QRect target(300,230,20,10);
pPainter.drawImage(target, img);
}
I use this to render text in a QGLWidget
QGLWidget::renderText(x, y, z, text, font)
The string is rendered at a depth of ~0.5 (obtained via glReadPixel()).
However, in my case it should be closer to ~0.9.
When I convert the x,y,z coords into screen coords with the current matrices I also find a result of ~0.9.
Why such a difference? It makes the text appear always in front.
I created a simple QT project in visual studio to reproduce the issue.
It draws a green square with text in front and behind the square. Both text look in front of the square. And the depth of the pixel can be read by hovering the mouse.
I use Qt version 5.5 built for 64bit platform.
MyGLWidget.h
#include <QGLWidget>
#include <QMouseEvent>
class MyGLWidget : public QGLWidget
{
Q_OBJECT
private:
float _depth;
public:
MyGLWidget(QWidget * parent = 0);
virtual ~MyGLWidget();
virtual void initializeGL();
virtual void paintGL();
void mouseMoveEvent(QMouseEvent * event);
signals:
void depthRead(float);
};
MyGLWidget.cpp
#include "MyGLWidget.h"
#include <gl/GLU.h>
#include <Qfont>
MyGLWidget::MyGLWidget(QWidget * parent) : QGLWidget(parent)
{
}
MyGLWidget::~MyGLWidget()
{
}
void MyGLWidget::initializeGL()
{
}
void MyGLWidget::paintGL()
{
// set up projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float width = this->width();
float height = this->height();
glViewport(0, 0, width, height);
gluPerspective(45, width / height, 1, 100);
// set up model view
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,5, // eye
0,0,0, // look at
0,1,0); // up
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
// draw a green square
glColor4f(0,1,0,1);
glBegin(GL_QUADS);
glVertex3f(-1,-1,0);
glVertex3f(1,-1,0);
glVertex3f(1,1,0);
glVertex3f(-1,1,0);
glEnd();
// render some blue text behind the square
QFont font;
font.setPointSize(20);
glColor4f(0,0,1,1);
renderText(-2,-0.5,-1, "BEHIND_BEHIND_BEHIND_BEHIND", font);
// render some red text in front of the square
glColor4f(1,0,0,1);
renderText(-2,0.5,+1, "IN_FRONT_IN_FRONT_IN_FRONT_I", font);
}
void MyGLWidget::mouseMoveEvent(QMouseEvent * event)
{
int x = event->x();
// flip y for QT origin is top left while OpenGL origin is bottom left
int y = this->height() - event->y();
// read pixel depth
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &_depth);
// update ui
emit depthRead(_depth);
}
rendertexttest.h
#ifndef RENDERTEXTTEST_H
#define RENDERTEXTTEST_H
#include <QtWidgets/QMainWindow>
#include "ui_rendertexttest.h"
#include "MyGLWidget.h"
class RenderTextTest : public QMainWindow
{
Q_OBJECT
public:
RenderTextTest(QWidget *parent = 0);
~RenderTextTest();
public slots:
void onDepthRead(float depth);
private:
Ui::RenderTextTestClass ui;
MyGLWidget * _glwidget;
};
#endif // RENDERTEXTTEST_H
rendertexttest.cpp
#include "rendertexttest.h"
RenderTextTest::RenderTextTest(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
_glwidget = new MyGLWidget(this);
_glwidget->setMouseTracking(true);
QObject::connect(_glwidget, SIGNAL(depthRead(float)),
this, SLOT(onDepthRead(float)));
ui._mainLayout->addWidget(_glwidget);
}
RenderTextTest::~RenderTextTest()
{
}
void RenderTextTest::onDepthRead(float depth)
{
ui._lblDepth->setText(QString::number(depth));
}
ui_rendertexttest.h
/********************************************************************************
** Form generated from reading UI file 'rendertexttest.ui'
**
** Created by: Qt User Interface Compiler version 5.3.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_RENDERTEXTTEST_H
#define UI_RENDERTEXTTEST_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_RenderTextTestClass
{
public:
QWidget *centralWidget;
QWidget *verticalLayoutWidget;
QVBoxLayout *_mainLayout;
QLabel *_lblDepth;
void setupUi(QMainWindow *RenderTextTestClass)
{
if (RenderTextTestClass->objectName().isEmpty())
RenderTextTestClass->setObjectName(QStringLiteral("RenderTextTestClass"));
RenderTextTestClass->resize(600, 438);
centralWidget = new QWidget(RenderTextTestClass);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
verticalLayoutWidget = new QWidget(centralWidget);
verticalLayoutWidget->setObjectName(QStringLiteral("verticalLayoutWidget"));
verticalLayoutWidget->setGeometry(QRect(9, 9, 581, 381));
_mainLayout = new QVBoxLayout(verticalLayoutWidget);
_mainLayout->setSpacing(6);
_mainLayout->setContentsMargins(11, 11, 11, 11);
_mainLayout->setObjectName(QStringLiteral("_mainLayout"));
_mainLayout->setSizeConstraint(QLayout::SetDefaultConstraint);
_mainLayout->setContentsMargins(0, 0, 0, 0);
_lblDepth = new QLabel(centralWidget);
_lblDepth->setObjectName(QStringLiteral("_lblDepth"));
_lblDepth->setGeometry(QRect(10, 410, 581, 16));
RenderTextTestClass->setCentralWidget(centralWidget);
retranslateUi(RenderTextTestClass);
QMetaObject::connectSlotsByName(RenderTextTestClass);
} // setupUi
void retranslateUi(QMainWindow *RenderTextTestClass)
{
RenderTextTestClass->setWindowTitle(QApplication::translate("RenderTextTestClass", "RenderTextTest", 0));
_lblDepth->setText(QApplication::translate("RenderTextTestClass", "Depth:", 0));
} // retranslateUi
};
namespace Ui {
class RenderTextTestClass: public Ui_RenderTextTestClass {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_RENDERTEXTTEST_H
There might 3 issues
1- the target depth is computed correctly in QGLWidget::renderText() and passed to the paintEngine via setTranslateZ(). However the vertex shader does not set this value directly in the vertex clipped coordinates. Instead it translate by this value.
2- the sign of translateZ seems incorrect. That would explain why the depth of the text pixels increases when the text comes closer.
3- it seems clipped coordinates [0, 1] are mapped to range [0.5 , 1] Yet I did not see any call to glDepthRange() in Qt's source.
If we change the code of qglslComplexGeometryPositionOnlyVertexShader in qglengineshadersource_p.h with the following, it fixes the problem.
static const char* const qglslComplexGeometryPositionOnlyVertexShader = "\n\
uniform highp mat3 matrix; \n\
uniform highp float translateZ; \n\
attribute highp vec2 vertexCoordsArray; \n\
void setPosition(void) \n\
{ \n\
vec3 v = matrix * vec3(vertexCoordsArray, 1.0); \n\
v.z = (-translateZ - 0.5f) * 2.0f; \n\
gl_Position = vec4(v.xyz, 1.0);\n\
} \n";
I found that a nice workaround is to render the text into a texture. And then display that texture in the scene.
This works nicely if the text is rendered over a solid background color.
QGLWidget does not seem to write to the alpha channel.
I have been trying to use Qt5 to give me an OpenGL context, which I believe it does, but when I try to call glewInit() from within the initializeGL function, the error returns back "Missing GL version," which I have been led to believe indicates that there is no valid context. The solution I saw was to call glewInit() from within initializeGL... but I'm already doing that.
I am setting the clear color and clearing to dark red to verify that gl calls are working, which they appear to be.
Any suggestions?
main.c
#define QT_NO_OPENGL_ES_2
#include <QApplication>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GLWidget w;
w.show();
return a.exec();
}
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <GL/glew.h>
#define QT_NO_OPENGL_ES_2
#include <QGLWidget>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QGLWidget *parent = 0);
~GLWidget();
QSize minimumSizeHint() const;
QSize sizeHint() const;
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(QGLWidget *parent) :
QGLWidget(parent)
{
}
GLWidget::~GLWidget() {}
QSize GLWidget::minimumSizeHint() const {
return QSize(640, 480);
}
QSize GLWidget::sizeHint() const {
return QSize(800, 600);
}
void GLWidget::initializeGL() {
GLenum err = glewInit();
if (GLEW_OK != err) {
printf("GLEW error: %s\n", glewGetErrorString(err));
} else {
printf("Glew loaded; using version %s\n", glewGetString(GLEW_VERSION));
}
glClearColor(0.2f, 0, 0, 1.0f);
}
void GLWidget::resizeGL(int w, int h) {
}
void GLWidget::paintGL() {
glClear( GL_COLOR_BUFFER_BIT );
}
Something tells me this is because of the QGLWidget's default QGLFormat using OpenGL version 1.0 (Looking through GLEW's change logs, it seems the earliest version they claim to fully support is 1.5) . Try instead to override the QGLWidget constructor that requires a QGLFormat and pass it an instance of QGLFormat that uses the version you are targeting.
The call to your widget should look something like:
QGLFormat format;
format.setVersion(3,3); // or whatever version you are targeting.
format.setDoubleBuffer(true);
GLWidget * widget = new GLWidget(format);