Partial Renderer OpenGL (viewport) on QT QQuickWindow - qt

How to render OpenGL viewport on QT Window? Even if I set glViewport(100, 100, 100, 100), it renders in all window. I want show partial view for Opengl and partial view for QT Controls.
I am using QT5 + QML (QQuickWindow).

Note, glViewport specifies the transformation of normalized device coordinates to window coordinates. But it doesn't "protect" the framebuffer area, outside a certain rectangle, from being written to.
So it doesn't effect operations like glClear.
The Scissor Test can be used to define a rectangle and discards operation on fragments which are not inside the rectangle.
The scissor test has to be enabled by glEnable(GL_SCISSOR_TEST) and the rectangular scissor area can be defined by glScissor:
e.g.
glEnable(GL_SCISSOR_TEST);
glScissor(100, 100, 100, 100);

Related

QT QVulkanWindow overlay widgets

I'm searching a way to draw any QT widget overlay on QVulkanWindow. I cannot find solution. Child/parent hierarchy and QT flags don't bring expected behaviour. Is it possible to draw QT widgets on the top of QVulkanWindow?
I've tried the following
1) attempt to create QWidget and Vulkan window from one parent QWidget
auto widget = new QWidget;
widget->resize(m_default_width, m_default_height);
widget->show();
m_label = new QLabel("text.", widget);
m_label->show();
m_vulkan_window = std::make_shared<WSQVulkanWindow>(this);
m_vulkan_window->setVulkanInstance(&m_qt_vk_instance);
m_vulkan_window->show();
auto wrapper = QWidget::createWindowContainer(m_vulkan_window.get(), widget);
wrapper->resize(m_default_width, m_default_height);
wrapper->show();
2) Added the following flags
m_label->setAttribute(Qt::WA_NoSystemBackground);
m_label->setAttribute(Qt::WA_TranslucentBackground);
m_label->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::CoverWindow);
Label is shown on top of vulkan window but it doesn't follow vulkan window position
3) Attempt to add QWidget::createWindowContainer of VulkanWindow and QLabel widget to one parent widget with QGridLayout or QVBoxLayout.
It has no effect
4) Create QVulkanWindow with parent newwidget->windowHandle() with following creation QLabel widget on newwidget parent
5) Create new QWindow with parent QVulkanWindow. After that create widget from QWindow and create child QLabel for mentioned widget.
winapi creates button on top of vulkan window. But it is impossible to create semi-transparent widgets
m_hwndButton = CreateWindowExW(
0L,
L"BUTTON", // Predefined class; Unicode assumed
L"VR", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
10, // y position
50, // Button width
50, // Button height
(HWND)m_vulkan_window->winId(), // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong((HWND)m_vulkan_window->winId(), -6), //instance
NULL); // Pointer not needed.
ShowWindow(m_hwndButton, SW_SHOW);
UpdateWindow(m_hwndButton);
Child/parent hierarchy and QT flags don't bring expected behaviour.
Once a surface is being managed by the GPU/Vulkan, you can't really expect to be able to draw native controls in it with something else.
Qt Widgets aren't really suited to rendering on a Vulkan surface. Widgets are typically native controls, so to display them on a Vulkan surface, you'd have to capture the widgets to an image, transfer that image to the GPU and then render the image.
If what you want to do is get UI inside Vulkan rendering, your best bets are either Imgui or QML. QML can be rendered to an OpenGL surface using QQuickRenderControl, and that GL surface can be shared with a Vulkan image using VK_KHR_external_memory. Imgui on the other hand is designed to be able to be rendered directly in a variety of GPU APIs, of which Vulkan is one. In both cases you will be responsible for capturing Qt events and passing them to the Imgui or QML layer.

Qt/PySide/PyQt - QGraphicsScene drawing fail when zooming in

I am using QGraphicsScene and View in Qt/PySide and have troubles using scaling the view - zoomin in.
I have a very simple scene:
scene = QtGui.QGraphicsScene()
scene.addText("hello!")
scene.addRect(0, 0, 50, 20)
view = QtGui.QGraphicsView(parent)
view.setScene(scene)
What I see is OK. When I zoom in using view.scale(factor, factor) and look at the lower left corner, it still is OK.
... but when I zoom even closer, it gets broken. Rectangle is no more rectangle and I can see a diagonal line while the bottom line is missing.
What is wrong with my code? Or is it error in Qt library? Does it happen also in Qt with C++.

JavaFX: Rectangle with custom bounding rect and paint method

What I want to do:
In PySide, one could override the paintEvent() method of a QWidget to draw a custom widget. The bounding rect can be customized by overriding the boundingRect() method.
How does one do this in JavaFX? My goal is to create a custom Rectangle object, that draws itself smaller than it's bounding rect.
In context:
I'm creating an MS Paint clone in JavaFX. I'm working on the selection box that you use to select/move pixels around. I want the cursor to change to the appropriate resizing cursor when it is near the outside of the selection box.
However, the bounding rect is the same size as the selection box drawn on the screen, so the cursor only changes when it is on top of the box, but not when near. My solution is to set the bounding rect to larger than the actual selection box is, so the cursor change will occur. Then, override it's paintEvent() equivalent to draw a smaller selection box.
Thanks for your help.
I have a similar use case to you, and asked a similiar question here : Drawing transform independent layout bounds in JavaFX.
The JavaFX API is much higher level though than Java2D or PySide (I am assuming from your snippets, because I actually never heard of it ;) ), it does not allow you to override painting of Nodes, nor can you stop a Node from inheriting its parents transform.
This means that you need a seperate Group parallel to your content where you create the selection box and update it according to your needs (content changes etc.).
Example SceneGraph:
Scene
contentGroup
someShapeFromUser
selectionBoxGroup
selectionBoxOfSomeShapeFromUser

qgraphicsview preferred size

I am now trying to resize a qgraphicsview to a preffered size:
I am using layouts:
this->layout()->addWidget(&qtview);
I have layouts everywhere, so thet the size of my main widow is adjusted depending on its contents.
If I use:
qtview.setMinimumWidth(500);
qtviewSetMinimumHeight(500);
Then my view is scaled to the given size, but I am not able to shrink the main window. (which makes sense as I set a minimum soze)
I would like to tell qt my preferred (not minimum or maximum) size for the view, letting the view use scrollbars when needed (i.e. if the preferred size does not fit in my screen), or letting qt have a smaller view than my preferred size if the scene is smaller than my view, (or enlarge the scene to fit the view in this case)
I am searching for something looking like an hypothetical method setPreferredWidth().
What can I do to get this behaviour?
It sounds like you're looking for the QGraphicsView function setSizePolicy: -
setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));

How to get visible scene rectangle of QGraphicsView?

I'm displaying a map built as rectangle of QGraphicsPixmapitem items (each item stands for one map tile). Because my map is quite large (around 30 MB of PNG files) I want to be able to load pixmaps on demand only when they're visible for user in QGraphicsView and unload when they became invisible.
Is there any way to figure out visible scene rectangle?
This gives you the visible scene rectangle:
sceneRect = graphicsView.mapToScene(graphicsView.rect()).boundingRect()
In case there is a shear or rotation transformation present it gives you the bounding rectangle of the visible scene area. If you do not have such transformations (only shift or zoom) the returned rectangle is the exact scene area.
Now for your real problem of efficiently display a huge tiles map in a scene? You could load the tiles in background and first evaluate if your Qt framework isn't already optimized for big pixmap that are outside the visible range. 30 MB also doesn't sound so big that it wouldn't fit into memory.
QGraphicsView inherits the QWidget::geometry() function. You can use this to determine its location and size within its parent widget. (Outside of its constructor)
The QGrapicsScene can be larger than the QGraphicsView. The default QGraphicsView will add horizontal and vertical scroll bars to house the QGraphicsScene. I imagine you would like to do something like this:
//create a QGraphicsScene (for this example *scene) that is the size of your entire map.
QGraphicsScene *scene=new QGraphicsScene(0,0,mapWidth,mapHeight);
//create a QGraphicsView* named view that is the size of your visible area
//I'm assuming visibleHeight and visibleWidth do not change (this is your viewing window)
QGraphicsView *view=new QGraphicsView(0,0,visibleWidth,visibleHeight);
view->setScene(scene);
Have the user control the x and y position of the scene that triggers some custom signal like sceneMoved(int,int). Before you redraw the scene, call a slot to check the new position of the scene:
connect(this,SIGNAL(sceneMoved(int,int)),this,SLOT(drawScene(int,int)));
void SomeClass::drawScene(int newX, int newY){
//if you already have a pointer to the scene do this, or call
//QGraphicsView::scene();
int oldX=scene->geometry()->x();
int oldY=scene->geometry()->y();
//now that you have your oldX, oldY, newX, and newY, visibleWidth, visibleHeight
//you can determine what you need to redraw, what you need to delete, and what can stay
}
There is still a lot of if..else, but you get the point. I suggest trying to segment your map into squares the size of your visible area.

Resources