Trying to make Qt HUD in OSG, camera issue - qt

I'm kind of newbie in both OSG and Qt, still I'm trying to make Qt HUD upon my OSG window, what I want is Qt interface elements fixed inside OSG scene, not spinning with the model. The thing is, I need Qt elements INSIDE osg scene, not OSG scene inside Qt window (like in OSGviewerQt example).
What I've got yet is OSGQtWidgets example with --useWidgetImage --fullscreen arguments, which shows fixed Qt controls ontop of OSG Model. The thing is, it creates new (FIXED) camera for qt element ontop of OSG model -- because of that, user cannot spin and move OSG model because camera is not transparent.
So the question is: is there a way to make transparent camera with useable Qt elements in it? Or is there some other way to achieve my goals?
Thank you in advance!

I am unable to try this out for myself first, but you can try setting a property on the Orthogonal "HUD" camera to let events pass through to the regular OSG viewer:
camera->setAllowEventFocus(false);
If you're using a recent version of osgQtWidgets.cpp, you'd want to add this around line 414.

Related

Qt: The best procedure to create own QGraphicsScene/s

I'm making fractal creator software. So I need one scene per fractal and these scenes need to be "layered" because of zooming rubber band.
I've already tried to write it the "widget" way, so I had one custom widget called "canvas". In my canvas class I overrided paintEvent, and inside this event I rendered current fractal. Everytime when somebody clicked to menu with another fractal, I called update() method and new fractal was rendered. To zooming I used overriding of mouse events and update() of canvas. At the first time I repainted the whole canvas, but it was very very slow. After that I repainted only the part under the rubber band, but still slow when I'd like to select some bigger area and other problems with repainting.
So I've looked for another way to do it. Layers. I've found the QStackedWidget, but I didn't find way how to make visible both of my layers and the top one to be transparent. After that, I've found QGraphicsScene and this seems to be the best way to do it. But I don't know the correct procedure to do it. Below are two procedures I'm thinking about:
Create QGraphicsView
Instead of the widget, the canvas will be QGraphicsScene
I'll override some QGraphicsScene event (but I don't know which one - drawItems() is obsolete and override update() seems wrong to me, but maybe...)
When other fractal will be chosen, I'll repaint canvas by calling update() the same way as in my "widget" solution
In the foreground layer will be zooming rubber band
or:
Create QGraphicsView
Instead of the widget, the canvas will be QGraphicsScene
Every fractal will be the child of QGraphicsItem
When other fractal will be chosen, I'll remove the old one fractal
item and replace it by new one and probably call invalidate()
In the foreground layer will be zooming rubber band - I think, that
it's common behaviour of the QGraphicsScene isn't it?
Is one of my reasonings correct? Do you suggest anything else? Fractals are complicated in the calculations and It's very important to repaint only if it is necessary. Could you help me, please?
Thank you :-)
Edit: "zooming rubber band" explanation:
I'm sorry for my expression "zooming rubber band". It means scale (zoom) the area below the selection made by the rubber band - zooming the same way as in Photoshop CS5 (for example). And I'd like to know what part of the scene is repainted while selecting this way. If there is repainted whole scene, or the part of the scene below selected area, or there is nothing repainted and rubber band selection is done in separate layer.
I hope my explanation helped :-).
In Qt, a QGraphicsScene can be thought of as a world of items, with a QGraphicsView as a window into that world. Therefore, you should be adding items to the QGraphicsScene, based on QGraphicsItem (or QGraphicsObject if you want signals and slots).
In your situation, I'd create a Fractal class that inherits from QGraphicsItem and add that to the scene. Ensure to override the necessary pure virtual functions such as boundingRect and paint.
Do not calculate the fractal code in the paint function. I suggest the Fractal class stores a QPixmap (or QImage if you're drawing at the pixel level) and render the fractal to this. Then perodically, in the paint function, the Fractal class would render the contents of the QPixmap with a call to painter->drawImage or painter->drawPixmap; whichever is relevant in this case.
As for zooming, your Fractal class can then response to being scaled, appropriately changing the rendering on the internal representation.

How can I hunt down these OpenGL calls that are distorting objects in my scene?

I'm mixing two libraries that use OpenGL: Qt and OpenSceneGraph. I'm targeting OpenGL ES 2, so everything is done with shaders and ES 2 compatible calls.
I'm specifically using OSG with QtDeclarative by trying to paint OSG onto a QDeclarativeItem. I do this the way suggested in Qt documentation: wrap all OpenGL calls between beginNativePainting()/endNativePainting().
This works fine until I use textures in my OpenSceneGraph scene. When I do this, my QML window gets "messed up" for lack of a better word. To keep it as simple as possible, my OSG scene consists of a plane with a texture applied to it. I recreated the scene using basic OpenGL calls and the problem no longer occurs. Here's the problem summarized as a bunch of pictures:
The QtDeclarative engine uses OpenGL to paint stuff. I set up a simple QML page:
I create a simple scene using OpenGL directly. It's a plane with a texture painted onto it.
Now I try to set up the same scene in OSG... identical shaders, etc.
You can see something odd is going on with the last screenshot. Don't worry about the black background where the original OpenGL scene was transparent, that's just OSG using a black clear color. The problem is that the other items set up with QML (the rectangles) get messed up.
Edit: To clarify what happens: The rectangles I draw with QML are all stretched out to the right edge of the screen. I also noticed if I draw rectangles after the OpenSceneGraph item in QML, they don't show up (I didn't notice this before). I draw the purpley black rectangle after the OSG item in the following screenshots... note that it disappears. There might be more weird stuff happening, but this is all I've observed playing with rectangles.
Before
After
I'm fairly new to OpenGL so I don't know what kind of call/state setting would cause something like this to happen. I think that OpenSceneGraph makes some OpenGL state change that's messing up Qt's paint engine. I also know that this only occurs when OSG uses textures... if I don't apply textures in my OSG scene, this doesn't happen. This is where I'm stuck.
Also, I tried to use BuGLe to get an OpenGL call trace with and without textures enabled in OSG to see if I could figure out the problematic state change(s). I found a few differences, and even some global state that OSG changed (such as glPixelStorei()) between the two, but resetting the changes I found made no difference. It would help a lot if I knew what to look for. If anyone's feeling insane, I also have the stack traces:
OSG with texturing: http://pastie.org/4223182 (osg texture stuff is lines 637~650)
OSG without texturing: http://pastie.org/4223197
Edit 2:
Here's a diff that might be helpful. You'll need to scroll way down before the relevant lines are apparent.
http://www.mergely.com/nUEePufa/
Edit 3:
Woah! Okay, that diff helped me out quite a bit. OSG enables VertexAttribArray 3 but doesn't disable it. Calling glDisableVertexAttribArray(3) after OSG renders its frame seems to partially solve the problem; there's no more stretching of the QML rectangles. However, rectangles drawn after the OSG item still don't show up.
After obsessing over the trace logs, I think I've found two OpenGL things that need to be reset before passing control back to Qt to cause the issues above to go away. I mentioned one in an edit... I'll summarize both in this answer.
Rectangle/QML Item distortion
QPainter uses Vertex Attributes 3, 4, and 5 directly for something that looks like its related to the geometry of those rectangles. This can be seen in the trace:
[INFO] trace.call: glVertexAttrib3fv(3, 0x2d94a14 -> { 0.00195312, 0, 0 })
[INFO] trace.call: glVertexAttrib3fv(4, 0x2d94a20 -> { 0, -0.00333333, 0 })
[INFO] trace.call: glVertexAttrib3fv(5, 0x2d94a2c -> { 0.2, 0.4, 1 })
Disabling the corresponding vertex attribute arrays fixes the stretchy rectangles issue:
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
glDisableVertexAttribArray(5);
Items drawn after the OSG Item don't render
In retrospect, this was one was easy and didn't have anything to do with texturing. I hadn't noticed this before trying to add textures to my scene though, so mixing the two issues was my fault. I also screwed up with the traces and diff I posted; I never updated them to account for the ordering problem after I discovered it (sorry!)
Anyways, QPainter expects depth testing to be turned off. Qt will turn depth testing off when you call beginNativePainting(), and also when it starts to paint its items... but you're expected to turn it back off whenever handing control back:
QPainter paints stuff (DEPTH_TEST = off)
OSG draws stuff (DEPTH_TEST = on)
QPainter paints more stuff [expects DEPTH_TEST = off]
The right trace logs showed that I wasn't doing this... So the fix is
glDisable(GL_DEPTH_TEST)
Maybe you just need to reenable GL_TEXTURE_2D? I notice in your example with textures that OSG enables, and subsequently disables GL_TEXTURE_2D. Thus the difference between your two cases (with texture vs without), is that the one that uses textures finishes with texturing disabled, while the one without texturing leaves GL_TEXTURE_2D in it's initial state.
If Qt needs/expects texturing enabled to draw quads it could cause nothing to show up.

Can't embed OpenGL window into QWidget with XReparentWindow

I'm trying to add better UI for an OpenGL-based program with Qt. Since I can modify that program it's not hard to get the window ID. So I think embedding it into a QWidget would be a good idea. However, it doesn't work like I expected:
After XReparentWindow is called, the OpenGL window lose its decoration, but the position didn't change.
If I use XConfigureWindow to move it to position (0, 0) relative to parent it goes to the top-left corner of the screen, but not the QWidget.
After reparenting, a third window can cover the QWidget, but nothing can cover the OpenGL window.
X11 reported no errors during the whole operation.
It seems the parent of the OpenGL window has been set to the root window instead of my QWidget. What should I do to make it work correctly?
You can replace your current OpenGL window with a QGLWidget which provides an OpenGL context and can be placed into a Qt window directly.
I'm not sure Qt supports XReparentWindow calls like that. The docs don't seem to say it does, so it's probably a bad idea to use it. You could try QWidget::create() instead.

draw qt widget bigger as the mouse hovers over it (overlapping of widgets)

I would like to create a simple effect with my qt gui, but i have no idea how to achieve this.
I have several widgets, that i implemented as subclasses of qwidget. These are part of another widget and live in a layout. When the mouse hovers over these widgets, i want them to appear bigger to highlight the selected one.
This is what i already tried:
Override the paint event, and simply paint it bigger. But then, the other widgets that also live in the same layout overpaint the oversized areas.
I also tried to call the paint function "by hand" from the parent window, to get control over the painting order. But that didnt help either.
I think there has to be a possibility achieving this effect this qt, but i simply dont know how.
Any ideas?
You could either:
create your GUI inside a QGraphicsView, with QGraphicsWidgets and use setScale when the mouse enters or leave the widget, or
use QML.

How to draw QGraphicsItem in a MFC view

I'm starting using Qt in my application. My application is MFC based. I want to draw some QGraphicsItems in my currect MFC view, is it possible?
You may say that it could be done by hosting QGraphicsView with QWinWidget in the MFC view, that don't work, however. Because my Canvas (MFC view) supports zooming and rotating while the QGraphicsView itself don't. When I zooming the QGraphicsItem, the QGraphicsView shows scroll bar instead of enlarging itself.
Any suggestion? Thanks!
Theoretically you could use QGraphicsScene::paint to paint the scene with your QGraphicsItems in the buffer, and then draw it to MFC view, but it does not make any sense...
What is the problem with QGraphicsView anyway? Have you taken a look at the rotate(), scale(), translate() or shear() functions of it?
You can turn off the displaying of scroll bard of QGraphicsView by setting the ScrollBarPolcies to Qt::ScrollBarAlwaysOff. (QGraphicsView is a sub-class of QAbstractScrollArea.)
I am not sure I understand what you mean by rotating QGraphicsView itself instead of the content. Without the scroll bars, I don't see the difference. Also much of the functionality of QGraphicsItem like editing as you indicated, depends on event handling in QGraphicsScene and QGraphicsView to work. I don't think plugging just a QGraphicsItem into the MFC view will do what you want.

Resources