How do I actually use OpenGL in Qt 5? - c++

Simply put, I cannot for the life of me figure out how to actually make use of things like QOpenGLWidget or QOpenGLWindow or anything. I want to have the rendering I do be a child widget of a window in a MDI, but nothing works.
Here's the code I have currently set up for the widget (at least, just the parts involving OpenGL):
Viewport::Viewport(QWidget * parent) : QOpenGLWidget(parent) { }
void Viewport::initializeGL() {
initializeOpenGLFunctions();
}
void Viewport::paintGL() {
// first, clear the screen
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
And here's how I use the widget:
vp = new Viewport;
vp->resize(QSize(320,240));
hbox->addWidget(vp);
And the result is that I see nothing. I just see a tiny sliver of empty space next to the other widget in the window, but that's it. No black screen like I try to clear with, not even a 320x240-sized empty space.
Like I said, I've been unable to do this in any of the ways I could find, and it's really frustrating. Am I missing something obvious? There's very little documentation as-is, so it's hard to tell if I am, or if there's some weird corner case I'm running into. (For example, none of the documentation I find uses QOpenGLWidget as part of a larger widget; is that because it can't be, or because all the examples I can find are just lazy about using the widget as its own top-level window?)

After some more fiddling around, it turns out my issue was apparently caused by the other object in the window (a QListView) by default taking up as much space as possible, making the OpenGL widget disappear since it doesn't have a minimum size.
In other words, the problem is fixed by either changing the QListView to have a QSizePolicy::Preferred sizing policy (since resizing the window will now let you see the OpenGL widget), or by giving the OpenGL widget a minimum or fixed size.
(As an aside, I really wish this could've been more obvious than just stumbling upon it by chance.)

Related

Painting with rotated QPainter clips to incorrect region of QImage

I have a QImage that represents a blank piece of paper and a QPainter, which is used to paint onto this image.
Sometimes, I will want to rotate/translate the QPainter before any paint operations, in order to paint onto this image in "Landscape" orientation.
Here is a simplified snippet of the code:
_image = new QImage(paperRect().size(), QImage::Format_RGB888);
_painter->begin(_image);
if (_orientation == QPrinter::Landscape)
{
_painter->translate(0, _image->height());
_painter->rotate(270);
}
// Painting operations here.
Unfortunately, this is not working as I had expected. It seems that even though the painter has been rotated, it is unaware of the "new" bounds it can paint within, thereby clipping to the "Portrait" size.
I have tried the following to no avail: Turning off clipping (_painter->setClipping(false);), setting a new clip rect (_painter->setClipRect(0, 0, _image.height(), _image.width());), and adjusting the window and viewport in various ways.
I have looked through the documentation of QPainter and QImage, and scoured the internet, but I haven't found this particular issue discussed before.
As it turns out, the problem was unrelated to my posted code. Here is my solution, in case anyone runs into this issue in the future.
The problem originally came about during implementation of a custom QPrintEngine/QPaintEngine class. The code posted in the question works--however, I had forgotten to update the QPrintEngine::property() function to return the new dimensions corresponding to the PPK_PageRect and PPK_PaperRect keys, when the orientation was set to Landscape.
Note that the QPrintEngine::metric() function does not appear to need to be updated in this way (in my project). I'm assuming this is because the metric function is mostly used when the QPrinter that utilizes this QPrintEngine implementation is used as a paint device, and that never happens in my project.
In any case, fixing this issue allows the QImage to be properly painted on "sideways".

X11 window does not get refreshed until it gets an event

In my application (cairo and X11), the user can issue a command whereby the drawing is enlarged. To be able to grab the entire drawing as a pattern, I enlarge the drawing surface to match the current scale (the drawing is just a graph, so this can be afforded as far as memory is concerned). Beginning with a certain scale though, the X11 window refuses to refresh until it gets an event (e.g. loss of focus, which is not even handled in my application).
I tried refreshing the window using both XFlush() and XSync().
Does this look like a bug in the windowing system? If not, what should I do? Everything works perfectly with smaller scales.
EDIT 1: After much work with gdb, I found that the problem is not with the window not refreshing. Rather, at a certain point a call to XNextEvent() causes the window to become all black.
EDIT2: It looks like calls to XNextEvent() actually cause the window to be refreshed! And here is the code that caused the problem:
struct PatternLock {
PatternLock(Graphics &g)
: g_(g) {
p_ = cairo_get_source(g_.cr);
cairo_pattern_reference(p_);
}
~PatternLock() {
// The commented lines caused the problem. How come?
// cairo_set_source_rgb(g_.cr, 0, 0, 0);
// cairo_paint(g_.cr);
cairo_set_source(g_.cr, p_);
cairo_paint(g_.cr);
cairo_pattern_destroy(p_);
}
private:
Graphics &g_;
cairo_pattern_t *p_;
};
Suppose the we have this code for moving the drawing:
{
PatternLock lock{g};
... // Change of transformation matrix
}
It somehow happen that the effect of the commented lines in the destructor of PatternLock becomes visible (hence the black screen), but the effect of the following lines does not. I realize that the commented code is actually unneeded. But still, how does this happen?
If my memory serves me correct, there's a limit to Drawables (e.g. Windows and Pixmaps) of 4096x4096 pixels. You should check the return values of your calls to XCreatePixmap() etc.
Either way, just enlarging the pixmap to draw your drawing is Bad Design (tm), and will inevitably lead to a very slow program. Learn how to deal with zoom and pan (tip: work from the center of your viewport, not the corners). Assuming your drawing is vector-based (i.e. lines and curves) you can optimize painting a lot at high zoom factors.
If you must grab a complete graph at a resolutions larger than 4096 pixels you must implement tiling, which isn't that hard if you have zoom and pan already.

How to draw to "parent TLW backing store"?

This might be very complicated question not many people know answer but I still will ask.
I do have QWindow derived class, with overloaded event(), which uses Backing store and fill in whole window with a colour, let say black.
Now I have my QT QML app, when I create my window and set parent as main view of my app, I getting window sized to 1x1px ! This is driving me crazy..
I dug though the QT source code and found this:
void QQnxRasterWindow::adjustBufferSize()
{
// When having a raster window we don't need any buffers, since
// Qt will draw to the parent TLW backing store.
const QSize windowSize = window()->parent() ? QSize(1,1) : window()->size();
if (windowSize != bufferSize())
setBufferSize(windowSize);
}
void QQnxRasterWindow::setParent(const QPlatformWindow *wnd)
{
QQnxWindow::setParent(wnd);
adjustBufferSize();
}
Which is kinda bummer because I have no idea how I suppose to use TLW and draw into my window now.
Any ideas?
First of all what is TLW ?
Second how do I draw into parent TLW in a way it will end up in my window buffer.
Thank you
QT 5.3.1
Edit:
not renderNow() - my mistake,
overloaded function event, which uses event UpdateRequested to draw my background.
Edit2:
Also this is only problem when I set parent, when no parent set I can do whatewer I want with my QWindow and it has own buffer. Kinda weird.

resizing QGLWidget to fit with each sprite size I have

I'm creating 2D Map editor using opengl to draw simple 32x32 sprites but it seems that I cannot resize my QGLWidget to a large size (i.e size * sprite size -> 1024 * 32), using 1024 only seems to work fine (using glwidget->setMinimumSize(...)). I've been googling for a while now about this, the only interesting thing I found is subclassing QAbstractScrollArea and setting my QGLWidget as it's viewport (That's what QGraphicsView does), I also seen all Qt opengl examples but i couldn't find anything that could help (except Image Viewer example which is not exactly what I want), I also tried the following:
horizontalScrollBar()->setMaximum(width * 32);
verticalScrollBar()->setMaximum(height * 32);
with the widget resizable set to true/false on the scrollarea but still nothing.
Any ideas how would I do that? I can show more code if you ask me to.
Using Qt v4.7.3.
I have two ideas:
If it's possible, drop the idea of using a QGLWidget and place the sprites directly in a graphics scene (QGraphicsPixmapItem). Possibly not what you want, but the graphics scene is made to handle a lot of items, so most things you need (trigger mouse events on items for example) are already implemented.
Or just place the QGLWidget in a graphics scene using a QGraphicsWidget. This should automatically tell the scene its size, which then tells the view the size of the scene. The scroll bars appear automatically if the scene doesn't fit into the view.
Update:
As described in this link, you can use OpenGL in any graphics view:
view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);

Coordinate confusion

I subclassed QGraphicsItem and reimplemented paint.
In paint I wrote something like this for labeling the item:
painter->drawText("Test",10,40);
After some time I think It may be useful to handle labeling with seperate item. So I wrote something like this.
QGraphicsTextItem *label = new QGraphicsTextItem("TEST",this);
setPos(10,40);
But two "TEST" drawing do not appear in the same place on screen. I guess difference may be related with item coordinates - scene coordinates. I tried all mapFrom... and mapTo... combinations inside QGraphicsItem interface but no progress. I want to drawings to appear in the same place on screen.
What I miss?
I assume that you are using the same font size and type in both cases. If the difference in position is very small the reason can be the QGraphicTextItem is using some padding for the text it contains. I would try to use QGraphicsSimpleTextItem that is not going to add fancy stuff internally and see if you still have the same problem. The coordinates system is the same one if you use painter or setPost so that is not the problem. If this doesn't help I will suggest to specify the same rect for both to avoid Qt adding it owns separation spaces.