aboutsummaryrefslogtreecommitdiffstats
path: root/examples/quick
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2023-05-30 11:52:37 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2023-06-01 11:27:56 +0200
commitb62efbe1afbec0eada19eeb66e55f68e2d129e36 (patch)
tree46c8b686ab7c5fd249d19a8574439d3d84b9713a /examples/quick
parent6bdc58c2dbeffe723e4d6ae878ad380e118104ca (diff)
Add the rhitextureitem example
fboitem, the OpenGL-based QQuickFramebufferObject example is now gone, replaced by the rhitextureitem example. It is now possible to implement a custom QQuickItem that renders into a QRhiTexture and then draws a triangle/strip geometry textured with that texture using just public Qt Quick APIs and the semi-public QRhi APIs. There should be conveniences provided for this in future Qt versions, but for the time being we provide an example how applications can do this in Qt 6.6 already. This complements the rhiunderqml example which shows the underlay/overlay approach, and the customrendernode example that shows the "inline" approach with a custom QSGRenderNode. The rhitextureitem example added here shows the third, "offscreen" approach that goes through a texture. The example docs are better than before but not yet complete. To be extended separately. Task-number: QTBUG-113331 Change-Id: I83000c08b057dd72371e2909905120dc496cb34d Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'examples/quick')
-rw-r--r--examples/quick/scenegraph/CMakeLists.txt2
-rw-r--r--examples/quick/scenegraph/fboitem/CMakeLists.txt46
-rw-r--r--examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpgbin25863 -> 0 bytes
-rw-r--r--examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc12
-rw-r--r--examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp38
-rw-r--r--examples/quick/scenegraph/fboitem/fboinsgrenderer.h19
-rw-r--r--examples/quick/scenegraph/fboitem/fboitem.pro20
-rw-r--r--examples/quick/scenegraph/fboitem/fboitem.qrc6
-rw-r--r--examples/quick/scenegraph/fboitem/shaders/checker.frag.qsbbin953 -> 0 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/CMakeLists.txt66
-rw-r--r--examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpgbin0 -> 24130 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc61
-rw-r--r--examples/quick/scenegraph/rhitextureitem/main.cpp (renamed from examples/quick/scenegraph/fboitem/main.cpp)12
-rw-r--r--examples/quick/scenegraph/rhitextureitem/main.qml (renamed from examples/quick/scenegraph/fboitem/main.qml)20
-rw-r--r--examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsbbin0 -> 1611 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.frag.qsbbin0 -> 772 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.vert.qsbbin0 -> 1738 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp443
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.h142
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro16
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc8
-rw-r--r--examples/quick/scenegraph/rhitextureitem/shaders/checker.frag (renamed from examples/quick/scenegraph/fboitem/shaders/checker.frag)11
-rw-r--r--examples/quick/scenegraph/rhitextureitem/shaders/logo.frag9
-rw-r--r--examples/quick/scenegraph/rhitextureitem/shaders/logo.vert19
-rw-r--r--examples/quick/scenegraph/scenegraph.pro6
-rw-r--r--examples/quick/scenegraph/shared/logorenderer.cpp219
-rw-r--r--examples/quick/scenegraph/shared/logorenderer.h41
27 files changed, 791 insertions, 425 deletions
diff --git a/examples/quick/scenegraph/CMakeLists.txt b/examples/quick/scenegraph/CMakeLists.txt
index 74b35f9086..156b1ed186 100644
--- a/examples/quick/scenegraph/CMakeLists.txt
+++ b/examples/quick/scenegraph/CMakeLists.txt
@@ -8,8 +8,8 @@ qt_internal_add_example(threadedanimation)
qt_internal_add_example(twotextureproviders)
qt_internal_add_example(customrendernode)
qt_internal_add_example(rhiunderqml)
+qt_internal_add_example(rhitextureitem)
if(QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3)
- qt_internal_add_example(fboitem)
qt_internal_add_example(openglunderqml)
endif()
if(IOS OR MACOS)
diff --git a/examples/quick/scenegraph/fboitem/CMakeLists.txt b/examples/quick/scenegraph/fboitem/CMakeLists.txt
deleted file mode 100644
index 371c7e31ed..0000000000
--- a/examples/quick/scenegraph/fboitem/CMakeLists.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
-
-cmake_minimum_required(VERSION 3.16)
-project(fboitem LANGUAGES CXX)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/fboitem")
-
-find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
-
-qt_standard_project_setup()
-
-qt_add_executable(fboitem WIN32 MACOSX_BUNDLE
- ../shared/logorenderer.cpp ../shared/logorenderer.h
- fboinsgrenderer.cpp fboinsgrenderer.h
- main.cpp
-)
-
-target_include_directories(fboitem PUBLIC
- ../shared
-)
-
-target_link_libraries(fboitem PRIVATE
- Qt6::Core
- Qt6::Gui
- Qt6::Qml
- Qt6::Quick
-)
-
-qt_add_qml_module(fboitem
- URI SceneGraphRendering
- QML_FILES main.qml
- RESOURCES shaders/checker.frag.qsb
- RESOURCE_PREFIX /scenegraph/fboitem
- NO_RESOURCE_TARGET_PATH
-)
-
-install(TARGETS fboitem
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg b/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg
deleted file mode 100644
index 306b8bab20..0000000000
--- a/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg
+++ /dev/null
Binary files differ
diff --git a/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc b/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc
deleted file mode 100644
index daa784bf79..0000000000
--- a/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \example scenegraph/fboitem
- \title Scene Graph - Rendering FBOs
- \ingroup qtquickexamples
-
- \brief Shows how to use FramebufferObjects with Qt Quick.
-
- \image fboitem-example.jpg
- */
diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp b/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp
deleted file mode 100644
index e4c0e61843..0000000000
--- a/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#include "fboinsgrenderer.h"
-#include "logorenderer.h"
-
-#include <QOpenGLFramebufferObject>
-
-#include <QtQuick/QQuickWindow>
-#include <qsgsimpletexturenode.h>
-
-class LogoInFboRenderer : public QQuickFramebufferObject::Renderer
-{
-public:
- LogoInFboRenderer()
- {
- logo.initialize();
- }
-
- void render() override {
- logo.render();
- update();
- }
-
- QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override {
- QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
- format.setSamples(4);
- return new QOpenGLFramebufferObject(size, format);
- }
-
- LogoRenderer logo;
-};
-
-QQuickFramebufferObject::Renderer *FboInSGRenderer::createRenderer() const
-{
- return new LogoInFboRenderer();
-}
diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
deleted file mode 100644
index c6eb745d5f..0000000000
--- a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#ifndef FBOINSGRENDERER_H
-#define FBOINSGRENDERER_H
-
-#include <QtQuick/QQuickFramebufferObject>
-
-class LogoRenderer;
-
-class FboInSGRenderer : public QQuickFramebufferObject
-{
- Q_OBJECT
- QML_NAMED_ELEMENT(Renderer)
-public:
- Renderer *createRenderer() const;
-};
-
-#endif
diff --git a/examples/quick/scenegraph/fboitem/fboitem.pro b/examples/quick/scenegraph/fboitem/fboitem.pro
deleted file mode 100644
index 180c2288e2..0000000000
--- a/examples/quick/scenegraph/fboitem/fboitem.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-QT += qml quick
-
-CONFIG += qmltypes
-QML_IMPORT_NAME = SceneGraphRendering
-QML_IMPORT_MAJOR_VERSION = 1
-
-HEADERS += fboinsgrenderer.h
-SOURCES += fboinsgrenderer.cpp main.cpp
-
-INCLUDEPATH += ../shared
-HEADERS += ../shared/logorenderer.h
-SOURCES += ../shared/logorenderer.cpp
-
-RESOURCES += fboitem.qrc
-
-target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/fboitem
-INSTALLS += target
-
-OTHER_FILES += \
- main.qml
diff --git a/examples/quick/scenegraph/fboitem/fboitem.qrc b/examples/quick/scenegraph/fboitem/fboitem.qrc
deleted file mode 100644
index 1782429798..0000000000
--- a/examples/quick/scenegraph/fboitem/fboitem.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource prefix="/scenegraph/fboitem">
- <file>main.qml</file>
- <file>shaders/checker.frag.qsb</file>
- </qresource>
-</RCC>
diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb b/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb
deleted file mode 100644
index 77cbf0b867..0000000000
--- a/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb
+++ /dev/null
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt b/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt
new file mode 100644
index 0000000000..d1ce25e313
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt
@@ -0,0 +1,66 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(rhitextureitem LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/rhitextureitem")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
+
+qt_standard_project_setup()
+
+qt_add_executable(rhitextureitem WIN32 MACOSX_BUNDLE
+ rhitextureitem.cpp rhitextureitem.h
+ main.cpp
+)
+
+target_include_directories(rhitextureitem PUBLIC
+ ../shared
+)
+
+target_link_libraries(rhitextureitem PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::GuiPrivate
+ Qt6::Qml
+ Qt6::Quick
+ Qt6::QuickPrivate
+)
+
+qt_add_qml_module(rhitextureitem
+ URI SceneGraphRendering
+ QML_FILES main.qml
+ RESOURCE_PREFIX /scenegraph/rhitextureitem
+ NO_RESOURCE_TARGET_PATH
+)
+
+qt_add_shaders(rhitextureitem "rhitextureitem_shaders"
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ /scenegraph/rhitextureitem
+ FILES
+ shaders/logo.vert
+ shaders/logo.frag
+)
+
+qt_add_shaders(rhitextureitem "rhitextureitem_effect_shaders"
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ /scenegraph/rhitextureitem
+ FILES
+ shaders/checker.frag
+)
+
+install(TARGETS rhitextureitem
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg b/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg
new file mode 100644
index 0000000000..4f50f94f04
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc
new file mode 100644
index 0000000000..97f0588314
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc
@@ -0,0 +1,61 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example scenegraph/rhitextureitem
+ \title Scene Graph - RHI Texture Item
+ \ingroup qtquickexamples
+
+ \brief Shows how to implement a custom QQuickItem that displays a QRhi-rendered texture.
+
+ \image rhitextureitem-example.jpg
+
+ This example shows how to implement an item that performs cross-platform,
+ portable 3D rendering into a texture using the QRhi APIs and then displays
+ that image.
+
+ The \l{Scene Graph - RHI Under QML}{RHI Under QML} example shows how to
+ implement portable, cross-platform 3D rendering with the \l QRhi APIs in a
+ manner where the custom rendering is issued before the Qt Quick scene
+ graph's own rendering, effectively providing an "underlay". That approach
+ is efficient since now additional render targets and render passes are
+ needed, the custom rendering is injected in the main render pass before the
+ scene graph's own draw calls.
+
+ In contrast, this example involves a separate render target (a QRhiTexture,
+ the \l{QRhiTexture::pixelSize()}{dimensions} of which match the
+ QQuickItem's size in the scene) and a whole render pass that is used to
+ clear and then draw into that texture. The texture is then used with an
+ instance of a custom QQuickItem subclass that is implemented using the \l
+ QSGSimpleTextureNode helper class.
+
+ Compared to the underlay/overlay approach, this allows displaying,
+ blending, and transforming the flattened 2D image of the 3D rendering
+ anywhere in the Qt Quick scene since here we have a true QQuickItem. This
+ comes at the expense of being more expensive in terms of resources and
+ performance since it involves rendering to a texture first.
+
+ \section1 Walkthrough
+
+ \c ExampleRhiItem is the QQuickItem subclass that is exposed to QML
+ and is instantied in the scene.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.h item
+
+ The \c angle property has a \l NumberAnimation on it, this is what drives
+ the continuous rotation of the 3D mesh.
+
+ \snippet scenegraph/rhitextureitem/main.qml 0
+
+ \c ExampleRhiItem drives from \c RhiItem, which contains the generic
+ implementation of a \l QQuickItem that maintains and displays a \l
+ QRhiTexture.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.h itembase
+
+ The corresponding scene graph node is implemented using \l
+ QSGSimpleTextureNode.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.h itemnode
+
+ */
diff --git a/examples/quick/scenegraph/fboitem/main.cpp b/examples/quick/scenegraph/rhitextureitem/main.cpp
index bbf3805002..5092552691 100644
--- a/examples/quick/scenegraph/fboitem/main.cpp
+++ b/examples/quick/scenegraph/rhitextureitem/main.cpp
@@ -1,21 +1,17 @@
-// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
-
-#include <QtQuick/QQuickView>
-
-#include "fboinsgrenderer.h"
+#include <QQuickView>
+#include "rhitextureitem.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
-
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
- view.setSource(QUrl("qrc:///scenegraph/fboitem/main.qml"));
+ view.setSource(QUrl("qrc:///scenegraph/rhitextureitem/main.qml"));
view.show();
return QGuiApplication::exec();
diff --git a/examples/quick/scenegraph/fboitem/main.qml b/examples/quick/scenegraph/rhitextureitem/main.qml
index db2df19197..5a3119c87a 100644
--- a/examples/quick/scenegraph/fboitem/main.qml
+++ b/examples/quick/scenegraph/rhitextureitem/main.qml
@@ -1,8 +1,7 @@
-// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-
import SceneGraphRendering
Item {
@@ -20,14 +19,23 @@ Item {
property size pixelSize: Qt.size(width / tileSize, height / tileSize);
- fragmentShader: "qrc:/scenegraph/fboitem/shaders/checker.frag.qsb"
+ fragmentShader: "qrc:/scenegraph/rhitextureitem/shaders/checker.frag.qsb"
}
- Renderer {
+ //! [0]
+ ExampleRhiItem {
id: renderer
anchors.fill: parent
anchors.margins: 10
+ NumberAnimation on angle {
+ from: 0
+ to: 360
+ duration: 5000
+ loops: Animation.Infinite
+ }
+ //! [0]
+
// The transform is just to show something interesting..
transform: [
Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; },
@@ -75,8 +83,6 @@ Item {
anchors.right: renderer.right
anchors.margins: 20
wrapMode: Text.WordWrap
- text: qsTr("The blue rectangle with the vintage 'Q' is an FBO, rendered by the application on the scene graph rendering thread. The FBO is managed and displayed using the QQuickFramebufferObject convenience class.")
+ text: qsTr("The blue rectangle with the vintage 'Q' is rendered by the application by directly using the QRhi APIs on the scene graph render thread. The custom QQuickItem then draws a quad textured with the QRhiTexture containing the custom 3D rendering.")
}
-
-
}
diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb
new file mode 100644
index 0000000000..31ad25de20
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.frag.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.frag.qsb
new file mode 100644
index 0000000000..9a9cbaa82d
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.vert.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.vert.qsb
new file mode 100644
index 0000000000..8626401364
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.vert.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp
new file mode 100644
index 0000000000..92615a4d5b
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp
@@ -0,0 +1,443 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "rhitextureitem.h"
+#include <QFile>
+
+RhiItemNode::RhiItemNode(RhiItem *item)
+ : m_item(item)
+{
+ m_window = m_item->window();
+ connect(m_window, &QQuickWindow::beforeRendering, this, &RhiItemNode::render,
+ Qt::DirectConnection);
+ connect(m_window, &QQuickWindow::screenChanged, this, [this]() {
+ if (m_window->effectiveDevicePixelRatio() != m_dpr)
+ m_item->update();
+ }, Qt::DirectConnection);
+}
+
+QSGTexture *RhiItemNode::texture() const
+{
+ return m_sgTexture.get();
+}
+
+void RhiItemNode::sync()
+{
+ if (!m_rhi) {
+ m_rhi = m_window->rhi();
+ if (!m_rhi) {
+ qWarning("No QRhi found for window %p, RhiItem will not be functional", m_window);
+ return;
+ }
+ }
+
+ m_dpr = m_window->effectiveDevicePixelRatio();
+ const int minTexSize = m_rhi->resourceLimit(QRhi::TextureSizeMin);
+ QSize newSize = QSize(qMax<int>(minTexSize, m_item->width()),
+ qMax<int>(minTexSize, m_item->height())) * m_dpr;
+
+ bool needsNew = !m_sgTexture;
+ if (newSize != m_pixelSize) {
+ needsNew = true;
+ m_pixelSize = newSize;
+ }
+
+ if (needsNew) {
+ QRhiTexture *texture = m_rhi->newTexture(QRhiTexture::RGBA8, m_pixelSize, 1, QRhiTexture::RenderTarget);
+ if (texture->create()) {
+ m_sgTexture.reset(m_window->createTextureFromRhiTexture(texture));
+ setTexture(m_sgTexture.get());
+ m_renderer->initialize(m_rhi, texture);
+ } else {
+ qWarning("Failed to create RhiItem texture of size %dx%d", m_pixelSize.width(), m_pixelSize.height());
+ delete texture;
+ }
+ }
+
+ m_renderer->synchronize(m_item);
+}
+
+void RhiItemNode::render()
+{
+ // called before Qt Quick starts recording its main render pass
+
+ if (!isValid() || !m_renderPending)
+ return;
+
+ QRhiSwapChain *swapchain = m_window->swapChain();
+ QSGRendererInterface *rif = m_window->rendererInterface();
+
+ // For completeness, handle both cases: on-screen QQuickWindow vs.
+ // off-screen QQuickWindow e.g. by using QQuickRenderControl to redirect
+ // into a texture. For the application's purposes just handling the first
+ // (swapchain is non-null) would be sufficient.
+ QRhiCommandBuffer *cb = swapchain ? swapchain->currentFrameCommandBuffer()
+ : static_cast<QRhiCommandBuffer *>(
+ rif->getResource(m_window, QSGRendererInterface::RhiRedirectCommandBuffer));
+
+ if (!cb) {
+ qWarning("Neither swapchain nor redirected command buffer are available.");
+ return;
+ }
+
+ m_renderPending = false;
+ m_renderer->render(cb);
+
+ markDirty(QSGNode::DirtyMaterial);
+ emit textureChanged();
+}
+
+void RhiItemNode::scheduleUpdate()
+{
+ m_renderPending = true;
+ m_window->update(); // ensure getting to beforeRendering() at some point
+}
+
+RhiItem::RhiItem(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QSGNode *RhiItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ // Changing to an empty size should not involve destroying and then later
+ // recreating the node, because we do not know how expensive the user's
+ // renderer setup is. Rather, keep the node if it already exist, and clamp
+ // all accesses to width and height. Hence the unusual !oldNode condition here.
+ if (!oldNode && (width() <= 0 || height() <= 0))
+ return nullptr;
+
+ RhiItemNode *n = static_cast<RhiItemNode *>(oldNode);
+ if (!n) {
+ if (!node)
+ node = new RhiItemNode(this);
+ if (!node->hasRenderer()) {
+ RhiItemRenderer *r = createRenderer();
+ if (r) {
+ r->data = node;
+ node->setRenderer(r);
+ } else {
+ qWarning("No RhiItemRenderer was created; the item will not render");
+ delete node;
+ node = nullptr;
+ return nullptr;
+ }
+ }
+ n = node;
+ }
+
+ n->sync();
+
+ if (!n->isValid()) {
+ delete n;
+ node = nullptr;
+ return nullptr;
+ }
+
+ if (window()->rhi()->isYUpInFramebuffer())
+ n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
+
+ n->setFiltering(QSGTexture::Linear);
+ n->setRect(0, 0, qMax<int>(0, width()), qMax<int>(0, height()));
+
+ n->scheduleUpdate();
+
+ return n;
+}
+
+void RhiItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickItem::geometryChange(newGeometry, oldGeometry);
+ if (newGeometry.size() != oldGeometry.size())
+ update();
+}
+
+void RhiItem::releaseResources()
+{
+ // called on the gui thread if the item is removed from scene
+
+ node = nullptr;
+}
+
+void RhiItem::invalidateSceneGraph()
+{
+ // called on the render thread when the scenegraph is invalidated
+
+ node = nullptr;
+}
+
+bool RhiItem::isTextureProvider() const
+{
+ return true;
+}
+
+QSGTextureProvider *RhiItem::textureProvider() const
+{
+ if (QQuickItem::isTextureProvider()) // e.g. if Item::layer::enabled == true
+ return QQuickItem::textureProvider();
+
+ if (!node) // create a node to have a provider, the texture will be null but that's ok
+ node = new RhiItemNode(const_cast<RhiItem *>(this));
+
+ return node;
+}
+
+void RhiItemRenderer::update()
+{
+ if (data)
+ static_cast<RhiItemNode *>(data)->scheduleUpdate();
+}
+
+RhiItemRenderer *ExampleRhiItem::createRenderer()
+{
+ return new ExampleRhiItemRenderer;
+}
+
+void ExampleRhiItem::setAngle(float a)
+{
+ if (m_angle == a)
+ return;
+
+ m_angle = a;
+ emit angleChanged();
+ update();
+}
+
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ return QShader();
+}
+
+void ExampleRhiItemRenderer::initialize(QRhi *rhi, QRhiTexture *outputTexture)
+{
+ m_rhi = rhi;
+
+ if (m_output && m_output != outputTexture) {
+ m_rt.reset();
+ m_rp.reset();
+ }
+
+ m_output = outputTexture;
+
+ if (!m_ds) {
+ m_ds.reset(m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, m_output->pixelSize()));
+ m_ds->create();
+ } else if (m_ds->pixelSize() != m_output->pixelSize()) {
+ m_ds->setPixelSize(m_output->pixelSize());
+ m_ds->create();
+ }
+
+ if (!m_rt) {
+ m_rt.reset(m_rhi->newTextureRenderTarget({ { m_output }, m_ds.get() }));
+ m_rp.reset(m_rt->newCompatibleRenderPassDescriptor());
+ m_rt->setRenderPassDescriptor(m_rp.get());
+ m_rt->create();
+ }
+
+ if (!scene.vbuf) {
+ createGeometry();
+
+ const quint32 vsize = m_vertices.size() * 3 * sizeof(float);
+ const quint32 nsize = m_normals.size() * 3 * sizeof(float);
+ const quint32 vbufSize = vsize + nsize;
+ scene.vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, vbufSize));
+ scene.vbuf->create();
+
+ scene.resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ scene.resourceUpdates->uploadStaticBuffer(scene.vbuf.get(), 0, vsize, m_vertices.constData());
+ scene.resourceUpdates->uploadStaticBuffer(scene.vbuf.get(), vsize, nsize, m_normals.constData());
+
+ scene.ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64));
+ scene.ubuf->create();
+
+ scene.srb.reset(m_rhi->newShaderResourceBindings());
+ scene.srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, scene.ubuf.get()),
+ });
+ scene.srb->create();
+
+ scene.ps.reset(m_rhi->newGraphicsPipeline());
+ scene.ps->setDepthTest(true);
+ scene.ps->setDepthWrite(true);
+ scene.ps->setShaderStages({
+ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/logo.vert.qsb")) },
+ { QRhiShaderStage::Fragment, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/logo.frag.qsb")) }
+ });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 3 * sizeof(float) },
+ { 3 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
+ { 1, 1, QRhiVertexInputAttribute::Float3, 0 }
+ });
+ scene.ps->setVertexInputLayout(inputLayout);
+ scene.ps->setShaderResourceBindings(scene.srb.get());
+ scene.ps->setRenderPassDescriptor(m_rp.get());
+ scene.ps->create();
+ }
+}
+
+void ExampleRhiItemRenderer::synchronize(RhiItem *rhiItem)
+{
+ // called on the render thread (if there is one), while the main (gui) thread is blocked
+
+ ExampleRhiItem *item = static_cast<ExampleRhiItem *>(rhiItem);
+ if (item->angle() != scene.logoAngle)
+ scene.logoAngle = item->angle();
+}
+
+void ExampleRhiItemRenderer::render(QRhiCommandBuffer *cb)
+{
+ QRhiResourceUpdateBatch *rub = scene.resourceUpdates;
+ if (rub)
+ scene.resourceUpdates = nullptr;
+ else
+ rub = m_rhi->nextResourceUpdateBatch();
+
+ const QMatrix4x4 matrix = m_rhi->clipSpaceCorrMatrix() * calculateModelViewMatrix();
+ rub->updateDynamicBuffer(scene.ubuf.get(), 0, 64, matrix.constData());
+
+ const QColor clearColor = QColor::fromRgbF(0.5f, 0.5f, 0.7f, 1.0f);
+ cb->beginPass(m_rt.get(), clearColor, { 1.0f, 0 }, rub);
+
+ cb->setGraphicsPipeline(scene.ps.get());
+ const QSize outputSize = m_output->pixelSize();
+ cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBindings[] = {
+ { scene.vbuf.get(), 0 },
+ { scene.vbuf.get(), quint32(m_vertices.size() * 3 * sizeof(float)) }
+ };
+ cb->setVertexInput(0, 2, vbufBindings);
+ cb->draw(m_vertices.size());
+
+ cb->endPass();
+}
+
+void ExampleRhiItemRenderer::createGeometry()
+{
+ m_vertices.clear();
+ m_normals.clear();
+
+ qreal x1 = +0.06f;
+ qreal y1 = -0.14f;
+ qreal x2 = +0.14f;
+ qreal y2 = -0.06f;
+ qreal x3 = +0.08f;
+ qreal y3 = +0.00f;
+ qreal x4 = +0.30f;
+ qreal y4 = +0.22f;
+
+ quad(x1, y1, x2, y2, y2, x2, y1, x1);
+ quad(x3, y3, x4, y4, y4, x4, y3, x3);
+
+ extrude(x1, y1, x2, y2);
+ extrude(x2, y2, y2, x2);
+ extrude(y2, x2, y1, x1);
+ extrude(y1, x1, x1, y1);
+ extrude(x3, y3, x4, y4);
+ extrude(x4, y4, y4, x4);
+ extrude(y4, x4, y3, x3);
+
+ const qreal Pi = M_PI;
+ const int NumSectors = 100;
+
+ for (int i = 0; i < NumSectors; ++i) {
+ qreal angle1 = (i * 2 * Pi) / NumSectors;
+ qreal x5 = 0.30 * sin(angle1);
+ qreal y5 = 0.30 * cos(angle1);
+ qreal x6 = 0.20 * sin(angle1);
+ qreal y6 = 0.20 * cos(angle1);
+
+ qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors;
+ qreal x7 = 0.20 * sin(angle2);
+ qreal y7 = 0.20 * cos(angle2);
+ qreal x8 = 0.30 * sin(angle2);
+ qreal y8 = 0.30 * cos(angle2);
+
+ quad(x5, y5, x6, y6, x7, y7, x8, y8);
+
+ extrude(x6, y6, x7, y7);
+ extrude(x8, y8, x5, y5);
+ }
+
+ for (int i = 0; i < m_vertices.size(); i++)
+ m_vertices[i] *= 2.0f;
+}
+
+void ExampleRhiItemRenderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4)
+{
+ m_vertices << QVector3D(x1, y1, -0.05f);
+ m_vertices << QVector3D(x2, y2, -0.05f);
+ m_vertices << QVector3D(x4, y4, -0.05f);
+
+ m_vertices << QVector3D(x3, y3, -0.05f);
+ m_vertices << QVector3D(x4, y4, -0.05f);
+ m_vertices << QVector3D(x2, y2, -0.05f);
+
+ QVector3D n = QVector3D::normal(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f));
+
+ m_normals << n;
+ m_normals << n;
+ m_normals << n;
+
+ m_normals << n;
+ m_normals << n;
+ m_normals << n;
+
+ m_vertices << QVector3D(x4, y4, 0.05f);
+ m_vertices << QVector3D(x2, y2, 0.05f);
+ m_vertices << QVector3D(x1, y1, 0.05f);
+
+ m_vertices << QVector3D(x2, y2, 0.05f);
+ m_vertices << QVector3D(x4, y4, 0.05f);
+ m_vertices << QVector3D(x3, y3, 0.05f);
+
+ n = QVector3D::normal(QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f));
+
+ m_normals << n;
+ m_normals << n;
+ m_normals << n;
+
+ m_normals << n;
+ m_normals << n;
+ m_normals << n;
+}
+
+void ExampleRhiItemRenderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2)
+{
+ m_vertices << QVector3D(x1, y1, +0.05f);
+ m_vertices << QVector3D(x2, y2, +0.05f);
+ m_vertices << QVector3D(x1, y1, -0.05f);
+
+ m_vertices << QVector3D(x2, y2, -0.05f);
+ m_vertices << QVector3D(x1, y1, -0.05f);
+ m_vertices << QVector3D(x2, y2, +0.05f);
+
+ QVector3D n = QVector3D::normal(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f));
+
+ m_normals << n;
+ m_normals << n;
+ m_normals << n;
+
+ m_normals << n;
+ m_normals << n;
+ m_normals << n;
+}
+
+QMatrix4x4 ExampleRhiItemRenderer::calculateModelViewMatrix() const
+{
+ QMatrix4x4 modelview;
+ modelview.rotate(scene.logoAngle, 0.0f, 1.0f, 0.0f);
+ modelview.rotate(scene.logoAngle, 1.0f, 0.0f, 0.0f);
+ modelview.rotate(scene.logoAngle, 0.0f, 0.0f, 1.0f);
+ modelview.translate(0.0f, -0.2f, 0.0f);
+ return modelview;
+}
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h
new file mode 100644
index 0000000000..d32ef34f11
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h
@@ -0,0 +1,142 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef RHITEXTUREITEM_H
+#define RHITEXTUREITEM_H
+
+#include <QQuickItem>
+#include <QSGSimpleTextureNode>
+#include <QSGTextureProvider>
+#include <rhi/qrhi.h>
+
+class LogoRenderer;
+class RhiItem;
+class RhiItemNode;
+
+QT_FORWARD_DECLARE_CLASS(QSGPlainTexture)
+
+class RhiItemRenderer
+{
+public:
+ virtual ~RhiItemRenderer() { }
+ virtual void initialize(QRhi *rhi, QRhiTexture *outputTexture) = 0;
+ virtual void synchronize(RhiItem *item) = 0;
+ virtual void render(QRhiCommandBuffer *cb) = 0;
+
+ void update();
+
+private:
+ void *data;
+ friend class RhiItem;
+};
+
+//! [itembase]
+class RhiItem : public QQuickItem
+{
+ Q_OBJECT
+public:
+ RhiItem(QQuickItem *parent = nullptr);
+
+ virtual RhiItemRenderer *createRenderer() = 0;
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void releaseResources() override;
+ bool isTextureProvider() const override;
+ QSGTextureProvider *textureProvider() const override;
+
+private Q_SLOTS:
+ void invalidateSceneGraph();
+
+private:
+ mutable RhiItemNode *node = nullptr;
+};
+//! [itembase]
+
+//! [itemnode]
+class RhiItemNode : public QSGTextureProvider, public QSGSimpleTextureNode
+//! [itemnode]
+{
+ Q_OBJECT
+
+public:
+ RhiItemNode(RhiItem *item);
+
+ QSGTexture *texture() const override;
+
+ void sync();
+ bool isValid() const { return m_rhi && m_sgTexture; }
+ void scheduleUpdate();
+ bool hasRenderer() const { return m_renderer != nullptr; }
+ void setRenderer(RhiItemRenderer *r) { m_renderer.reset(r); }
+ void setMirrorVertically(bool b);
+
+private slots:
+ void render();
+
+private:
+ RhiItem *m_item;
+ QQuickWindow *m_window;
+ QSize m_pixelSize;
+ qreal m_dpr = 0.0f;
+ QRhi *m_rhi = nullptr;
+ bool m_renderPending = true;
+ std::unique_ptr<QSGTexture> m_sgTexture;
+ std::unique_ptr<RhiItemRenderer> m_renderer;
+};
+
+//! [item]
+class ExampleRhiItem : public RhiItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ExampleRhiItem)
+ Q_PROPERTY(float angle READ angle WRITE setAngle NOTIFY angleChanged)
+
+public:
+ float angle() const { return m_angle; }
+ void setAngle(float a);
+
+ RhiItemRenderer *createRenderer() override;
+
+signals:
+ void angleChanged();
+
+private:
+ float m_angle = 0.0f;
+};
+//! [item]
+
+class ExampleRhiItemRenderer : public RhiItemRenderer
+{
+public:
+ void initialize(QRhi *rhi, QRhiTexture *outputTexture) override;
+ void synchronize(RhiItem *item) override;
+ void render(QRhiCommandBuffer *cb) override;
+
+private:
+ QRhi *m_rhi = nullptr;
+ QRhiTexture *m_output = nullptr;
+ std::unique_ptr<QRhiRenderBuffer> m_ds;
+ std::unique_ptr<QRhiTextureRenderTarget> m_rt;
+ std::unique_ptr<QRhiRenderPassDescriptor> m_rp;
+
+ struct {
+ QRhiResourceUpdateBatch *resourceUpdates = nullptr;
+ std::unique_ptr<QRhiBuffer> vbuf;
+ std::unique_ptr<QRhiBuffer> ubuf;
+ std::unique_ptr<QRhiShaderResourceBindings> srb;
+ std::unique_ptr<QRhiGraphicsPipeline> ps;
+ float logoAngle = 0.0f;
+ } scene;
+
+ void createGeometry();
+ void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4);
+ void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
+ QMatrix4x4 calculateModelViewMatrix() const;
+
+ QList<QVector3D> m_vertices;
+ QList<QVector3D> m_normals;
+};
+
+#endif
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro
new file mode 100644
index 0000000000..4d5c132a42
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro
@@ -0,0 +1,16 @@
+QT += gui-private qml quick
+
+CONFIG += qmltypes
+QML_IMPORT_NAME = SceneGraphRendering
+QML_IMPORT_MAJOR_VERSION = 1
+
+HEADERS += rhitextureitem.h
+SOURCES += rhitextureitem.cpp main.cpp
+
+RESOURCES += rhitextureitem.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/rhitextureitem
+INSTALLS += target
+
+OTHER_FILES += \
+ main.qml
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc
new file mode 100644
index 0000000000..c507ac33c2
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/scenegraph/rhitextureitem">
+ <file>main.qml</file>
+ <file alias="shaders/logo.vert.qsb">prebuilts_for_qmake/logo.vert.qsb</file>
+ <file alias="shaders/logo.frag.qsb">prebuilts_for_qmake/logo.frag.qsb</file>
+ <file alias="shaders/checker.frag.qsb">prebuilts_for_qmake/checker.frag.qsb</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag b/examples/quick/scenegraph/rhitextureitem/shaders/checker.frag
index 1e4131d026..d62eceec8f 100644
--- a/examples/quick/scenegraph/fboitem/shaders/checker.frag
+++ b/examples/quick/scenegraph/rhitextureitem/shaders/checker.frag
@@ -1,22 +1,23 @@
#version 440
layout(std140, binding = 0) uniform buf {
+ // built-in Qt data
mat4 qt_Matrix;
float qt_Opacity;
-
+ // custom data
vec4 color1;
vec4 color2;
vec2 pixelSize;
-} ubuf;
+};
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
void main()
{
- vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * ubuf.pixelSize));
+ vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize));
if (tc.x != tc.y)
- fragColor = ubuf.color1;
+ fragColor = color1;
else
- fragColor = ubuf.color2;
+ fragColor = color2;
}
diff --git a/examples/quick/scenegraph/rhitextureitem/shaders/logo.frag b/examples/quick/scenegraph/rhitextureitem/shaders/logo.frag
new file mode 100644
index 0000000000..1e2101776d
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/shaders/logo.frag
@@ -0,0 +1,9 @@
+#version 440
+
+layout(location = 0) in vec4 v_color;
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ fragColor = v_color;
+}
diff --git a/examples/quick/scenegraph/rhitextureitem/shaders/logo.vert b/examples/quick/scenegraph/rhitextureitem/shaders/logo.vert
new file mode 100644
index 0000000000..5a2aa7f504
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/shaders/logo.vert
@@ -0,0 +1,19 @@
+#version 440
+
+layout(location = 0) in vec4 vertex;
+layout(location = 1) in vec3 normal;
+
+layout(location = 0) out vec4 v_color;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 matrix;
+};
+
+void main()
+{
+ vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));
+ float angle = max(dot(normal, toLight), 0.0);
+ vec3 col = vec3(0.40, 1.0, 0.0);
+ v_color = clamp(vec4(col * 0.2 + col * 0.8 * angle, 1.0), 0.0, 1.0);
+ gl_Position = matrix * vertex;
+}
diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro
index 85dd7bd439..c37e822680 100644
--- a/examples/quick/scenegraph/scenegraph.pro
+++ b/examples/quick/scenegraph/scenegraph.pro
@@ -2,8 +2,7 @@ TEMPLATE = subdirs
qtConfig(opengl(es1|es2)?) {
SUBDIRS += \
- fboitem \
- openglunderqml \
+ openglunderqml
}
SUBDIRS += \
@@ -12,7 +11,8 @@ SUBDIRS += \
graph \
threadedanimation \
twotextureproviders \
- rhiunderqml
+ rhiunderqml \
+ rhitextureitem
macos|ios {
SUBDIRS += \
diff --git a/examples/quick/scenegraph/shared/logorenderer.cpp b/examples/quick/scenegraph/shared/logorenderer.cpp
deleted file mode 100644
index b95ae0d21d..0000000000
--- a/examples/quick/scenegraph/shared/logorenderer.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#include "logorenderer.h"
-#include <QPainter>
-#include <QPaintEngine>
-#include <qmath.h>
-
-LogoRenderer::LogoRenderer()
-{
-}
-
-LogoRenderer::~LogoRenderer()
-{
-}
-
-
-void LogoRenderer::paintQtLogo()
-{
- program1.enableAttributeArray(normalAttr1);
- program1.enableAttributeArray(vertexAttr1);
- program1.setAttributeArray(vertexAttr1, vertices.constData());
- program1.setAttributeArray(normalAttr1, normals.constData());
- glDrawArrays(GL_TRIANGLES, 0, vertices.size());
- program1.disableAttributeArray(normalAttr1);
- program1.disableAttributeArray(vertexAttr1);
-}
-
-
-void LogoRenderer::initialize()
-{
- initializeOpenGLFunctions();
-
- glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
-
- const char *vsrc1 =
- "attribute highp vec4 vertex;\n"
- "attribute mediump vec3 normal;\n"
- "uniform mediump mat4 matrix;\n"
- "varying mediump vec4 color;\n"
- "void main(void)\n"
- "{\n"
- " vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n"
- " float angle = max(dot(normal, toLight), 0.0);\n"
- " vec3 col = vec3(0.40, 1.0, 0.0);\n"
- " color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n"
- " color = clamp(color, 0.0, 1.0);\n"
- " gl_Position = matrix * vertex;\n"
- "}\n";
-
- const char *fsrc1 =
- "varying mediump vec4 color;\n"
- "void main(void)\n"
- "{\n"
- " gl_FragColor = color;\n"
- "}\n";
-
- program1.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vsrc1);
- program1.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fsrc1);
- program1.link();
-
- vertexAttr1 = program1.attributeLocation("vertex");
- normalAttr1 = program1.attributeLocation("normal");
- matrixUniform1 = program1.uniformLocation("matrix");
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
- m_fAngle = 0;
- m_fScale = 1;
- createGeometry();
-}
-
-void LogoRenderer::render()
-{
- glDepthMask(true);
-
- glClearColor(0.5f, 0.5f, 0.7f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
- glFrontFace(GL_CW);
- glCullFace(GL_FRONT);
- glEnable(GL_CULL_FACE);
- glEnable(GL_DEPTH_TEST);
-
- QMatrix4x4 modelview;
- modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
- modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
- modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
- modelview.scale(m_fScale);
- modelview.translate(0.0f, -0.2f, 0.0f);
-
- program1.bind();
- program1.setUniformValue(matrixUniform1, modelview);
- paintQtLogo();
- program1.release();
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
-
- m_fAngle += 1.0f;
-}
-
-void LogoRenderer::createGeometry()
-{
- vertices.clear();
- normals.clear();
-
- qreal x1 = +0.06f;
- qreal y1 = -0.14f;
- qreal x2 = +0.14f;
- qreal y2 = -0.06f;
- qreal x3 = +0.08f;
- qreal y3 = +0.00f;
- qreal x4 = +0.30f;
- qreal y4 = +0.22f;
-
- quad(x1, y1, x2, y2, y2, x2, y1, x1);
- quad(x3, y3, x4, y4, y4, x4, y3, x3);
-
- extrude(x1, y1, x2, y2);
- extrude(x2, y2, y2, x2);
- extrude(y2, x2, y1, x1);
- extrude(y1, x1, x1, y1);
- extrude(x3, y3, x4, y4);
- extrude(x4, y4, y4, x4);
- extrude(y4, x4, y3, x3);
-
- const qreal Pi = M_PI;
- const int NumSectors = 100;
-
- for (int i = 0; i < NumSectors; ++i) {
- qreal angle1 = (i * 2 * Pi) / NumSectors;
- qreal x5 = 0.30 * sin(angle1);
- qreal y5 = 0.30 * cos(angle1);
- qreal x6 = 0.20 * sin(angle1);
- qreal y6 = 0.20 * cos(angle1);
-
- qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors;
- qreal x7 = 0.20 * sin(angle2);
- qreal y7 = 0.20 * cos(angle2);
- qreal x8 = 0.30 * sin(angle2);
- qreal y8 = 0.30 * cos(angle2);
-
- quad(x5, y5, x6, y6, x7, y7, x8, y8);
-
- extrude(x6, y6, x7, y7);
- extrude(x8, y8, x5, y5);
- }
-
- for (int i = 0;i < vertices.size();i++)
- vertices[i] *= 2.0f;
-}
-
-void LogoRenderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4)
-{
- vertices << QVector3D(x1, y1, -0.05f);
- vertices << QVector3D(x2, y2, -0.05f);
- vertices << QVector3D(x4, y4, -0.05f);
-
- vertices << QVector3D(x3, y3, -0.05f);
- vertices << QVector3D(x4, y4, -0.05f);
- vertices << QVector3D(x2, y2, -0.05f);
-
- QVector3D n = QVector3D::normal
- (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f));
-
- normals << n;
- normals << n;
- normals << n;
-
- normals << n;
- normals << n;
- normals << n;
-
- vertices << QVector3D(x4, y4, 0.05f);
- vertices << QVector3D(x2, y2, 0.05f);
- vertices << QVector3D(x1, y1, 0.05f);
-
- vertices << QVector3D(x2, y2, 0.05f);
- vertices << QVector3D(x4, y4, 0.05f);
- vertices << QVector3D(x3, y3, 0.05f);
-
- n = QVector3D::normal
- (QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f));
-
- normals << n;
- normals << n;
- normals << n;
-
- normals << n;
- normals << n;
- normals << n;
-}
-
-void LogoRenderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2)
-{
- vertices << QVector3D(x1, y1, +0.05f);
- vertices << QVector3D(x2, y2, +0.05f);
- vertices << QVector3D(x1, y1, -0.05f);
-
- vertices << QVector3D(x2, y2, -0.05f);
- vertices << QVector3D(x1, y1, -0.05f);
- vertices << QVector3D(x2, y2, +0.05f);
-
- QVector3D n = QVector3D::normal
- (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f));
-
- normals << n;
- normals << n;
- normals << n;
-
- normals << n;
- normals << n;
- normals << n;
-}
diff --git a/examples/quick/scenegraph/shared/logorenderer.h b/examples/quick/scenegraph/shared/logorenderer.h
deleted file mode 100644
index 06c49baab1..0000000000
--- a/examples/quick/scenegraph/shared/logorenderer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#ifndef LOGORENDERER_H
-#define LOGORENDERER_H
-
-#include <QtGui/qvector3d.h>
-#include <QtGui/qmatrix4x4.h>
-#include <qopenglshaderprogram.h>
-#include <qopenglfunctions.h>
-
-#include <QTime>
-#include <QList>
-
-class LogoRenderer : protected QOpenGLFunctions
-{
-public:
- LogoRenderer();
- ~LogoRenderer();
-
- void render();
- void initialize();
-
-private:
-
- qreal m_fAngle;
- qreal m_fScale;
-
- void paintQtLogo();
- void createGeometry();
- void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4);
- void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
-
- QList<QVector3D> vertices;
- QList<QVector3D> normals;
- QOpenGLShaderProgram program1;
- int vertexAttr1;
- int normalAttr1;
- int matrixUniform1;
-};
-#endif