summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/corelib/ipc/localfortuneclient/client.cpp67
-rw-r--r--examples/corelib/ipc/localfortuneclient/client.h13
-rw-r--r--examples/corelib/ipc/localfortuneclient/main.cpp1
-rw-r--r--examples/corelib/ipc/localfortuneserver/main.cpp2
-rw-r--r--examples/corelib/ipc/localfortuneserver/server.cpp36
-rw-r--r--examples/corelib/ipc/localfortuneserver/server.h4
-rw-r--r--examples/corelib/json/savegame/character.cpp28
-rw-r--r--examples/corelib/json/savegame/character.h6
-rw-r--r--examples/corelib/json/savegame/doc/src/savegame.qdoc37
-rw-r--r--examples/corelib/json/savegame/game.cpp86
-rw-r--r--examples/corelib/json/savegame/game.h12
-rw-r--r--examples/corelib/json/savegame/level.cpp44
-rw-r--r--examples/corelib/json/savegame/level.h16
-rw-r--r--examples/corelib/json/savegame/main.cpp28
-rw-r--r--examples/corelib/threads/queuedcustomtype/main.cpp1
-rw-r--r--examples/corelib/threads/queuedcustomtype/renderthread.cpp6
-rw-r--r--examples/corelib/threads/semaphores/semaphores.cpp3
-rw-r--r--examples/corelib/threads/waitconditions/waitconditions.cpp4
-rw-r--r--examples/corelib/tools/contiguouscache/randomlistmodel.cpp3
-rw-r--r--examples/dbus/remotecontrolledcar/car/car.cpp8
-rw-r--r--examples/embedded/flickable/main.cpp2
-rw-r--r--examples/embedded/lightmaps/lightmaps.cpp6
-rw-r--r--examples/embedded/lightmaps/slippymap.cpp14
-rw-r--r--examples/embedded/raycasting/raycasting.cpp7
-rw-r--r--examples/examples.pro7
-rw-r--r--examples/network/broadcastreceiver/receiver.cpp14
-rw-r--r--examples/network/broadcastreceiver/receiver.h11
-rw-r--r--examples/network/broadcastsender/sender.cpp22
-rw-r--r--examples/network/broadcastsender/sender.h19
-rw-r--r--examples/network/doc/images/http-example.pngbin7006 -> 8099 bytes
-rw-r--r--examples/network/download/main.cpp58
-rw-r--r--examples/network/downloadmanager/downloadmanager.cpp58
-rw-r--r--examples/network/downloadmanager/downloadmanager.h23
-rw-r--r--examples/network/downloadmanager/main.cpp8
-rw-r--r--examples/network/downloadmanager/textprogressbar.cpp13
-rw-r--r--examples/network/downloadmanager/textprogressbar.h10
-rw-r--r--examples/network/fortuneclient/client.cpp19
-rw-r--r--examples/network/fortuneclient/client.h18
-rw-r--r--examples/network/fortuneclient/main.cpp4
-rw-r--r--examples/network/fortuneserver/main.cpp8
-rw-r--r--examples/network/fortuneserver/server.cpp79
-rw-r--r--examples/network/fortuneserver/server.h15
-rw-r--r--examples/network/googlesuggest/googlesuggest.cpp36
-rw-r--r--examples/network/googlesuggest/googlesuggest.h19
-rw-r--r--examples/network/googlesuggest/main.cpp6
-rw-r--r--examples/network/googlesuggest/searchbox.cpp8
-rw-r--r--examples/network/googlesuggest/searchbox.h6
-rw-r--r--examples/network/http/httpwindow.cpp46
-rw-r--r--examples/network/http/httpwindow.h8
-rw-r--r--examples/network/multicastreceiver/receiver.cpp38
-rw-r--r--examples/network/multicastreceiver/receiver.h12
-rw-r--r--examples/network/multicastsender/sender.cpp41
-rw-r--r--examples/network/multicastsender/sender.h32
-rw-r--r--examples/network/securesocketclient/certificateinfo.cpp22
-rw-r--r--examples/network/securesocketclient/certificateinfo.h13
-rw-r--r--examples/network/securesocketclient/certificateinfo.ui2
-rw-r--r--examples/network/securesocketclient/main.cpp7
-rw-r--r--examples/network/securesocketclient/securesocketclient.pro2
-rw-r--r--examples/network/securesocketclient/sslclient.cpp168
-rw-r--r--examples/network/securesocketclient/sslclient.h25
-rw-r--r--examples/network/securesocketclient/sslclient.ui10
-rw-r--r--examples/network/threadedfortuneserver/fortuneserver.cpp4
-rw-r--r--examples/network/threadedfortuneserver/main.cpp1
-rw-r--r--examples/network/torrent/main.cpp1
-rw-r--r--examples/network/torrent/torrentclient.cpp22
-rw-r--r--examples/opengl/hellowindow/hellowindow.cpp34
-rw-r--r--examples/opengl/hellowindow/hellowindow.h2
-rw-r--r--examples/opengl/legacy/framebufferobject2/glwidget.cpp5
-rw-r--r--examples/opengl/legacy/grabber/glwidget.cpp16
-rw-r--r--examples/opengl/legacy/overpainting/bubble.cpp10
-rw-r--r--examples/opengl/legacy/overpainting/glwidget.cpp12
-rw-r--r--examples/opengl/legacy/pbuffers2/glwidget.cpp35
-rw-r--r--examples/opengl/legacy/samplebuffers/glwidget.cpp26
-rw-r--r--examples/opengl/qopenglwidget/bubble.cpp8
-rw-r--r--examples/opengl/qopenglwidget/glwidget.cpp43
-rw-r--r--examples/opengl/qopenglwidget/main.cpp4
-rw-r--r--examples/opengl/qopenglwidget/mainwindow.cpp5
-rw-r--r--examples/opengl/qopenglwindow/background.frag2
-rw-r--r--examples/opengl/threadedqopenglwidget/glwidget.cpp26
-rw-r--r--examples/sql/doc/src/drilldown.qdoc2
-rw-r--r--examples/touch/pinchzoom/main.cpp1
-rw-r--r--examples/touch/pinchzoom/mouse.cpp30
-rw-r--r--examples/vulkan/doc/images/hellovulkancubes.pngbin0 -> 98495 bytes
-rw-r--r--examples/vulkan/doc/images/hellovulkantexture.pngbin0 -> 10259 bytes
-rw-r--r--examples/vulkan/doc/images/hellovulkantriangle.pngbin0 -> 30952 bytes
-rw-r--r--examples/vulkan/doc/images/hellovulkanwidget.pngbin0 -> 25256 bytes
-rw-r--r--examples/vulkan/doc/images/hellovulkanwindow.pngbin0 -> 2736 bytes
-rw-r--r--examples/vulkan/doc/src/hellovulkancubes.qdoc58
-rw-r--r--examples/vulkan/doc/src/hellovulkantexture.qdoc (renamed from examples/widgets/doc/src/appchooser.qdoc)19
-rw-r--r--examples/vulkan/doc/src/hellovulkantriangle.qdoc49
-rw-r--r--examples/vulkan/doc/src/hellovulkanwidget.qdoc (renamed from examples/widgets/doc/src/lighting.qdoc)26
-rw-r--r--examples/vulkan/doc/src/hellovulkanwindow.qdoc101
-rw-r--r--examples/vulkan/hellovulkancubes/camera.cpp112
-rw-r--r--examples/vulkan/hellovulkancubes/camera.h (renamed from examples/widgets/effects/lighting/main.cpp)37
-rw-r--r--examples/vulkan/hellovulkancubes/color.frag12
-rw-r--r--examples/vulkan/hellovulkancubes/color.vert14
-rw-r--r--examples/vulkan/hellovulkancubes/color_frag.spvbin0 -> 616 bytes
-rw-r--r--examples/vulkan/hellovulkancubes/color_phong.frag39
-rw-r--r--examples/vulkan/hellovulkancubes/color_phong.vert32
-rw-r--r--examples/vulkan/hellovulkancubes/color_phong_frag.spvbin0 -> 3364 bytes
-rw-r--r--examples/vulkan/hellovulkancubes/color_phong_vert.spvbin0 -> 2268 bytes
-rw-r--r--examples/vulkan/hellovulkancubes/color_vert.spvbin0 -> 744 bytes
-rw-r--r--examples/vulkan/hellovulkancubes/hellovulkancubes.pro24
-rw-r--r--examples/vulkan/hellovulkancubes/hellovulkancubes.qrc10
-rw-r--r--examples/vulkan/hellovulkancubes/main.cpp92
-rw-r--r--examples/vulkan/hellovulkancubes/mainwindow.cpp117
-rw-r--r--examples/vulkan/hellovulkancubes/mainwindow.h83
-rw-r--r--examples/vulkan/hellovulkancubes/mesh.cpp98
-rw-r--r--examples/vulkan/hellovulkancubes/mesh.h (renamed from examples/widgets/effects/lighting/lighting.h)43
-rw-r--r--examples/vulkan/hellovulkancubes/renderer.cpp1048
-rw-r--r--examples/vulkan/hellovulkancubes/renderer.h158
-rw-r--r--examples/vulkan/hellovulkancubes/shader.cpp94
-rw-r--r--examples/vulkan/hellovulkancubes/shader.h77
-rw-r--r--examples/vulkan/hellovulkancubes/vulkanwindow.cpp134
-rw-r--r--examples/vulkan/hellovulkancubes/vulkanwindow.h85
-rw-r--r--examples/vulkan/hellovulkantexture/hellovulkantexture.cpp829
-rw-r--r--examples/vulkan/hellovulkantexture/hellovulkantexture.h108
-rw-r--r--examples/vulkan/hellovulkantexture/hellovulkantexture.pro7
-rw-r--r--examples/vulkan/hellovulkantexture/hellovulkantexture.qrc7
-rw-r--r--examples/vulkan/hellovulkantexture/main.cpp91
-rw-r--r--examples/vulkan/hellovulkantexture/qt256.pngbin0 -> 6208 bytes
-rw-r--r--examples/vulkan/hellovulkantexture/texture.frag12
-rw-r--r--examples/vulkan/hellovulkantexture/texture.vert18
-rw-r--r--examples/vulkan/hellovulkantexture/texture_frag.spvbin0 -> 556 bytes
-rw-r--r--examples/vulkan/hellovulkantexture/texture_vert.spvbin0 -> 968 bytes
-rw-r--r--examples/vulkan/hellovulkantriangle/hellovulkantriangle.pro12
-rw-r--r--examples/vulkan/hellovulkantriangle/hellovulkantriangle.qrc6
-rw-r--r--examples/vulkan/hellovulkantriangle/main.cpp100
-rw-r--r--examples/vulkan/hellovulkanwidget/hellovulkanwidget.cpp185
-rw-r--r--examples/vulkan/hellovulkanwidget/hellovulkanwidget.h100
-rw-r--r--examples/vulkan/hellovulkanwidget/hellovulkanwidget.pro16
-rw-r--r--examples/vulkan/hellovulkanwidget/hellovulkanwidget.qrc6
-rw-r--r--examples/vulkan/hellovulkanwidget/main.cpp112
-rw-r--r--examples/vulkan/hellovulkanwindow/hellovulkanwindow.cpp128
-rw-r--r--examples/vulkan/hellovulkanwindow/hellovulkanwindow.h77
-rw-r--r--examples/vulkan/hellovulkanwindow/hellovulkanwindow.pro6
-rw-r--r--examples/vulkan/hellovulkanwindow/main.cpp93
-rw-r--r--examples/vulkan/shared/block.bufbin0 -> 4256 bytes
-rw-r--r--examples/vulkan/shared/block.txt100
-rw-r--r--examples/vulkan/shared/color.frag10
-rw-r--r--examples/vulkan/shared/color.vert18
-rw-r--r--examples/vulkan/shared/color_frag.spvbin0 -> 496 bytes
-rw-r--r--examples/vulkan/shared/color_vert.spvbin0 -> 960 bytes
-rw-r--r--examples/vulkan/shared/objconvert.js241
-rw-r--r--examples/vulkan/shared/qt_logo.bufbin0 -> 125600 bytes
-rw-r--r--examples/vulkan/shared/qt_logo.txt2912
-rw-r--r--examples/vulkan/shared/trianglerenderer.cpp513
-rw-r--r--examples/vulkan/shared/trianglerenderer.h85
-rw-r--r--examples/vulkan/vulkan.pro10
-rw-r--r--examples/widgets/animation/animatedtiles/main.cpp5
-rw-r--r--examples/widgets/animation/animation.pro1
-rw-r--r--examples/widgets/animation/appchooser/accessories-dictionary.pngbin5396 -> 0 bytes
-rw-r--r--examples/widgets/animation/appchooser/akregator.pngbin4873 -> 0 bytes
-rw-r--r--examples/widgets/animation/appchooser/appchooser.pro8
-rw-r--r--examples/widgets/animation/appchooser/appchooser.qrc8
-rw-r--r--examples/widgets/animation/appchooser/digikam.pngbin3334 -> 0 bytes
-rw-r--r--examples/widgets/animation/appchooser/k3b.pngbin8220 -> 0 bytes
-rw-r--r--examples/widgets/animation/appchooser/main.cpp183
-rw-r--r--examples/widgets/animation/moveblocks/main.cpp4
-rw-r--r--examples/widgets/animation/stickman/lifecycle.cpp3
-rw-r--r--examples/widgets/animation/stickman/stickman.cpp10
-rw-r--r--examples/widgets/animation/sub-attaq/main.cpp2
-rw-r--r--examples/widgets/animation/sub-attaq/states.cpp7
-rw-r--r--examples/widgets/animation/sub-attaq/submarine_p.h5
-rw-r--r--examples/widgets/dialogs/dialogs.pro1
-rw-r--r--examples/widgets/doc/images/addressbook-editdialog.pngbin8669 -> 11374 bytes
-rw-r--r--examples/widgets/doc/images/addressbook-example.pngbin12388 -> 20047 bytes
-rw-r--r--examples/widgets/doc/images/addressbook-newaddresstab.pngbin12556 -> 17413 bytes
-rw-r--r--examples/widgets/doc/images/graphicssimpleanchorlayout-example.pngbin16743 -> 11301 bytes
-rw-r--r--examples/widgets/doc/images/itemviews-editabletreemodel.pngbin32534 -> 30556 bytes
-rw-r--r--examples/widgets/doc/images/stylesheet-pagefold.pngbin15989 -> 29118 bytes
-rw-r--r--examples/widgets/doc/src/addressbook.qdoc43
-rw-r--r--examples/widgets/doc/src/basiclayouts.qdoc6
-rw-r--r--examples/widgets/doc/src/calendarwidget.qdoc10
-rw-r--r--examples/widgets/doc/src/collidingmice-example.qdoc10
-rw-r--r--examples/widgets/doc/src/customsortfiltermodel.qdoc6
-rw-r--r--examples/widgets/doc/src/dragdroprobot.qdoc2
-rw-r--r--examples/widgets/doc/src/elasticnodes.qdoc9
-rw-r--r--examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc46
-rw-r--r--examples/widgets/doc/src/painterpaths.qdoc11
-rw-r--r--examples/widgets/doc/src/stardelegate.qdoc16
-rw-r--r--examples/widgets/doc/src/stylesheet.qdoc51
-rw-r--r--examples/widgets/doc/src/tablet.qdoc13
-rw-r--r--examples/widgets/doc/src/validators.qdoc2
-rw-r--r--examples/widgets/draganddrop/draggableicons/dragwidget.h2
-rw-r--r--examples/widgets/draganddrop/draggabletext/dragwidget.cpp4
-rw-r--r--examples/widgets/draganddrop/draggabletext/dragwidget.h2
-rw-r--r--examples/widgets/draganddrop/dropsite/droparea.h4
-rw-r--r--examples/widgets/draganddrop/dropsite/dropsitewindow.cpp6
-rw-r--r--examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp2
-rw-r--r--examples/widgets/draganddrop/fridgemagnets/dragwidget.h2
-rw-r--r--examples/widgets/draganddrop/puzzle/main.cpp4
-rw-r--r--examples/widgets/draganddrop/puzzle/mainwindow.cpp27
-rw-r--r--examples/widgets/draganddrop/puzzle/mainwindow.h4
-rw-r--r--examples/widgets/draganddrop/puzzle/pieceslist.cpp2
-rw-r--r--examples/widgets/draganddrop/puzzle/pieceslist.h4
-rw-r--r--examples/widgets/draganddrop/puzzle/puzzlewidget.cpp65
-rw-r--r--examples/widgets/draganddrop/puzzle/puzzlewidget.h15
-rw-r--r--examples/widgets/effects/blurpicker/blurpicker.cpp9
-rw-r--r--examples/widgets/effects/effects.pro1
-rw-r--r--examples/widgets/effects/lighting/lighting.cpp150
-rw-r--r--examples/widgets/effects/lighting/lighting.pro8
-rw-r--r--examples/widgets/graphicsview/boxes/glbuffers.cpp4
-rw-r--r--examples/widgets/graphicsview/boxes/qtbox.cpp2
-rw-r--r--examples/widgets/graphicsview/boxes/scene.cpp15
-rw-r--r--examples/widgets/graphicsview/boxes/scene.h2
-rw-r--r--examples/widgets/graphicsview/boxes/trackball.cpp8
-rw-r--r--examples/widgets/graphicsview/collidingmice/main.cpp1
-rw-r--r--examples/widgets/graphicsview/collidingmice/mouse.cpp30
-rw-r--r--examples/widgets/graphicsview/diagramscene/arrow.cpp17
-rw-r--r--examples/widgets/graphicsview/dragdroprobot/coloritem.cpp4
-rw-r--r--examples/widgets/graphicsview/dragdroprobot/main.cpp1
-rw-r--r--examples/widgets/graphicsview/elasticnodes/edge.cpp28
-rw-r--r--examples/widgets/graphicsview/elasticnodes/graphwidget.cpp3
-rw-r--r--examples/widgets/graphicsview/elasticnodes/main.cpp1
-rw-r--r--examples/widgets/itemviews/addressbook/addresswidget.cpp26
-rw-r--r--examples/widgets/itemviews/addressbook/tablemodel.cpp37
-rw-r--r--examples/widgets/itemviews/addressbook/tablemodel.h29
-rw-r--r--examples/widgets/itemviews/chart/pieview.cpp12
-rw-r--r--examples/widgets/itemviews/puzzle/main.cpp2
-rw-r--r--examples/widgets/itemviews/puzzle/mainwindow.cpp33
-rw-r--r--examples/widgets/itemviews/puzzle/mainwindow.h2
-rw-r--r--examples/widgets/itemviews/puzzle/piecesmodel.cpp3
-rw-r--r--examples/widgets/itemviews/puzzle/puzzlewidget.cpp57
-rw-r--r--examples/widgets/itemviews/puzzle/puzzlewidget.h16
-rw-r--r--examples/widgets/itemviews/storageview/main.cpp10
-rw-r--r--examples/widgets/itemviews/storageview/storagemodel.cpp79
-rw-r--r--examples/widgets/itemviews/storageview/storagemodel.h14
-rw-r--r--examples/widgets/mainwindows/mainwindow/mainwindow.cpp1
-rw-r--r--examples/widgets/mainwindows/mainwindow/toolbar.cpp4
-rw-r--r--examples/widgets/painting/affine/xform.cpp48
-rw-r--r--examples/widgets/painting/composition/composition.cpp2
-rw-r--r--examples/widgets/painting/painterpaths/window.cpp10
-rw-r--r--examples/widgets/statemachine/rogue/window.cpp4
-rw-r--r--examples/widgets/tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp10
-rw-r--r--examples/widgets/tools/undo/mainwindow.cpp11
-rw-r--r--examples/widgets/tools/undoframework/diagramitem.cpp3
-rw-r--r--examples/widgets/widgets/tablet/mainwindow.cpp10
-rw-r--r--examples/widgets/widgets/tablet/mainwindow.h1
-rw-r--r--examples/widgets/widgets/tablet/tabletcanvas.cpp52
-rw-r--r--examples/widgets/widgets/tablet/tabletcanvas.h2
-rw-r--r--examples/widgets/widgets/tetrix/main.cpp1
-rw-r--r--examples/widgets/widgets/tetrix/tetrixpiece.cpp2
-rw-r--r--examples/widgets/widgets/tooltips/main.cpp1
-rw-r--r--examples/widgets/widgets/tooltips/sortingbox.cpp4
-rw-r--r--examples/xml/dombookmarks/mainwindow.cpp44
-rw-r--r--examples/xml/dombookmarks/mainwindow.h9
-rw-r--r--examples/xml/dombookmarks/xbeltree.cpp74
-rw-r--r--examples/xml/dombookmarks/xbeltree.h11
-rw-r--r--examples/xml/saxbookmarks/mainwindow.cpp67
-rw-r--r--examples/xml/saxbookmarks/mainwindow.h13
-rw-r--r--examples/xml/saxbookmarks/xbelgenerator.cpp18
-rw-r--r--examples/xml/saxbookmarks/xbelgenerator.h6
-rw-r--r--examples/xml/saxbookmarks/xbelhandler.cpp28
-rw-r--r--examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc2
-rw-r--r--examples/xml/streambookmarks/mainwindow.cpp75
-rw-r--r--examples/xml/streambookmarks/mainwindow.h13
-rw-r--r--examples/xml/streambookmarks/xbelreader.cpp36
-rw-r--r--examples/xml/streambookmarks/xbelreader.h4
-rw-r--r--examples/xml/streambookmarks/xbelwriter.cpp29
-rw-r--r--examples/xml/streambookmarks/xbelwriter.h6
261 files changed, 9975 insertions, 1809 deletions
diff --git a/examples/corelib/ipc/localfortuneclient/client.cpp b/examples/corelib/ipc/localfortuneclient/client.cpp
index d5a1525769..8d415f73aa 100644
--- a/examples/corelib/ipc/localfortuneclient/client.cpp
+++ b/examples/corelib/ipc/localfortuneclient/client.cpp
@@ -54,45 +54,45 @@
#include "client.h"
Client::Client(QWidget *parent)
- : QDialog(parent)
+ : QDialog(parent),
+ hostLineEdit(new QLineEdit("fortune")),
+ getFortuneButton(new QPushButton(tr("Get Fortune"))),
+ statusLabel(new QLabel(tr("This examples requires that you run the "
+ "Local Fortune Server example as well."))),
+ socket(new QLocalSocket(this))
{
- hostLabel = new QLabel(tr("&Server name:"));
- hostLineEdit = new QLineEdit("fortune");
-
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ QLabel *hostLabel = new QLabel(tr("&Server name:"));
hostLabel->setBuddy(hostLineEdit);
- statusLabel = new QLabel(tr("This examples requires that you run the "
- "Fortune Server example as well."));
statusLabel->setWordWrap(true);
- getFortuneButton = new QPushButton(tr("Get Fortune"));
getFortuneButton->setDefault(true);
+ QPushButton *quitButton = new QPushButton(tr("Quit"));
- quitButton = new QPushButton(tr("Quit"));
-
- buttonBox = new QDialogButtonBox;
+ QDialogButtonBox *buttonBox = new QDialogButtonBox;
buttonBox->addButton(getFortuneButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
- socket = new QLocalSocket(this);
+ in.setDevice(socket);
+ in.setVersion(QDataStream::Qt_5_10);
- connect(hostLineEdit, SIGNAL(textChanged(QString)),
- this, SLOT(enableGetFortuneButton()));
- connect(getFortuneButton, SIGNAL(clicked()),
- this, SLOT(requestNewFortune()));
- connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
- connect(socket, SIGNAL(readyRead()), this, SLOT(readFortune()));
- connect(socket, SIGNAL(error(QLocalSocket::LocalSocketError)),
- this, SLOT(displayError(QLocalSocket::LocalSocketError)));
+ connect(hostLineEdit, &QLineEdit::textChanged,
+ this, &Client::enableGetFortuneButton);
+ connect(getFortuneButton, &QPushButton::clicked,
+ this, &Client::requestNewFortune);
+ connect(quitButton, &QPushButton::clicked, this, &Client::close);
+ connect(socket, &QLocalSocket::readyRead, this, &Client::readFortune);
+ connect(socket, QOverload<QLocalSocket::LocalSocketError>::of(&QLocalSocket::error),
+ this, &Client::displayError);
- QGridLayout *mainLayout = new QGridLayout;
+ QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(hostLabel, 0, 0);
mainLayout->addWidget(hostLineEdit, 0, 1);
mainLayout->addWidget(statusLabel, 2, 0, 1, 2);
mainLayout->addWidget(buttonBox, 3, 0, 1, 2);
- setLayout(mainLayout);
- setWindowTitle(tr("Fortune Client"));
+ setWindowTitle(QGuiApplication::applicationDisplayName());
hostLineEdit->setFocus();
}
@@ -106,11 +106,9 @@ void Client::requestNewFortune()
void Client::readFortune()
{
- QDataStream in(socket);
- in.setVersion(QDataStream::Qt_4_0);
-
if (blockSize == 0) {
- // Relies on the fact that QDataStream format streams a quint32 into sizeof(quint32) bytes
+ // Relies on the fact that QDataStream serializes a quint32 into
+ // sizeof(quint32) bytes
if (socket->bytesAvailable() < (int)sizeof(quint32))
return;
in >> blockSize;
@@ -123,7 +121,7 @@ void Client::readFortune()
in >> nextFortune;
if (nextFortune == currentFortune) {
- QTimer::singleShot(0, this, SLOT(requestNewFortune()));
+ QTimer::singleShot(0, this, &Client::requestNewFortune);
return;
}
@@ -136,21 +134,22 @@ void Client::displayError(QLocalSocket::LocalSocketError socketError)
{
switch (socketError) {
case QLocalSocket::ServerNotFoundError:
- QMessageBox::information(this, tr("Fortune Client"),
- tr("The host was not found. Please check the "
- "host name and port settings."));
+ QMessageBox::information(this, tr("Local Fortune Client"),
+ tr("The host was not found. Please make sure "
+ "that the server is running and that the "
+ "server name is correct."));
break;
case QLocalSocket::ConnectionRefusedError:
- QMessageBox::information(this, tr("Fortune Client"),
+ QMessageBox::information(this, tr("Local Fortune Client"),
tr("The connection was refused by the peer. "
"Make sure the fortune server is running, "
- "and check that the host name and port "
- "settings are correct."));
+ "and check that the server name "
+ "is correct."));
break;
case QLocalSocket::PeerClosedError:
break;
default:
- QMessageBox::information(this, tr("Fortune Client"),
+ QMessageBox::information(this, tr("Local Fortune Client"),
tr("The following error occurred: %1.")
.arg(socket->errorString()));
}
diff --git a/examples/corelib/ipc/localfortuneclient/client.h b/examples/corelib/ipc/localfortuneclient/client.h
index 8e628efcee..0c1ede94c9 100644
--- a/examples/corelib/ipc/localfortuneclient/client.h
+++ b/examples/corelib/ipc/localfortuneclient/client.h
@@ -52,11 +52,11 @@
#define CLIENT_H
#include <QDialog>
+#include <QDataStream>
#include <qlocalsocket.h>
QT_BEGIN_NAMESPACE
-class QDialogButtonBox;
class QLabel;
class QLineEdit;
class QPushButton;
@@ -68,7 +68,7 @@ class Client : public QDialog
Q_OBJECT
public:
- Client(QWidget *parent = 0);
+ explicit Client(QWidget *parent = nullptr);
private slots:
void requestNewFortune();
@@ -77,16 +77,15 @@ private slots:
void enableGetFortuneButton();
private:
- QLabel *hostLabel;
QLineEdit *hostLineEdit;
- QLabel *statusLabel;
QPushButton *getFortuneButton;
- QPushButton *quitButton;
- QDialogButtonBox *buttonBox;
+ QLabel *statusLabel;
QLocalSocket *socket;
- QString currentFortune;
+ QDataStream in;
quint32 blockSize;
+
+ QString currentFortune;
};
#endif
diff --git a/examples/corelib/ipc/localfortuneclient/main.cpp b/examples/corelib/ipc/localfortuneclient/main.cpp
index dd13a05be9..ed5cf4c569 100644
--- a/examples/corelib/ipc/localfortuneclient/main.cpp
+++ b/examples/corelib/ipc/localfortuneclient/main.cpp
@@ -55,6 +55,7 @@
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
+ QGuiApplication::setApplicationDisplayName(Client::tr("Local Fortune Client"));
Client client;
client.show();
return app.exec();
diff --git a/examples/corelib/ipc/localfortuneserver/main.cpp b/examples/corelib/ipc/localfortuneserver/main.cpp
index cd066a0acd..6f8ec539fe 100644
--- a/examples/corelib/ipc/localfortuneserver/main.cpp
+++ b/examples/corelib/ipc/localfortuneserver/main.cpp
@@ -58,8 +58,8 @@
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
+ QGuiApplication::setApplicationDisplayName(Server::tr("Local Fortune Server"));
Server server;
server.show();
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
return app.exec();
}
diff --git a/examples/corelib/ipc/localfortuneserver/server.cpp b/examples/corelib/ipc/localfortuneserver/server.cpp
index 2eee4760be..be8d4750d6 100644
--- a/examples/corelib/ipc/localfortuneserver/server.cpp
+++ b/examples/corelib/ipc/localfortuneserver/server.cpp
@@ -60,22 +60,21 @@
Server::Server(QWidget *parent)
: QDialog(parent)
{
- statusLabel = new QLabel;
- statusLabel->setWordWrap(true);
- quitButton = new QPushButton(tr("Quit"));
- quitButton->setAutoDefault(false);
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
server = new QLocalServer(this);
if (!server->listen("fortune")) {
- QMessageBox::critical(this, tr("Fortune Server"),
+ QMessageBox::critical(this, tr("Local Fortune Server"),
tr("Unable to start the server: %1.")
.arg(server->errorString()));
close();
return;
}
+ QLabel *statusLabel = new QLabel;
+ statusLabel->setWordWrap(true);
statusLabel->setText(tr("The server is running.\n"
- "Run the Fortune Client example now."));
+ "Run the Local Fortune Client example now."));
fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
<< tr("You've got to think about tomorrow.")
@@ -85,35 +84,36 @@ Server::Server(QWidget *parent)
<< tr("You cannot kill time without injuring eternity.")
<< tr("Computers are not intelligent. They only think they are.");
- connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
- connect(server, SIGNAL(newConnection()), this, SLOT(sendFortune()));
+ QPushButton *quitButton = new QPushButton(tr("Quit"));
+ quitButton->setAutoDefault(false);
+ connect(quitButton, &QPushButton::clicked, this, &Server::close);
+ connect(server, &QLocalServer::newConnection, this, &Server::sendFortune);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(1);
buttonLayout->addWidget(quitButton);
buttonLayout->addStretch(1);
- QVBoxLayout *mainLayout = new QVBoxLayout;
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(statusLabel);
mainLayout->addLayout(buttonLayout);
- setLayout(mainLayout);
- setWindowTitle(tr("Fortune Server"));
+ setWindowTitle(QGuiApplication::applicationDisplayName());
}
void Server::sendFortune()
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
- out.setVersion(QDataStream::Qt_4_0);
- out << (quint32)0;
- out << fortunes.at(qrand() % fortunes.size());
- out.device()->seek(0);
- out << (quint32)(block.size() - sizeof(quint32));
+ out.setVersion(QDataStream::Qt_5_10);
+ const int fortuneIndex = QRandomGenerator::global()->bounded(0, fortunes.size());
+ const QString &message = fortunes.at(fortuneIndex);
+ out << quint32(message.size());
+ out << message;
QLocalSocket *clientConnection = server->nextPendingConnection();
- connect(clientConnection, SIGNAL(disconnected()),
- clientConnection, SLOT(deleteLater()));
+ connect(clientConnection, &QLocalSocket::disconnected,
+ clientConnection, &QLocalSocket::deleteLater);
clientConnection->write(block);
clientConnection->flush();
diff --git a/examples/corelib/ipc/localfortuneserver/server.h b/examples/corelib/ipc/localfortuneserver/server.h
index c77b4e8127..6b90ba5932 100644
--- a/examples/corelib/ipc/localfortuneserver/server.h
+++ b/examples/corelib/ipc/localfortuneserver/server.h
@@ -64,14 +64,12 @@ class Server : public QDialog
Q_OBJECT
public:
- Server(QWidget *parent = 0);
+ explicit Server(QWidget *parent = nullptr);
private slots:
void sendFortune();
private:
- QLabel *statusLabel;
- QPushButton *quitButton;
QLocalServer *server;
QStringList fortunes;
};
diff --git a/examples/corelib/json/savegame/character.cpp b/examples/corelib/json/savegame/character.cpp
index 20bbc34961..046cde3091 100644
--- a/examples/corelib/json/savegame/character.cpp
+++ b/examples/corelib/json/savegame/character.cpp
@@ -50,12 +50,17 @@
#include "character.h"
+#include <QMetaEnum>
+#include <QTextStream>
+
Character::Character() :
mLevel(0),
mClassType(Warrior) {
}
-Character::Character(const QString &name, int level, Character::ClassType classType) :
+Character::Character(const QString &name,
+ int level,
+ Character::ClassType classType) :
mName(name),
mLevel(level),
mClassType(classType)
@@ -95,9 +100,14 @@ void Character::setClassType(Character::ClassType classType)
//! [0]
void Character::read(const QJsonObject &json)
{
- mName = json["name"].toString();
- mLevel = json["level"].toDouble();
- mClassType = ClassType(qRound(json["classType"].toDouble()));
+ if (json.contains("name") && json["name"].isString())
+ mName = json["name"].toString();
+
+ if (json.contains("level") && json["level"].isDouble())
+ mLevel = json["level"].toInt();
+
+ if (json.contains("classType") && json["classType"].isDouble())
+ mClassType = ClassType(json["classType"].toInt());
}
//! [0]
@@ -109,3 +119,13 @@ void Character::write(QJsonObject &json) const
json["classType"] = mClassType;
}
//! [1]
+
+void Character::print(int indentation) const
+{
+ const QString indent(indentation * 2, ' ');
+ QTextStream(stdout) << indent << "Name:\t" << mName << "\n";
+ QTextStream(stdout) << indent << "Level:\t" << mLevel << "\n";
+
+ QString className = QMetaEnum::fromType<ClassType>().valueToKey(mClassType);
+ QTextStream(stdout) << indent << "Class:\t" << className << "\n";
+}
diff --git a/examples/corelib/json/savegame/character.h b/examples/corelib/json/savegame/character.h
index 740496822c..cbf06d7fd6 100644
--- a/examples/corelib/json/savegame/character.h
+++ b/examples/corelib/json/savegame/character.h
@@ -52,15 +52,19 @@
#define CHARACTER_H
#include <QJsonObject>
+#include <QObject>
#include <QString>
//! [0]
class Character
{
+ Q_GADGET;
+
public:
enum ClassType {
Warrior, Mage, Archer
};
+ Q_ENUM(ClassType)
Character();
Character(const QString &name, int level, ClassType classType);
@@ -76,6 +80,8 @@ public:
void read(const QJsonObject &json);
void write(QJsonObject &json) const;
+
+ void print(int indentation = 0) const;
private:
QString mName;
int mLevel;
diff --git a/examples/corelib/json/savegame/doc/src/savegame.qdoc b/examples/corelib/json/savegame/doc/src/savegame.qdoc
index fec5fe8e5d..06e70680c6 100644
--- a/examples/corelib/json/savegame/doc/src/savegame.qdoc
+++ b/examples/corelib/json/savegame/doc/src/savegame.qdoc
@@ -61,8 +61,8 @@
QJsonObject argument. You can use either \l QJsonObject::operator[]() or
QJsonObject::value() to access values within the JSON object; both are
const functions and return QJsonValue::Undefined if the key is invalid. We
- could check if the keys are valid before attempting to read them with
- QJsonObject::contains(), but we assume that they are.
+ check if the keys are valid before attempting to read them with
+ QJsonObject::contains().
\snippet json/savegame/character.cpp 1
@@ -77,7 +77,7 @@
\snippet json/savegame/level.h 0
We want to have several levels in our game, each with several NPCs, so we
- keep a QList of Character objects. We also provide the familiar read() and
+ keep a QVector of Character objects. We also provide the familiar read() and
write() functions.
\snippet json/savegame/level.cpp 0
@@ -86,7 +86,7 @@
case, we construct a QJsonArray from the value associated with the key
\c "npcs". Then, for each QJsonValue element in the array, we call
toObject() to get the Character's JSON object. The Character object can then
- read their JSON and be appended to our NPC list.
+ read their JSON and be appended to our NPC array.
\note \l{Container Classes}{Associate containers} can be written by storing
the key in each value object (if it's not already). With this approach, the
@@ -120,10 +120,10 @@
\snippet json/savegame/game.cpp 1
The first thing we do in the read() function is tell the player to read
- itself. We then clear the levels list so that calling loadGame() on the same
- Game object twice doesn't result in old levels hanging around.
+ itself. We then clear the level array so that calling loadGame() on the
+ same Game object twice doesn't result in old levels hanging around.
- We then populate the level list by reading each Level from a QJsonArray.
+ We then populate the level array by reading each Level from a QJsonArray.
\snippet json/savegame/game.cpp 2
@@ -159,20 +159,23 @@
Since we're only interested in demonstrating \e serialization of a game with
JSON, our game is not actually playable. Therefore, we only need
- QCoreApplication and have no event loop. We create our game and assume that
- the player had a great time and made lots of progress, altering the internal
- state of our Character, Level and Game objects.
+ QCoreApplication and have no event loop. On application start-up we parse
+ the command-line arguments to decide how to start the game. For the first
+ argument the options "new" (default) and "load" are available. When "new"
+ is specified a new game will be generated, and when "load" is specified a
+ previously saved game will be loaded in. For the second argument
+ "json" (default) and "binary" are available as options. This argument will
+ decide which file is saved to and/or loaded from. We then move ahead and
+ assume that the player had a great time and made lots of progress, altering
+ the internal state of our Character, Level and Game objects.
\snippet json/savegame/main.cpp 1
When the player has finished, we save their game. For demonstration
- purposes, we serialize to both JSON and binary. You can examine the contents
- of the files in the same directory as the executable, although the binary
- save file will contain some garbage characters (which is normal).
-
- To show that the saved files can be loaded again, we call loadGame() for
- each format, returning \c 1 on failure. Assuming everything went well, we
- return \c 0 to indicate success.
+ purposes, we can serialize to either JSON or binary. You can examine the
+ contents of the files in the same directory as the executable (or re-run
+ the example, making sure to also specify the "load" option), although the
+ binary save file will contain some garbage characters (which is normal).
That concludes our example. As you can see, serialization with Qt's JSON
classes is very simple and convenient. The advantages of using QJsonDocument
diff --git a/examples/corelib/json/savegame/game.cpp b/examples/corelib/json/savegame/game.cpp
index b0d800f4ab..4caec71a03 100644
--- a/examples/corelib/json/savegame/game.cpp
+++ b/examples/corelib/json/savegame/game.cpp
@@ -53,41 +53,54 @@
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
+#include <QRandomGenerator>
+#include <QTextStream>
-Game::Game()
-{
-}
-
-const Character &Game::player() const
+Character Game::player() const
{
return mPlayer;
}
-const QList<Level> &Game::levels() const {
+QVector<Level> Game::levels() const
+{
return mLevels;
}
//! [0]
-void Game::newGame() {
+void Game::newGame()
+{
mPlayer = Character();
mPlayer.setName(QStringLiteral("Hero"));
mPlayer.setClassType(Character::Archer);
- mPlayer.setLevel(15);
+ mPlayer.setLevel(QRandomGenerator::global()->bounded(15, 21));
mLevels.clear();
-
- Level village;
- QList<Character> villageNpcs;
- villageNpcs.append(Character(QStringLiteral("Barry the Blacksmith"), 10, Character::Warrior));
- villageNpcs.append(Character(QStringLiteral("Terry the Trader"), 10, Character::Warrior));
+ mLevels.reserve(2);
+
+ Level village(QStringLiteral("Village"));
+ QVector<Character> villageNpcs;
+ villageNpcs.reserve(2);
+ villageNpcs.append(Character(QStringLiteral("Barry the Blacksmith"),
+ QRandomGenerator::global()->bounded(8, 11),
+ Character::Warrior));
+ villageNpcs.append(Character(QStringLiteral("Terry the Trader"),
+ QRandomGenerator::global()->bounded(6, 8),
+ Character::Warrior));
village.setNpcs(villageNpcs);
mLevels.append(village);
- Level dungeon;
- QList<Character> dungeonNpcs;
- dungeonNpcs.append(Character(QStringLiteral("Eric the Evil"), 20, Character::Mage));
- dungeonNpcs.append(Character(QStringLiteral("Eric's Sidekick #1"), 5, Character::Warrior));
- dungeonNpcs.append(Character(QStringLiteral("Eric's Sidekick #2"), 5, Character::Warrior));
+ Level dungeon(QStringLiteral("Dungeon"));
+ QVector<Character> dungeonNpcs;
+ dungeonNpcs.reserve(3);
+ dungeonNpcs.append(Character(QStringLiteral("Eric the Evil"),
+ QRandomGenerator::global()->bounded(18, 26),
+ Character::Mage));
+ dungeonNpcs.append(Character(QStringLiteral("Eric's Left Minion"),
+ QRandomGenerator::global()->bounded(5, 7),
+ Character::Warrior));
+ dungeonNpcs.append(Character(QStringLiteral("Eric's Right Minion"),
+ QRandomGenerator::global()->bounded(4, 9),
+ Character::Warrior));
dungeon.setNpcs(dungeonNpcs);
mLevels.append(dungeon);
}
@@ -113,6 +126,10 @@ bool Game::loadGame(Game::SaveFormat saveFormat)
read(loadDoc.object());
+ QTextStream(stdout) << "Loaded save for "
+ << loadDoc["player"]["name"].toString()
+ << " using "
+ << (saveFormat != Json ? "binary " : "") << "JSON...\n";
return true;
}
//! [3]
@@ -143,15 +160,19 @@ bool Game::saveGame(Game::SaveFormat saveFormat) const
//! [1]
void Game::read(const QJsonObject &json)
{
- mPlayer.read(json["player"].toObject());
-
- mLevels.clear();
- QJsonArray levelArray = json["levels"].toArray();
- for (int levelIndex = 0; levelIndex < levelArray.size(); ++levelIndex) {
- QJsonObject levelObject = levelArray[levelIndex].toObject();
- Level level;
- level.read(levelObject);
- mLevels.append(level);
+ if (json.contains("player") && json["player"].isObject())
+ mPlayer.read(json["player"].toObject());
+
+ if (json.contains("levels") && json["levels"].isArray()) {
+ QJsonArray levelArray = json["levels"].toArray();
+ mLevels.clear();
+ mLevels.reserve(levelArray.size());
+ for (int levelIndex = 0; levelIndex < levelArray.size(); ++levelIndex) {
+ QJsonObject levelObject = levelArray[levelIndex].toObject();
+ Level level;
+ level.read(levelObject);
+ mLevels.append(level);
+ }
}
}
//! [1]
@@ -172,3 +193,14 @@ void Game::write(QJsonObject &json) const
json["levels"] = levelArray;
}
//! [2]
+
+void Game::print(int indentation) const
+{
+ const QString indent(indentation * 2, ' ');
+ QTextStream(stdout) << indent << "Player\n";
+ mPlayer.print(indentation + 1);
+
+ QTextStream(stdout) << indent << "Levels\n";
+ for (Level level : mLevels)
+ level.print(indentation + 1);
+}
diff --git a/examples/corelib/json/savegame/game.h b/examples/corelib/json/savegame/game.h
index c02832b0ab..3da9c148be 100644
--- a/examples/corelib/json/savegame/game.h
+++ b/examples/corelib/json/savegame/game.h
@@ -52,7 +52,7 @@
#define GAME_H
#include <QJsonObject>
-#include <QList>
+#include <QVector>
#include "character.h"
#include "level.h"
@@ -61,14 +61,12 @@
class Game
{
public:
- Game();
-
enum SaveFormat {
Json, Binary
};
- const Character &player() const;
- const QList<Level> &levels() const;
+ Character player() const;
+ QVector<Level> levels() const;
void newGame();
bool loadGame(SaveFormat saveFormat);
@@ -76,9 +74,11 @@ public:
void read(const QJsonObject &json);
void write(QJsonObject &json) const;
+
+ void print(int indentation = 0) const;
private:
Character mPlayer;
- QList<Level> mLevels;
+ QVector<Level> mLevels;
};
//! [0]
diff --git a/examples/corelib/json/savegame/level.cpp b/examples/corelib/json/savegame/level.cpp
index 5b9fb5c90a..8eda107f46 100644
--- a/examples/corelib/json/savegame/level.cpp
+++ b/examples/corelib/json/savegame/level.cpp
@@ -51,16 +51,23 @@
#include "level.h"
#include <QJsonArray>
+#include <QTextStream>
-Level::Level() {
+Level::Level(const QString &name) : mName(name)
+{
}
-const QList<Character> &Level::npcs() const
+QString Level::name() const
+{
+ return mName;
+}
+
+QVector<Character> Level::npcs() const
{
return mNpcs;
}
-void Level::setNpcs(const QList<Character> &npcs)
+void Level::setNpcs(const QVector<Character> &npcs)
{
mNpcs = npcs;
}
@@ -68,13 +75,19 @@ void Level::setNpcs(const QList<Character> &npcs)
//! [0]
void Level::read(const QJsonObject &json)
{
- mNpcs.clear();
- QJsonArray npcArray = json["npcs"].toArray();
- for (int npcIndex = 0; npcIndex < npcArray.size(); ++npcIndex) {
- QJsonObject npcObject = npcArray[npcIndex].toObject();
- Character npc;
- npc.read(npcObject);
- mNpcs.append(npc);
+ if (json.contains("name") && json["name"].isString())
+ mName = json["name"].toString();
+
+ if (json.contains("npcs") && json["npcs"].isArray()) {
+ QJsonArray npcArray = json["npcs"].toArray();
+ mNpcs.clear();
+ mNpcs.reserve(npcArray.size());
+ for (int npcIndex = 0; npcIndex < npcArray.size(); ++npcIndex) {
+ QJsonObject npcObject = npcArray[npcIndex].toObject();
+ Character npc;
+ npc.read(npcObject);
+ mNpcs.append(npc);
+ }
}
}
//! [0]
@@ -82,6 +95,7 @@ void Level::read(const QJsonObject &json)
//! [1]
void Level::write(QJsonObject &json) const
{
+ json["name"] = mName;
QJsonArray npcArray;
foreach (const Character npc, mNpcs) {
QJsonObject npcObject;
@@ -91,3 +105,13 @@ void Level::write(QJsonObject &json) const
json["npcs"] = npcArray;
}
//! [1]
+
+void Level::print(int indentation) const
+{
+ const QString indent(indentation * 2, ' ');
+ QTextStream(stdout) << indent << "Name:\t" << mName << "\n";
+
+ QTextStream(stdout) << indent << "NPCs:\n";
+ for (const Character &character : mNpcs)
+ character.print(2);
+}
diff --git a/examples/corelib/json/savegame/level.h b/examples/corelib/json/savegame/level.h
index 878510e9d5..393524abfd 100644
--- a/examples/corelib/json/savegame/level.h
+++ b/examples/corelib/json/savegame/level.h
@@ -52,7 +52,7 @@
#define LEVEL_H
#include <QJsonObject>
-#include <QList>
+#include <QVector>
#include "character.h"
@@ -60,15 +60,21 @@
class Level
{
public:
- Level();
+ Level() = default;
+ Level(const QString &name);
- const QList<Character> &npcs() const;
- void setNpcs(const QList<Character> &npcs);
+ QString name() const;
+
+ QVector<Character> npcs() const;
+ void setNpcs(const QVector<Character> &npcs);
void read(const QJsonObject &json);
void write(QJsonObject &json) const;
+
+ void print(int indentation = 0) const;
private:
- QList<Character> mNpcs;
+ QString mName;
+ QVector<Character> mNpcs;
};
//! [0]
diff --git a/examples/corelib/json/savegame/main.cpp b/examples/corelib/json/savegame/main.cpp
index 2e4e864942..d091684211 100644
--- a/examples/corelib/json/savegame/main.cpp
+++ b/examples/corelib/json/savegame/main.cpp
@@ -49,30 +49,32 @@
****************************************************************************/
#include <QCoreApplication>
+#include <QTextStream>
#include "game.h"
//! [0]
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
+ QStringList args = QCoreApplication::arguments();
+ bool newGame = true;
+ if (args.length() > 1)
+ newGame = (args[1].toLower() != QStringLiteral("load"));
+ bool json = true;
+ if (args.length() > 2)
+ json = (args[2].toLower() != QStringLiteral("binary"));
Game game;
- game.newGame();
+ if (newGame)
+ game.newGame();
+ else if (!game.loadGame(json ? Game::Json : Game::Binary))
+ return 1;
// Game is played; changes are made...
//! [0]
//! [1]
- if (!game.saveGame(Game::Json))
- return 1;
-
- if (!game.saveGame(Game::Binary))
- return 1;
-
- Game fromJsonGame;
- if (!fromJsonGame.loadGame(Game::Json))
- return 1;
-
- Game fromBinaryGame;
- if (!fromBinaryGame.loadGame(Game::Binary))
+ QTextStream(stdout) << "Game ended in the following state:\n";
+ game.print();
+ if (!game.saveGame(json ? Game::Json : Game::Binary))
return 1;
return 0;
diff --git a/examples/corelib/threads/queuedcustomtype/main.cpp b/examples/corelib/threads/queuedcustomtype/main.cpp
index 7084b7538a..1f25fafa1b 100644
--- a/examples/corelib/threads/queuedcustomtype/main.cpp
+++ b/examples/corelib/threads/queuedcustomtype/main.cpp
@@ -126,7 +126,6 @@ int main(int argc, char *argv[])
//! [main start] //! [register meta-type for queued communications]
qRegisterMetaType<Block>();
//! [register meta-type for queued communications]
- qsrand(QTime::currentTime().elapsed());
Window window;
window.show();
diff --git a/examples/corelib/threads/queuedcustomtype/renderthread.cpp b/examples/corelib/threads/queuedcustomtype/renderthread.cpp
index f894dd587f..67cedf1e74 100644
--- a/examples/corelib/threads/queuedcustomtype/renderthread.cpp
+++ b/examples/corelib/threads/queuedcustomtype/renderthread.cpp
@@ -50,6 +50,8 @@
#include "renderthread.h"
+#include <QRandomGenerator>
+
RenderThread::RenderThread(QObject *parent)
: QThread(parent)
{
@@ -82,9 +84,9 @@ void RenderThread::run()
for (int s = size; s > 0; --s) {
for (int c = 0; c < 400; ++c) {
//![processing the image (start)]
- int x1 = qMax(0, (qrand() % m_image.width()) - s/2);
+ int x1 = qMax(0, QRandomGenerator::global()->bounded(m_image.width()) - s/2);
int x2 = qMin(x1 + s/2 + 1, m_image.width());
- int y1 = qMax(0, (qrand() % m_image.height()) - s/2);
+ int y1 = qMax(0, QRandomGenerator::global()->bounded(m_image.height()) - s/2);
int y2 = qMin(y1 + s/2 + 1, m_image.height());
int n = 0;
int red = 0;
diff --git a/examples/corelib/threads/semaphores/semaphores.cpp b/examples/corelib/threads/semaphores/semaphores.cpp
index 37dd4cda20..145624bb0b 100644
--- a/examples/corelib/threads/semaphores/semaphores.cpp
+++ b/examples/corelib/threads/semaphores/semaphores.cpp
@@ -70,10 +70,9 @@ class Producer : public QThread
public:
void run() override
{
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for (int i = 0; i < DataSize; ++i) {
freeBytes.acquire();
- buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];
+ buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
usedBytes.release();
}
}
diff --git a/examples/corelib/threads/waitconditions/waitconditions.cpp b/examples/corelib/threads/waitconditions/waitconditions.cpp
index 9eab28f94c..963ee03a76 100644
--- a/examples/corelib/threads/waitconditions/waitconditions.cpp
+++ b/examples/corelib/threads/waitconditions/waitconditions.cpp
@@ -76,15 +76,13 @@ public:
void run() override
{
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
-
for (int i = 0; i < DataSize; ++i) {
mutex.lock();
if (numUsedBytes == BufferSize)
bufferNotFull.wait(&mutex);
mutex.unlock();
- buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];
+ buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
mutex.lock();
++numUsedBytes;
diff --git a/examples/corelib/tools/contiguouscache/randomlistmodel.cpp b/examples/corelib/tools/contiguouscache/randomlistmodel.cpp
index f3d8f4b133..ccaa45a28b 100644
--- a/examples/corelib/tools/contiguouscache/randomlistmodel.cpp
+++ b/examples/corelib/tools/contiguouscache/randomlistmodel.cpp
@@ -48,6 +48,7 @@
**
****************************************************************************/
#include "randomlistmodel.h"
+#include <QRandomGenerator>
#include <stdlib.h>
static const int bufferSize(500);
@@ -101,6 +102,6 @@ void RandomListModel::cacheRows(int from, int to) const
//![1]
QString RandomListModel::fetchRow(int position) const
{
- return QString::number(rand() % ++position);
+ return QString::number(QRandomGenerator::global()->bounded(++position));
}
//![1]
diff --git a/examples/dbus/remotecontrolledcar/car/car.cpp b/examples/dbus/remotecontrolledcar/car/car.cpp
index 67daac79ba..2de4e6447a 100644
--- a/examples/dbus/remotecontrolledcar/car/car.cpp
+++ b/examples/dbus/remotecontrolledcar/car/car.cpp
@@ -50,9 +50,7 @@
#include "car.h"
#include <QtWidgets/QtWidgets>
-#include <math.h>
-
-static const double Pi = 3.14159265358979323846264338327950288419717;
+#include <qmath.h>
QRectF Car::boundingRect() const
{
@@ -135,10 +133,10 @@ void Car::timerEvent(QTimerEvent *event)
Q_UNUSED(event);
const qreal axelDistance = 54;
- qreal wheelsAngleRads = (wheelsAngle * Pi) / 180;
+ qreal wheelsAngleRads = qDegreesToRadians(wheelsAngle);
qreal turnDistance = ::cos(wheelsAngleRads) * axelDistance * 2;
qreal turnRateRads = wheelsAngleRads / turnDistance; // rough estimate
- qreal turnRate = (turnRateRads * 180) / Pi;
+ qreal turnRate = qRadiansToDegrees(turnRateRads);
qreal rotation = speed * turnRate;
setTransform(QTransform().rotate(rotation), true);
diff --git a/examples/embedded/flickable/main.cpp b/examples/embedded/flickable/main.cpp
index 9772ba4f55..9367c8b4fe 100644
--- a/examples/embedded/flickable/main.cpp
+++ b/examples/embedded/flickable/main.cpp
@@ -72,7 +72,7 @@ static QStringList colorPairs(int max)
// randomize it
colors.clear();
while (combinedColors.count()) {
- int i = qrand() % combinedColors.count();
+ int i = QRandomGenerator::global()->bounded(combinedColors.count());
colors << combinedColors[i];
combinedColors.removeAt(i);
if (colors.count() == max)
diff --git a/examples/embedded/lightmaps/lightmaps.cpp b/examples/embedded/lightmaps/lightmaps.cpp
index a8bc13beaf..6334530c3a 100644
--- a/examples/embedded/lightmaps/lightmaps.cpp
+++ b/examples/embedded/lightmaps/lightmaps.cpp
@@ -52,15 +52,9 @@
#include <QtWidgets>
#include <QtNetwork>
-#include <math.h>
-
#include "lightmaps.h"
#include "slippymap.h"
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
// how long (milliseconds) the user need to hold (after a tap on the screen)
// before triggering the magnifying glass feature
// 701, a prime number, is the sum of 229, 233, 239
diff --git a/examples/embedded/lightmaps/slippymap.cpp b/examples/embedded/lightmaps/slippymap.cpp
index 7e847c2501..ff43261700 100644
--- a/examples/embedded/lightmaps/slippymap.cpp
+++ b/examples/embedded/lightmaps/slippymap.cpp
@@ -48,15 +48,10 @@
**
****************************************************************************/
-#include <math.h>
-
#include <QtWidgets>
#include <QtNetwork>
#include "slippymap.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
+#include "qmath.h"
uint qHash(const QPoint& p)
{
@@ -68,10 +63,10 @@ const int tdim = 256;
QPointF tileForCoordinate(qreal lat, qreal lng, int zoom)
{
+ qreal radianLat = qDegreesToRadians(lat);
qreal zn = static_cast<qreal>(1 << zoom);
qreal tx = (lng + 180.0) / 360.0;
- qreal ty = (1.0 - log(tan(lat * M_PI / 180.0) +
- 1.0 / cos(lat * M_PI / 180.0)) / M_PI) / 2.0;
+ qreal ty = 0.5 - log(tan(radianLat) + 1.0 / cos(radianLat)) / M_PI / 2.0;
return QPointF(tx * zn, ty * zn);
}
@@ -86,8 +81,7 @@ qreal latitudeFromTile(qreal ty, int zoom)
{
qreal zn = static_cast<qreal>(1 << zoom);
qreal n = M_PI - 2 * M_PI * ty / zn;
- qreal lng = 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
- return lng;
+ return qRadiansToDegrees(atan(sinh(n)));
}
diff --git a/examples/embedded/raycasting/raycasting.cpp b/examples/embedded/raycasting/raycasting.cpp
index 992c383db1..d37b9f5d2e 100644
--- a/examples/embedded/raycasting/raycasting.cpp
+++ b/examples/embedded/raycasting/raycasting.cpp
@@ -50,12 +50,7 @@
#include <QtCore>
#include <QtWidgets>
-
-#include <math.h>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
+#include <qmath.h>
#define WORLD_SIZE 8
int world_map[WORLD_SIZE][WORLD_SIZE] = {
diff --git a/examples/examples.pro b/examples/examples.pro
index d87fa2da88..4ec5ca60e2 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -14,8 +14,11 @@ qtHaveModule(concurrent): SUBDIRS += qtconcurrent
qtHaveModule(sql): SUBDIRS += sql
qtHaveModule(widgets): SUBDIRS += widgets
qtHaveModule(xml): SUBDIRS += xml
-qtHaveModule(gui): SUBDIRS += gui
-qtHaveModule(gui):qtConfig(opengl): SUBDIRS += opengl
+qtHaveModule(gui) {
+ SUBDIRS += gui
+ qtConfig(opengl): SUBDIRS += opengl
+ qtConfig(vulkan): SUBDIRS += vulkan
+}
aggregate.files = aggregate/examples.pro
aggregate.path = $$[QT_INSTALL_EXAMPLES]
diff --git a/examples/network/broadcastreceiver/receiver.cpp b/examples/network/broadcastreceiver/receiver.cpp
index 4225a19746..2f111b4795 100644
--- a/examples/network/broadcastreceiver/receiver.cpp
+++ b/examples/network/broadcastreceiver/receiver.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -59,7 +59,7 @@ Receiver::Receiver(QWidget *parent)
statusLabel = new QLabel(tr("Listening for broadcasted messages"));
statusLabel->setWordWrap(true);
- quitButton = new QPushButton(tr("&Quit"));
+ auto quitButton = new QPushButton(tr("&Quit"));
//! [0]
udpSocket = new QUdpSocket(this);
@@ -72,12 +72,12 @@ Receiver::Receiver(QWidget *parent)
//! [1]
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
- QHBoxLayout *buttonLayout = new QHBoxLayout;
+ auto buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(1);
buttonLayout->addWidget(quitButton);
buttonLayout->addStretch(1);
- QVBoxLayout *mainLayout = new QVBoxLayout;
+ auto mainLayout = new QVBoxLayout;
mainLayout->addWidget(statusLabel);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
@@ -87,13 +87,13 @@ Receiver::Receiver(QWidget *parent)
void Receiver::processPendingDatagrams()
{
+ QByteArray datagram;
//! [2]
while (udpSocket->hasPendingDatagrams()) {
- QByteArray datagram;
- datagram.resize(udpSocket->pendingDatagramSize());
+ datagram.resize(int(udpSocket->pendingDatagramSize()));
udpSocket->readDatagram(datagram.data(), datagram.size());
statusLabel->setText(tr("Received datagram: \"%1\"")
- .arg(datagram.data()));
+ .arg(datagram.constData()));
}
//! [2]
}
diff --git a/examples/network/broadcastreceiver/receiver.h b/examples/network/broadcastreceiver/receiver.h
index 71b91246fc..e6f8d97c23 100644
--- a/examples/network/broadcastreceiver/receiver.h
+++ b/examples/network/broadcastreceiver/receiver.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -55,9 +55,7 @@
QT_BEGIN_NAMESPACE
class QLabel;
-class QPushButton;
class QUdpSocket;
-class QAction;
QT_END_NAMESPACE
class Receiver : public QWidget
@@ -65,15 +63,14 @@ class Receiver : public QWidget
Q_OBJECT
public:
- Receiver(QWidget *parent = 0);
+ explicit Receiver(QWidget *parent = nullptr);
private slots:
void processPendingDatagrams();
private:
- QLabel *statusLabel;
- QPushButton *quitButton;
- QUdpSocket *udpSocket;
+ QLabel *statusLabel = nullptr;
+ QUdpSocket *udpSocket = nullptr;
};
#endif
diff --git a/examples/network/broadcastsender/sender.cpp b/examples/network/broadcastsender/sender.cpp
index 344f898683..ee4896e9dd 100644
--- a/examples/network/broadcastsender/sender.cpp
+++ b/examples/network/broadcastsender/sender.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -50,6 +50,7 @@
#include <QtWidgets>
#include <QtNetwork>
+#include <QtCore>
#include "sender.h"
@@ -60,23 +61,21 @@ Sender::Sender(QWidget *parent)
statusLabel->setWordWrap(true);
startButton = new QPushButton(tr("&Start"));
- quitButton = new QPushButton(tr("&Quit"));
+ auto quitButton = new QPushButton(tr("&Quit"));
- buttonBox = new QDialogButtonBox;
+ auto buttonBox = new QDialogButtonBox;
buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
- timer = new QTimer(this);
//! [0]
udpSocket = new QUdpSocket(this);
//! [0]
- messageNo = 1;
- connect(startButton, SIGNAL(clicked()), this, SLOT(startBroadcasting()));
- connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
- connect(timer, SIGNAL(timeout()), this, SLOT(broadcastDatagram()));
+ connect(startButton, &QPushButton::clicked, this, &Sender::startBroadcasting);
+ connect(quitButton, &QPushButton::clicked, this, &Sender::close);
+ connect(&timer, &QTimer::timeout, this, &Sender::broadcastDatagram);
- QVBoxLayout *mainLayout = new QVBoxLayout;
+ auto mainLayout = new QVBoxLayout;
mainLayout->addWidget(statusLabel);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
@@ -87,7 +86,7 @@ Sender::Sender(QWidget *parent)
void Sender::startBroadcasting()
{
startButton->setEnabled(false);
- timer->start(1000);
+ timer.start(1000);
}
void Sender::broadcastDatagram()
@@ -95,8 +94,7 @@ void Sender::broadcastDatagram()
statusLabel->setText(tr("Now broadcasting datagram %1").arg(messageNo));
//! [1]
QByteArray datagram = "Broadcast message " + QByteArray::number(messageNo);
- udpSocket->writeDatagram(datagram.data(), datagram.size(),
- QHostAddress::Broadcast, 45454);
+ udpSocket->writeDatagram(datagram, QHostAddress::Broadcast, 45454);
//! [1]
++messageNo;
}
diff --git a/examples/network/broadcastsender/sender.h b/examples/network/broadcastsender/sender.h
index e9c1076dd3..f91c7769ec 100644
--- a/examples/network/broadcastsender/sender.h
+++ b/examples/network/broadcastsender/sender.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -52,12 +52,11 @@
#define SENDER_H
#include <QWidget>
+#include <QTimer>
QT_BEGIN_NAMESPACE
-class QDialogButtonBox;
class QLabel;
class QPushButton;
-class QTimer;
class QUdpSocket;
QT_END_NAMESPACE
@@ -66,20 +65,18 @@ class Sender : public QWidget
Q_OBJECT
public:
- Sender(QWidget *parent = 0);
+ explicit Sender(QWidget *parent = nullptr);
private slots:
void startBroadcasting();
void broadcastDatagram();
private:
- QLabel *statusLabel;
- QPushButton *startButton;
- QPushButton *quitButton;
- QDialogButtonBox *buttonBox;
- QUdpSocket *udpSocket;
- QTimer *timer;
- int messageNo;
+ QLabel *statusLabel = nullptr;
+ QPushButton *startButton = nullptr;
+ QUdpSocket *udpSocket = nullptr;
+ QTimer timer;
+ int messageNo = 1;
};
#endif
diff --git a/examples/network/doc/images/http-example.png b/examples/network/doc/images/http-example.png
index 16b0539b1b..c5f3ef1649 100644
--- a/examples/network/doc/images/http-example.png
+++ b/examples/network/doc/images/http-example.png
Binary files differ
diff --git a/examples/network/download/main.cpp b/examples/network/download/main.cpp
index e5ad050de3..96111983ea 100644
--- a/examples/network/download/main.cpp
+++ b/examples/network/download/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -48,37 +48,29 @@
**
****************************************************************************/
-#include <QCoreApplication>
-#include <QFile>
-#include <QFileInfo>
-#include <QList>
-#include <QNetworkAccessManager>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#include <QSslError>
-#include <QStringList>
-#include <QTimer>
-#include <QUrl>
+#include <QtCore>
+#include <QtNetwork>
-#include <stdio.h>
+#include <cstdio>
QT_BEGIN_NAMESPACE
class QSslError;
QT_END_NAMESPACE
-QT_USE_NAMESPACE
+using namespace std;
class DownloadManager: public QObject
{
Q_OBJECT
QNetworkAccessManager manager;
- QList<QNetworkReply *> currentDownloads;
+ QVector<QNetworkReply *> currentDownloads;
public:
DownloadManager();
void doDownload(const QUrl &url);
- QString saveFileName(const QUrl &url);
+ static QString saveFileName(const QUrl &url);
bool saveToDisk(const QString &filename, QIODevice *data);
+ static bool isHttpRedirect(QNetworkReply *reply);
public slots:
void execute();
@@ -97,8 +89,9 @@ void DownloadManager::doDownload(const QUrl &url)
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
-#ifndef QT_NO_SSL
- connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(sslErrors(QList<QSslError>)));
+#if QT_CONFIG(ssl)
+ connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
+ SLOT(sslErrors(QList<QSslError>)));
#endif
currentDownloads.append(reply);
@@ -141,6 +134,13 @@ bool DownloadManager::saveToDisk(const QString &filename, QIODevice *data)
return true;
}
+bool DownloadManager::isHttpRedirect(QNetworkReply *reply)
+{
+ int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ return statusCode == 301 || statusCode == 302 || statusCode == 303
+ || statusCode == 305 || statusCode == 307 || statusCode == 308;
+}
+
void DownloadManager::execute()
{
QStringList args = QCoreApplication::instance()->arguments();
@@ -156,7 +156,7 @@ void DownloadManager::execute()
return;
}
- foreach (QString arg, args) {
+ for (const QString &arg : qAsConst(args)) {
QUrl url = QUrl::fromEncoded(arg.toLocal8Bit());
doDownload(url);
}
@@ -164,8 +164,8 @@ void DownloadManager::execute()
void DownloadManager::sslErrors(const QList<QSslError> &sslErrors)
{
-#ifndef QT_NO_SSL
- foreach (const QSslError &error, sslErrors)
+#if QT_CONFIG(ssl)
+ for (const QSslError &error : sslErrors)
fprintf(stderr, "SSL error: %s\n", qPrintable(error.errorString()));
#else
Q_UNUSED(sslErrors);
@@ -180,18 +180,24 @@ void DownloadManager::downloadFinished(QNetworkReply *reply)
url.toEncoded().constData(),
qPrintable(reply->errorString()));
} else {
- QString filename = saveFileName(url);
- if (saveToDisk(filename, reply))
- printf("Download of %s succeeded (saved to %s)\n",
- url.toEncoded().constData(), qPrintable(filename));
+ if (isHttpRedirect(reply)) {
+ fputs("Request was redirected.\n", stderr);
+ } else {
+ QString filename = saveFileName(url);
+ if (saveToDisk(filename, reply)) {
+ printf("Download of %s succeeded (saved to %s)\n",
+ url.toEncoded().constData(), qPrintable(filename));
+ }
+ }
}
currentDownloads.removeAll(reply);
reply->deleteLater();
- if (currentDownloads.isEmpty())
+ if (currentDownloads.isEmpty()) {
// all downloads finished
QCoreApplication::instance()->quit();
+ }
}
int main(int argc, char **argv)
diff --git a/examples/network/downloadmanager/downloadmanager.cpp b/examples/network/downloadmanager/downloadmanager.cpp
index 69d8fd1ebc..e820b4ff70 100644
--- a/examples/network/downloadmanager/downloadmanager.cpp
+++ b/examples/network/downloadmanager/downloadmanager.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -50,23 +50,21 @@
#include "downloadmanager.h"
-#include <QFileInfo>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#include <QString>
-#include <QStringList>
-#include <QTimer>
-#include <stdio.h>
+#include <QTextStream>
+
+#include <cstdio>
+
+using namespace std;
DownloadManager::DownloadManager(QObject *parent)
- : QObject(parent), downloadedCount(0), totalCount(0)
+ : QObject(parent)
{
}
-void DownloadManager::append(const QStringList &urlList)
+void DownloadManager::append(const QStringList &urls)
{
- foreach (QString url, urlList)
- append(QUrl::fromEncoded(url.toLocal8Bit()));
+ for (const QString &urlAsString : urls)
+ append(QUrl::fromEncoded(urlAsString.toLocal8Bit()));
if (downloadQueue.isEmpty())
QTimer::singleShot(0, this, SIGNAL(finished()));
@@ -167,9 +165,16 @@ void DownloadManager::downloadFinished()
if (currentDownload->error()) {
// download failed
fprintf(stderr, "Failed: %s\n", qPrintable(currentDownload->errorString()));
+ output.remove();
} else {
- printf("Succeeded.\n");
- ++downloadedCount;
+ // let's check if it was actually a redirect
+ if (isHttpRedirect()) {
+ reportRedirect();
+ output.remove();
+ } else {
+ printf("Succeeded.\n");
+ ++downloadedCount;
+ }
}
currentDownload->deleteLater();
@@ -180,3 +185,28 @@ void DownloadManager::downloadReadyRead()
{
output.write(currentDownload->readAll());
}
+
+bool DownloadManager::isHttpRedirect() const
+{
+ int statusCode = currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ return statusCode == 301 || statusCode == 302 || statusCode == 303
+ || statusCode == 305 || statusCode == 307 || statusCode == 308;
+}
+
+void DownloadManager::reportRedirect()
+{
+ int statusCode = currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ QUrl requestUrl = currentDownload->request().url();
+ QTextStream(stderr) << "Request: " << requestUrl.toDisplayString()
+ << " was redirected with code: " << statusCode
+ << '\n';
+
+ QVariant target = currentDownload->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (!target.isValid())
+ return;
+ QUrl redirectUrl = target.toUrl();
+ if (redirectUrl.isRelative())
+ redirectUrl = requestUrl.resolved(redirectUrl);
+ QTextStream(stderr) << "Redirected to: " << redirectUrl.toDisplayString()
+ << '\n';
+}
diff --git a/examples/network/downloadmanager/downloadmanager.h b/examples/network/downloadmanager/downloadmanager.h
index 550a197ef8..4bc6351ff9 100644
--- a/examples/network/downloadmanager/downloadmanager.h
+++ b/examples/network/downloadmanager/downloadmanager.h
@@ -51,12 +51,8 @@
#ifndef DOWNLOADMANAGER_H
#define DOWNLOADMANAGER_H
-#include <QFile>
-#include <QObject>
-#include <QQueue>
-#include <QTime>
-#include <QUrl>
-#include <QNetworkAccessManager>
+#include <QtNetwork>
+#include <QtCore>
#include "textprogressbar.h"
@@ -64,11 +60,11 @@ class DownloadManager: public QObject
{
Q_OBJECT
public:
- DownloadManager(QObject *parent = 0);
+ explicit DownloadManager(QObject *parent = nullptr);
void append(const QUrl &url);
- void append(const QStringList &urlList);
- QString saveFileName(const QUrl &url);
+ void append(const QStringList &urls);
+ static QString saveFileName(const QUrl &url);
signals:
void finished();
@@ -80,15 +76,18 @@ private slots:
void downloadReadyRead();
private:
+ bool isHttpRedirect() const;
+ void reportRedirect();
+
QNetworkAccessManager manager;
QQueue<QUrl> downloadQueue;
- QNetworkReply *currentDownload;
+ QNetworkReply *currentDownload = nullptr;
QFile output;
QTime downloadTime;
TextProgressBar progressBar;
- int downloadedCount;
- int totalCount;
+ int downloadedCount = 0;
+ int totalCount = 0;
};
#endif
diff --git a/examples/network/downloadmanager/main.cpp b/examples/network/downloadmanager/main.cpp
index 158f04c9e6..e3ba490992 100644
--- a/examples/network/downloadmanager/main.cpp
+++ b/examples/network/downloadmanager/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -50,11 +50,15 @@
#include <QCoreApplication>
#include <QStringList>
+
#include "downloadmanager.h"
-#include <stdio.h>
+
+#include <cstdio>
int main(int argc, char **argv)
{
+ using namespace std;
+
QCoreApplication app(argc, argv);
QStringList arguments = app.arguments();
arguments.takeFirst(); // remove the first argument, which is the program's name
diff --git a/examples/network/downloadmanager/textprogressbar.cpp b/examples/network/downloadmanager/textprogressbar.cpp
index d9506a563a..3449e6bad5 100644
--- a/examples/network/downloadmanager/textprogressbar.cpp
+++ b/examples/network/downloadmanager/textprogressbar.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -49,22 +49,21 @@
****************************************************************************/
#include "textprogressbar.h"
+
#include <QByteArray>
-#include <stdio.h>
-TextProgressBar::TextProgressBar()
- : value(0), maximum(-1), iteration(0)
-{
-}
+#include <cstdio>
+
+using namespace std;
void TextProgressBar::clear()
{
printf("\n");
fflush(stdout);
- iteration = 0;
value = 0;
maximum = -1;
+ iteration = 0;
}
void TextProgressBar::update()
diff --git a/examples/network/downloadmanager/textprogressbar.h b/examples/network/downloadmanager/textprogressbar.h
index 57bcd6e92a..30affeb55c 100644
--- a/examples/network/downloadmanager/textprogressbar.h
+++ b/examples/network/downloadmanager/textprogressbar.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -56,8 +56,6 @@
class TextProgressBar
{
public:
- TextProgressBar();
-
void clear();
void update();
void setMessage(const QString &message);
@@ -65,9 +63,9 @@ public:
private:
QString message;
- qint64 value;
- qint64 maximum;
- int iteration;
+ qint64 value = 0;
+ qint64 maximum = -1;
+ int iteration = 0;
};
#endif
diff --git a/examples/network/fortuneclient/client.cpp b/examples/network/fortuneclient/client.cpp
index c0043e246f..4d3a318a7b 100644
--- a/examples/network/fortuneclient/client.cpp
+++ b/examples/network/fortuneclient/client.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -60,7 +60,6 @@ Client::Client(QWidget *parent)
, portLineEdit(new QLineEdit)
, getFortuneButton(new QPushButton(tr("Get Fortune")))
, tcpSocket(new QTcpSocket(this))
- , networkSession(Q_NULLPTR)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
//! [0]
@@ -90,9 +89,9 @@ Client::Client(QWidget *parent)
portLineEdit->setValidator(new QIntValidator(1, 65535, this));
- QLabel *hostLabel = new QLabel(tr("&Server name:"));
+ auto hostLabel = new QLabel(tr("&Server name:"));
hostLabel->setBuddy(hostCombo);
- QLabel *portLabel = new QLabel(tr("S&erver port:"));
+ auto portLabel = new QLabel(tr("S&erver port:"));
portLabel->setBuddy(portLineEdit);
statusLabel = new QLabel(tr("This examples requires that you run the "
@@ -101,9 +100,9 @@ Client::Client(QWidget *parent)
getFortuneButton->setDefault(true);
getFortuneButton->setEnabled(false);
- QPushButton *quitButton = new QPushButton(tr("Quit"));
+ auto quitButton = new QPushButton(tr("Quit"));
- QDialogButtonBox *buttonBox = new QDialogButtonBox;
+ auto buttonBox = new QDialogButtonBox;
buttonBox->addButton(getFortuneButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
@@ -127,13 +126,13 @@ Client::Client(QWidget *parent)
this, &Client::displayError);
//! [4]
- QGridLayout *mainLayout = Q_NULLPTR;
+ QGridLayout *mainLayout = nullptr;
if (QGuiApplication::styleHints()->showIsFullScreen() || QGuiApplication::styleHints()->showIsMaximized()) {
- QVBoxLayout *outerVerticalLayout = new QVBoxLayout(this);
+ auto outerVerticalLayout = new QVBoxLayout(this);
outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
- QHBoxLayout *outerHorizontalLayout = new QHBoxLayout;
+ auto outerHorizontalLayout = new QHBoxLayout;
outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
- QGroupBox *groupBox = new QGroupBox(QGuiApplication::applicationDisplayName());
+ auto groupBox = new QGroupBox(QGuiApplication::applicationDisplayName());
mainLayout = new QGridLayout(groupBox);
outerHorizontalLayout->addWidget(groupBox);
outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
diff --git a/examples/network/fortuneclient/client.h b/examples/network/fortuneclient/client.h
index 8037e9b047..ac335acb83 100644
--- a/examples/network/fortuneclient/client.h
+++ b/examples/network/fortuneclient/client.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -51,9 +51,9 @@
#ifndef CLIENT_H
#define CLIENT_H
+#include <QDataStream>
#include <QDialog>
#include <QTcpSocket>
-#include <QDataStream>
QT_BEGIN_NAMESPACE
class QComboBox;
@@ -70,7 +70,7 @@ class Client : public QDialog
Q_OBJECT
public:
- explicit Client(QWidget *parent = Q_NULLPTR);
+ explicit Client(QWidget *parent = nullptr);
private slots:
void requestNewFortune();
@@ -80,16 +80,16 @@ private slots:
void sessionOpened();
private:
- QComboBox *hostCombo;
- QLineEdit *portLineEdit;
- QLabel *statusLabel;
- QPushButton *getFortuneButton;
+ QComboBox *hostCombo = nullptr;
+ QLineEdit *portLineEdit = nullptr;
+ QLabel *statusLabel = nullptr;
+ QPushButton *getFortuneButton = nullptr;
- QTcpSocket *tcpSocket;
+ QTcpSocket *tcpSocket = nullptr;
QDataStream in;
QString currentFortune;
- QNetworkSession *networkSession;
+ QNetworkSession *networkSession = nullptr;
};
//! [0]
diff --git a/examples/network/fortuneclient/main.cpp b/examples/network/fortuneclient/main.cpp
index e313b251ef..6b02708ce1 100644
--- a/examples/network/fortuneclient/main.cpp
+++ b/examples/network/fortuneclient/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -54,7 +54,7 @@
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
- QGuiApplication::setApplicationDisplayName(Client::tr("Fortune Client"));
+ QApplication::setApplicationDisplayName(Client::tr("Fortune Client"));
Client client;
client.show();
return app.exec();
diff --git a/examples/network/fortuneserver/main.cpp b/examples/network/fortuneserver/main.cpp
index 12137d647c..a64fcb26dc 100644
--- a/examples/network/fortuneserver/main.cpp
+++ b/examples/network/fortuneserver/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -49,18 +49,14 @@
****************************************************************************/
#include <QApplication>
-#include <QtCore>
-
-#include <stdlib.h>
#include "server.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
- QGuiApplication::setApplicationDisplayName(Server::tr("Fortune Server"));
+ QApplication::setApplicationDisplayName(Server::tr("Fortune Server"));
Server server;
server.show();
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
return app.exec();
}
diff --git a/examples/network/fortuneserver/server.cpp b/examples/network/fortuneserver/server.cpp
index f027d68dd9..7db81fe07a 100644
--- a/examples/network/fortuneserver/server.cpp
+++ b/examples/network/fortuneserver/server.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -50,16 +50,13 @@
#include <QtWidgets>
#include <QtNetwork>
-
-#include <stdlib.h>
+#include <QtCore>
#include "server.h"
Server::Server(QWidget *parent)
: QDialog(parent)
, statusLabel(new QLabel)
- , tcpServer(Q_NULLPTR)
- , networkSession(0)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
statusLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
@@ -89,46 +86,46 @@ Server::Server(QWidget *parent)
}
//! [2]
- fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
- << tr("You've got to think about tomorrow.")
- << tr("You will be surprised by a loud noise.")
- << tr("You will feel hungry again in another hour.")
- << tr("You might have mail.")
- << tr("You cannot kill time without injuring eternity.")
- << tr("Computers are not intelligent. They only think they are.");
+ fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
+ << tr("You've got to think about tomorrow.")
+ << tr("You will be surprised by a loud noise.")
+ << tr("You will feel hungry again in another hour.")
+ << tr("You might have mail.")
+ << tr("You cannot kill time without injuring eternity.")
+ << tr("Computers are not intelligent. They only think they are.");
//! [2]
- QPushButton *quitButton = new QPushButton(tr("Quit"));
- quitButton->setAutoDefault(false);
- connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close);
+ auto quitButton = new QPushButton(tr("Quit"));
+ quitButton->setAutoDefault(false);
+ connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close);
//! [3]
- connect(tcpServer, &QTcpServer::newConnection, this, &Server::sendFortune);
+ connect(tcpServer, &QTcpServer::newConnection, this, &Server::sendFortune);
//! [3]
- QHBoxLayout *buttonLayout = new QHBoxLayout;
- buttonLayout->addStretch(1);
- buttonLayout->addWidget(quitButton);
- buttonLayout->addStretch(1);
-
- QVBoxLayout *mainLayout = Q_NULLPTR;
- if (QGuiApplication::styleHints()->showIsFullScreen() || QGuiApplication::styleHints()->showIsMaximized()) {
- QVBoxLayout *outerVerticalLayout = new QVBoxLayout(this);
- outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
- QHBoxLayout *outerHorizontalLayout = new QHBoxLayout;
- outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
- QGroupBox *groupBox = new QGroupBox(QGuiApplication::applicationDisplayName());
- mainLayout = new QVBoxLayout(groupBox);
- outerHorizontalLayout->addWidget(groupBox);
- outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
- outerVerticalLayout->addLayout(outerHorizontalLayout);
- outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
- } else {
- mainLayout = new QVBoxLayout(this);
- }
+ auto buttonLayout = new QHBoxLayout;
+ buttonLayout->addStretch(1);
+ buttonLayout->addWidget(quitButton);
+ buttonLayout->addStretch(1);
+
+ QVBoxLayout *mainLayout = nullptr;
+ if (QGuiApplication::styleHints()->showIsFullScreen() || QGuiApplication::styleHints()->showIsMaximized()) {
+ auto outerVerticalLayout = new QVBoxLayout(this);
+ outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
+ auto outerHorizontalLayout = new QHBoxLayout;
+ outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
+ auto groupBox = new QGroupBox(QGuiApplication::applicationDisplayName());
+ mainLayout = new QVBoxLayout(groupBox);
+ outerHorizontalLayout->addWidget(groupBox);
+ outerHorizontalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
+ outerVerticalLayout->addLayout(outerHorizontalLayout);
+ outerVerticalLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
+ } else {
+ mainLayout = new QVBoxLayout(this);
+ }
- mainLayout->addWidget(statusLabel);
- mainLayout->addLayout(buttonLayout);
+ mainLayout->addWidget(statusLabel);
+ mainLayout->addLayout(buttonLayout);
- setWindowTitle(QGuiApplication::applicationDisplayName());
+ setWindowTitle(QGuiApplication::applicationDisplayName());
}
void Server::sessionOpened()
@@ -183,9 +180,9 @@ void Server::sendFortune()
//! [5]
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
- out.setVersion(QDataStream::Qt_4_0);
+ out.setVersion(QDataStream::Qt_5_10);
- out << fortunes.at(qrand() % fortunes.size());
+ out << fortunes[QRandomGenerator::global()->bounded(fortunes.size())];
//! [4] //! [7]
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
diff --git a/examples/network/fortuneserver/server.h b/examples/network/fortuneserver/server.h
index ea5ed78292..c5bfa7d928 100644
--- a/examples/network/fortuneserver/server.h
+++ b/examples/network/fortuneserver/server.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -52,10 +52,11 @@
#define SERVER_H
#include <QDialog>
+#include <QString>
+#include <QVector>
QT_BEGIN_NAMESPACE
class QLabel;
-class QPushButton;
class QTcpServer;
class QNetworkSession;
QT_END_NAMESPACE
@@ -66,17 +67,17 @@ class Server : public QDialog
Q_OBJECT
public:
- explicit Server(QWidget *parent = Q_NULLPTR);
+ explicit Server(QWidget *parent = nullptr);
private slots:
void sessionOpened();
void sendFortune();
private:
- QLabel *statusLabel;
- QTcpServer *tcpServer;
- QStringList fortunes;
- QNetworkSession *networkSession;
+ QLabel *statusLabel = nullptr;
+ QTcpServer *tcpServer = nullptr;
+ QVector<QString> fortunes;
+ QNetworkSession *networkSession = nullptr;
};
//! [0]
diff --git a/examples/network/googlesuggest/googlesuggest.cpp b/examples/network/googlesuggest/googlesuggest.cpp
index 9fdfd8faa6..24fdde0a5c 100644
--- a/examples/network/googlesuggest/googlesuggest.cpp
+++ b/examples/network/googlesuggest/googlesuggest.cpp
@@ -51,7 +51,7 @@
//! [1]
#include "googlesuggest.h"
-#define GSUGGEST_URL "http://google.com/complete/search?output=toolbar&q=%1"
+const QString gsuggestUrl(QStringLiteral("http://google.com/complete/search?output=toolbar&q=%1"));
//! [1]
//! [2]
@@ -77,11 +77,10 @@ GSuggestCompletion::GSuggestCompletion(QLineEdit *parent): QObject(parent), edit
connect(popup, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
SLOT(doneCompletion()));
- timer = new QTimer(this);
- timer->setSingleShot(true);
- timer->setInterval(500);
- connect(timer, SIGNAL(timeout()), SLOT(autoSuggest()));
- connect(editor, SIGNAL(textEdited(QString)), timer, SLOT(start()));
+ timer.setSingleShot(true);
+ timer.setInterval(500);
+ connect(&timer, SIGNAL(timeout()), SLOT(autoSuggest()));
+ connect(editor, SIGNAL(textEdited(QString)), &timer, SLOT(start()));
connect(&networkManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(handleNetworkData(QNetworkReply*)));
@@ -109,7 +108,6 @@ bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev)
}
if (ev->type() == QEvent::KeyPress) {
-
bool consumed = false;
int key = static_cast<QKeyEvent*>(ev)->key();
switch (key) {
@@ -148,9 +146,8 @@ bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev)
//! [4]
//! [5]
-void GSuggestCompletion::showCompletion(const QStringList &choices)
+void GSuggestCompletion::showCompletion(const QVector<QString> &choices)
{
-
if (choices.isEmpty())
return;
@@ -159,12 +156,13 @@ void GSuggestCompletion::showCompletion(const QStringList &choices)
popup->setUpdatesEnabled(false);
popup->clear();
- for (int i = 0; i < choices.count(); ++i) {
- QTreeWidgetItem * item;
- item = new QTreeWidgetItem(popup);
- item->setText(0, choices[i]);
+
+ for (const auto &choice : choices) {
+ auto item = new QTreeWidgetItem(popup);
+ item->setText(0, choice);
item->setTextColor(0, color);
}
+
popup->setCurrentItem(popup->topLevelItem(0));
popup->resizeColumnToContents(0);
popup->setUpdatesEnabled(true);
@@ -178,7 +176,7 @@ void GSuggestCompletion::showCompletion(const QStringList &choices)
//! [6]
void GSuggestCompletion::doneCompletion()
{
- timer->stop();
+ timer.stop();
popup->hide();
editor->setFocus();
QTreeWidgetItem *item = popup->currentItem();
@@ -193,15 +191,15 @@ void GSuggestCompletion::doneCompletion()
void GSuggestCompletion::autoSuggest()
{
QString str = editor->text();
- QString url = QString(GSUGGEST_URL).arg(str);
- networkManager.get(QNetworkRequest(QString(url)));
+ QString url = gsuggestUrl.arg(str);
+ networkManager.get(QNetworkRequest(url));
}
//! [7]
//! [8]
void GSuggestCompletion::preventSuggest()
{
- timer->stop();
+ timer.stop();
}
//! [8]
@@ -209,8 +207,8 @@ void GSuggestCompletion::preventSuggest()
void GSuggestCompletion::handleNetworkData(QNetworkReply *networkReply)
{
QUrl url = networkReply->url();
- if (!networkReply->error()) {
- QStringList choices;
+ if (networkReply->error() == QNetworkReply::NoError) {
+ QVector<QString> choices;
QByteArray response(networkReply->readAll());
QXmlStreamReader xml(response);
diff --git a/examples/network/googlesuggest/googlesuggest.h b/examples/network/googlesuggest/googlesuggest.h
index 1d42f31571..a0b0ac069c 100644
--- a/examples/network/googlesuggest/googlesuggest.h
+++ b/examples/network/googlesuggest/googlesuggest.h
@@ -53,14 +53,7 @@
#include <QtWidgets>
#include <QtNetwork>
-#include <QObject>
-
-QT_BEGIN_NAMESPACE
-class QLineEdit;
-class QNetworkReply;
-class QTimer;
-class QTreeWidget;
-QT_END_NAMESPACE
+#include <QtCore>
//! [1]
class GSuggestCompletion : public QObject
@@ -68,10 +61,10 @@ class GSuggestCompletion : public QObject
Q_OBJECT
public:
- GSuggestCompletion(QLineEdit *parent = 0);
+ explicit GSuggestCompletion(QLineEdit *parent = nullptr);
~GSuggestCompletion();
bool eventFilter(QObject *obj, QEvent *ev) override;
- void showCompletion(const QStringList &choices);
+ void showCompletion(const QVector<QString> &choices);
public slots:
@@ -81,9 +74,9 @@ public slots:
void handleNetworkData(QNetworkReply *networkReply);
private:
- QLineEdit *editor;
- QTreeWidget *popup;
- QTimer *timer;
+ QLineEdit *editor = nullptr;
+ QTreeWidget *popup = nullptr;
+ QTimer timer;
QNetworkAccessManager networkManager;
};
//! [1]
diff --git a/examples/network/googlesuggest/main.cpp b/examples/network/googlesuggest/main.cpp
index 9de966d7a5..ab819c5502 100644
--- a/examples/network/googlesuggest/main.cpp
+++ b/examples/network/googlesuggest/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -55,7 +55,7 @@
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
- SearchBox *searchEdit = new SearchBox;
- searchEdit->show();
+ SearchBox searchEdit;
+ searchEdit.show();
return app.exec();
}
diff --git a/examples/network/googlesuggest/searchbox.cpp b/examples/network/googlesuggest/searchbox.cpp
index e0754a7de2..d0bdb70daa 100644
--- a/examples/network/googlesuggest/searchbox.cpp
+++ b/examples/network/googlesuggest/searchbox.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -54,7 +54,7 @@
#include "searchbox.h"
#include "googlesuggest.h"
-#define GSEARCH_URL "http://www.google.com/search?q=%1"
+const QString gsearchUrl = QStringLiteral("http://www.google.com/search?q=%1");
//! [1]
SearchBox::SearchBox(QWidget *parent): QLineEdit(parent)
@@ -75,8 +75,8 @@ SearchBox::SearchBox(QWidget *parent): QLineEdit(parent)
void SearchBox::doSearch()
{
completer->preventSuggest();
- QString url = QString(GSEARCH_URL).arg(text());
- QDesktopServices::openUrl(QUrl(url));
+ QString url = gsearchUrl.arg(text());
+ QDesktopServices::openUrl(url);
}
//! [2]
diff --git a/examples/network/googlesuggest/searchbox.h b/examples/network/googlesuggest/searchbox.h
index eea5854de8..fbd33011b7 100644
--- a/examples/network/googlesuggest/searchbox.h
+++ b/examples/network/googlesuggest/searchbox.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -61,13 +61,13 @@ class SearchBox: public QLineEdit
Q_OBJECT
public:
- SearchBox(QWidget *parent = 0);
+ explicit SearchBox(QWidget *parent = nullptr);
protected slots:
void doSearch();
private:
- GSuggestCompletion *completer;
+ GSuggestCompletion *completer = nullptr;
//! [1]
};
diff --git a/examples/network/http/httpwindow.cpp b/examples/network/http/httpwindow.cpp
index fddd2c809a..ec90b8f7fe 100644
--- a/examples/network/http/httpwindow.cpp
+++ b/examples/network/http/httpwindow.cpp
@@ -55,12 +55,12 @@
#include "httpwindow.h"
#include "ui_authenticationdialog.h"
-#ifndef QT_NO_SSL
-static const char defaultUrl[] = "https://www.qt.io/";
+#if QT_CONFIG(ssl)
+const char defaultUrl[] = "https://www.qt.io/";
#else
-static const char defaultUrl[] = "http://www.qt.io/";
+const char defaultUrl[] = "http://www.qt.io/";
#endif
-static const char defaultFileName[] = "index.html";
+const char defaultFileName[] = "index.html";
ProgressDialog::ProgressDialog(const QUrl &url, QWidget *parent)
: QProgressDialog(parent)
@@ -71,6 +71,7 @@ ProgressDialog::ProgressDialog(const QUrl &url, QWidget *parent)
setMinimum(0);
setValue(0);
setMinimumDuration(0);
+ setMinimumSize(QSize(400, 75));
}
void ProgressDialog::networkReplyProgress(qint64 bytesRead, qint64 totalBytes)
@@ -87,8 +88,8 @@ HttpWindow::HttpWindow(QWidget *parent)
, launchCheckBox(new QCheckBox("Launch file"))
, defaultFileLineEdit(new QLineEdit(defaultFileName))
, downloadDirectoryLineEdit(new QLineEdit)
- , reply(Q_NULLPTR)
- , file(Q_NULLPTR)
+ , reply(nullptr)
+ , file(nullptr)
, httpRequestAborted(false)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -174,15 +175,22 @@ void HttpWindow::downloadFile()
if (fileName.isEmpty())
fileName = defaultFileName;
QString downloadDirectory = QDir::cleanPath(downloadDirectoryLineEdit->text().trimmed());
- if (!downloadDirectory.isEmpty() && QFileInfo(downloadDirectory).isDir())
+ bool useDirectory = !downloadDirectory.isEmpty() && QFileInfo(downloadDirectory).isDir();
+ if (useDirectory)
fileName.prepend(downloadDirectory + '/');
if (QFile::exists(fileName)) {
if (QMessageBox::question(this, tr("Overwrite Existing File"),
- tr("There already exists a file called %1 in "
- "the current directory. Overwrite?").arg(fileName),
- QMessageBox::Yes|QMessageBox::No, QMessageBox::No)
- == QMessageBox::No)
+ tr("There already exists a file called %1%2."
+ " Overwrite?")
+ .arg(fileName,
+ useDirectory
+ ? QString()
+ : QStringLiteral(" in the current directory")),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No)
+ == QMessageBox::No) {
return;
+ }
QFile::remove(fileName);
}
@@ -204,7 +212,7 @@ QFile *HttpWindow::openFileForWrite(const QString &fileName)
tr("Unable to save the file %1: %2.")
.arg(QDir::toNativeSeparators(fileName),
file->errorString()));
- return Q_NULLPTR;
+ return nullptr;
}
return file.take();
}
@@ -224,12 +232,12 @@ void HttpWindow::httpFinished()
fi.setFile(file->fileName());
file->close();
delete file;
- file = Q_NULLPTR;
+ file = nullptr;
}
if (httpRequestAborted) {
reply->deleteLater();
- reply = Q_NULLPTR;
+ reply = nullptr;
return;
}
@@ -238,21 +246,23 @@ void HttpWindow::httpFinished()
statusLabel->setText(tr("Download failed:\n%1.").arg(reply->errorString()));
downloadButton->setEnabled(true);
reply->deleteLater();
- reply = Q_NULLPTR;
+ reply = nullptr;
return;
}
const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
reply->deleteLater();
- reply = Q_NULLPTR;
+ reply = nullptr;
if (!redirectionTarget.isNull()) {
const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());
if (QMessageBox::question(this, tr("Redirect"),
tr("Redirect to %1 ?").arg(redirectedUrl.toString()),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
+ QFile::remove(fi.absoluteFilePath());
downloadButton->setEnabled(true);
+ statusLabel->setText(tr("Download failed:\nRedirect rejected."));
return;
}
file = openFileForWrite(fi.absoluteFilePath());
@@ -286,7 +296,7 @@ void HttpWindow::enableDownloadButton()
downloadButton->setEnabled(!urlLineEdit->text().isEmpty());
}
-void HttpWindow::slotAuthenticationRequired(QNetworkReply*,QAuthenticator *authenticator)
+void HttpWindow::slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator)
{
QDialog authenticationDialog;
Ui::Dialog ui;
@@ -306,7 +316,7 @@ void HttpWindow::slotAuthenticationRequired(QNetworkReply*,QAuthenticator *authe
}
#ifndef QT_NO_SSL
-void HttpWindow::sslErrors(QNetworkReply*,const QList<QSslError> &errors)
+void HttpWindow::sslErrors(QNetworkReply *, const QList<QSslError> &errors)
{
QString errorString;
foreach (const QSslError &error, errors) {
diff --git a/examples/network/http/httpwindow.h b/examples/network/http/httpwindow.h
index 3bb43dbf89..20ad2bb4da 100644
--- a/examples/network/http/httpwindow.h
+++ b/examples/network/http/httpwindow.h
@@ -71,7 +71,7 @@ class ProgressDialog : public QProgressDialog {
Q_OBJECT
public:
- explicit ProgressDialog(const QUrl &url, QWidget *parent = Q_NULLPTR);
+ explicit ProgressDialog(const QUrl &url, QWidget *parent = nullptr);
public slots:
void networkReplyProgress(qint64 bytesRead, qint64 totalBytes);
@@ -82,7 +82,7 @@ class HttpWindow : public QDialog
Q_OBJECT
public:
- explicit HttpWindow(QWidget *parent = Q_NULLPTR);
+ explicit HttpWindow(QWidget *parent = nullptr);
void startRequest(const QUrl &requestedUrl);
@@ -92,9 +92,9 @@ private slots:
void httpFinished();
void httpReadyRead();
void enableDownloadButton();
- void slotAuthenticationRequired(QNetworkReply*,QAuthenticator *);
+ void slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator);
#ifndef QT_NO_SSL
- void sslErrors(QNetworkReply*,const QList<QSslError> &errors);
+ void sslErrors(QNetworkReply *, const QList<QSslError> &errors);
#endif
private:
diff --git a/examples/network/multicastreceiver/receiver.cpp b/examples/network/multicastreceiver/receiver.cpp
index 10154c60cc..8985ad1d82 100644
--- a/examples/network/multicastreceiver/receiver.cpp
+++ b/examples/network/multicastreceiver/receiver.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -54,41 +54,39 @@
#include "receiver.h"
Receiver::Receiver(QWidget *parent)
- : QDialog(parent)
+ : QDialog(parent),
+ groupAddress(QStringLiteral("239.255.43.21"))
{
- groupAddress = QHostAddress("239.255.43.21");
-
statusLabel = new QLabel(tr("Listening for multicasted messages"));
- quitButton = new QPushButton(tr("&Quit"));
-
- udpSocket = new QUdpSocket(this);
- udpSocket->bind(QHostAddress::AnyIPv4, 45454, QUdpSocket::ShareAddress);
- udpSocket->joinMulticastGroup(groupAddress);
-
- connect(udpSocket, SIGNAL(readyRead()),
- this, SLOT(processPendingDatagrams()));
- connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
+ auto quitButton = new QPushButton(tr("&Quit"));
- QHBoxLayout *buttonLayout = new QHBoxLayout;
+ auto buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(1);
buttonLayout->addWidget(quitButton);
buttonLayout->addStretch(1);
- QVBoxLayout *mainLayout = new QVBoxLayout;
+ auto mainLayout = new QVBoxLayout;
mainLayout->addWidget(statusLabel);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
setWindowTitle(tr("Multicast Receiver"));
+
+ udpSocket.bind(QHostAddress::AnyIPv4, 45454, QUdpSocket::ShareAddress);
+ udpSocket.joinMulticastGroup(groupAddress);
+
+ connect(&udpSocket, SIGNAL(readyRead()),
+ this, SLOT(processPendingDatagrams()));
+ connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
}
void Receiver::processPendingDatagrams()
{
- while (udpSocket->hasPendingDatagrams()) {
- QByteArray datagram;
- datagram.resize(udpSocket->pendingDatagramSize());
- udpSocket->readDatagram(datagram.data(), datagram.size());
+ QByteArray datagram;
+ while (udpSocket.hasPendingDatagrams()) {
+ datagram.resize(int(udpSocket.pendingDatagramSize()));
+ udpSocket.readDatagram(datagram.data(), datagram.size());
statusLabel->setText(tr("Received datagram: \"%1\"")
- .arg(datagram.data()));
+ .arg(datagram.constData()));
}
}
diff --git a/examples/network/multicastreceiver/receiver.h b/examples/network/multicastreceiver/receiver.h
index efef1cdb30..54927fdd63 100644
--- a/examples/network/multicastreceiver/receiver.h
+++ b/examples/network/multicastreceiver/receiver.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -53,11 +53,10 @@
#include <QDialog>
#include <QHostAddress>
+#include <QUdpSocket>
QT_BEGIN_NAMESPACE
class QLabel;
-class QPushButton;
-class QUdpSocket;
QT_END_NAMESPACE
class Receiver : public QDialog
@@ -65,15 +64,14 @@ class Receiver : public QDialog
Q_OBJECT
public:
- Receiver(QWidget *parent = 0);
+ explicit Receiver(QWidget *parent = nullptr);
private slots:
void processPendingDatagrams();
private:
- QLabel *statusLabel;
- QPushButton *quitButton;
- QUdpSocket *udpSocket;
+ QLabel *statusLabel = nullptr;
+ QUdpSocket udpSocket;
QHostAddress groupAddress;
};
diff --git a/examples/network/multicastsender/sender.cpp b/examples/network/multicastsender/sender.cpp
index 4aa65fee27..cb4bf45672 100644
--- a/examples/network/multicastsender/sender.cpp
+++ b/examples/network/multicastsender/sender.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -48,43 +48,35 @@
**
****************************************************************************/
-#include <QtWidgets>
-#include <QtNetwork>
-
#include "sender.h"
Sender::Sender(QWidget *parent)
- : QDialog(parent)
+ : QDialog(parent),
+ groupAddress(QStringLiteral("239.255.43.21"))
{
- groupAddress = QHostAddress("239.255.43.21");
-
statusLabel = new QLabel(tr("Ready to multicast datagrams to group %1 on port 45454").arg(groupAddress.toString()));
- ttlLabel = new QLabel(tr("TTL for multicast datagrams:"));
- ttlSpinBox = new QSpinBox;
+ auto ttlLabel = new QLabel(tr("TTL for multicast datagrams:"));
+ auto ttlSpinBox = new QSpinBox;
ttlSpinBox->setRange(0, 255);
- QHBoxLayout *ttlLayout = new QHBoxLayout;
+ auto ttlLayout = new QHBoxLayout;
ttlLayout->addWidget(ttlLabel);
ttlLayout->addWidget(ttlSpinBox);
startButton = new QPushButton(tr("&Start"));
- quitButton = new QPushButton(tr("&Quit"));
+ auto quitButton = new QPushButton(tr("&Quit"));
- buttonBox = new QDialogButtonBox;
+ auto buttonBox = new QDialogButtonBox;
buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
- timer = new QTimer(this);
- udpSocket = new QUdpSocket(this);
- messageNo = 1;
-
- connect(ttlSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ttlChanged(int)));
- connect(startButton, SIGNAL(clicked()), this, SLOT(startSending()));
- connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
- connect(timer, SIGNAL(timeout()), this, SLOT(sendDatagram()));
+ connect(ttlSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &Sender::ttlChanged);
+ connect(startButton, &QPushButton::clicked, this, &Sender::startSending);
+ connect(quitButton, &QPushButton::clicked, this, &Sender::close);
+ connect(&timer, &QTimer::timeout, this, &Sender::sendDatagram);
- QVBoxLayout *mainLayout = new QVBoxLayout;
+ auto mainLayout = new QVBoxLayout;
mainLayout->addWidget(statusLabel);
mainLayout->addLayout(ttlLayout);
mainLayout->addWidget(buttonBox);
@@ -96,20 +88,19 @@ Sender::Sender(QWidget *parent)
void Sender::ttlChanged(int newTtl)
{
- udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, newTtl);
+ udpSocket.setSocketOption(QAbstractSocket::MulticastTtlOption, newTtl);
}
void Sender::startSending()
{
startButton->setEnabled(false);
- timer->start(1000);
+ timer.start(1000);
}
void Sender::sendDatagram()
{
statusLabel->setText(tr("Now sending datagram %1").arg(messageNo));
QByteArray datagram = "Multicast message " + QByteArray::number(messageNo);
- udpSocket->writeDatagram(datagram.data(), datagram.size(),
- groupAddress, 45454);
+ udpSocket.writeDatagram(datagram, groupAddress, 45454);
++messageNo;
}
diff --git a/examples/network/multicastsender/sender.h b/examples/network/multicastsender/sender.h
index 8e10f88c0d..5d8769790e 100644
--- a/examples/network/multicastsender/sender.h
+++ b/examples/network/multicastsender/sender.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -51,24 +51,16 @@
#ifndef SENDER_H
#define SENDER_H
-#include <QDialog>
-#include <QHostAddress>
-
-QT_BEGIN_NAMESPACE
-class QDialogButtonBox;
-class QLabel;
-class QPushButton;
-class QTimer;
-class QUdpSocket;
-class QSpinBox;
-QT_END_NAMESPACE
+#include <QtWidgets>
+#include <QtNetwork>
+#include <QtCore>
class Sender : public QDialog
{
Q_OBJECT
public:
- Sender(QWidget *parent = 0);
+ explicit Sender(QWidget *parent = nullptr);
private slots:
void ttlChanged(int newTtl);
@@ -76,16 +68,12 @@ private slots:
void sendDatagram();
private:
- QLabel *statusLabel;
- QLabel *ttlLabel;
- QSpinBox *ttlSpinBox;
- QPushButton *startButton;
- QPushButton *quitButton;
- QDialogButtonBox *buttonBox;
- QUdpSocket *udpSocket;
- QTimer *timer;
+ QLabel *statusLabel = nullptr;
+ QPushButton *startButton = nullptr;
+ QUdpSocket udpSocket;
+ QTimer timer;
QHostAddress groupAddress;
- int messageNo;
+ int messageNo = 1;
};
#endif
diff --git a/examples/network/securesocketclient/certificateinfo.cpp b/examples/network/securesocketclient/certificateinfo.cpp
index c8cd86bc72..81429fc655 100644
--- a/examples/network/securesocketclient/certificateinfo.cpp
+++ b/examples/network/securesocketclient/certificateinfo.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -57,8 +57,8 @@ CertificateInfo::CertificateInfo(QWidget *parent)
form = new Ui_CertificateInfo;
form->setupUi(this);
- connect(form->certificationPathView, SIGNAL(currentIndexChanged(int)),
- this, SLOT(updateCertificateInfo(int)));
+ connect(form->certificationPathView, QOverload<int>::of(&QComboBox::currentIndexChanged),
+ this, &CertificateInfo::updateCertificateInfo);
}
CertificateInfo::~CertificateInfo()
@@ -68,25 +68,23 @@ CertificateInfo::~CertificateInfo()
void CertificateInfo::setCertificateChain(const QList<QSslCertificate> &chain)
{
- this->chain = chain;
+ certificateChain = chain;
form->certificationPathView->clear();
-
- for (int i = 0; i < chain.size(); ++i) {
- const QSslCertificate &cert = chain.at(i);
+ for (int i = 0; i < certificateChain.size(); ++i) {
+ const QSslCertificate &cert = certificateChain.at(i);
form->certificationPathView->addItem(tr("%1%2 (%3)").arg(!i ? QString() : tr("Issued by: "))
.arg(cert.subjectInfo(QSslCertificate::Organization).join(QLatin1Char(' ')))
.arg(cert.subjectInfo(QSslCertificate::CommonName).join(QLatin1Char(' '))));
}
-
form->certificationPathView->setCurrentIndex(0);
}
void CertificateInfo::updateCertificateInfo(int index)
{
form->certificateInfoView->clear();
- if (index >= 0 && index < chain.size()) {
- const QSslCertificate &cert = chain.at(index);
+ if (index >= 0 && index < certificateChain.size()) {
+ const QSslCertificate &cert = certificateChain.at(index);
QStringList lines;
lines << tr("Organization: %1").arg(cert.subjectInfo(QSslCertificate::Organization).join(QLatin1Char(' ')))
<< tr("Subunit: %1").arg(cert.subjectInfo(QSslCertificate::OrganizationalUnitName).join(QLatin1Char(' ')))
@@ -101,9 +99,7 @@ void CertificateInfo::updateCertificateInfo(int index)
<< tr("Issuer Locality: %1").arg(cert.issuerInfo(QSslCertificate::LocalityName).join(QLatin1Char(' ')))
<< tr("Issuer State/Province: %1").arg(cert.issuerInfo(QSslCertificate::StateOrProvinceName).join(QLatin1Char(' ')))
<< tr("Issuer Common Name: %1").arg(cert.issuerInfo(QSslCertificate::CommonName).join(QLatin1Char(' ')));
- foreach (QString line, lines)
+ for (const auto &line : lines)
form->certificateInfoView->addItem(line);
- } else {
- form->certificateInfoView->clear();
}
}
diff --git a/examples/network/securesocketclient/certificateinfo.h b/examples/network/securesocketclient/certificateinfo.h
index abc56dfbcd..9e079c5603 100644
--- a/examples/network/securesocketclient/certificateinfo.h
+++ b/examples/network/securesocketclient/certificateinfo.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -51,8 +51,9 @@
#ifndef CERTIFICATEINFO_H
#define CERTIFICATEINFO_H
-#include <QtWidgets/QDialog>
-#include <QtNetwork/QSslCertificate>
+#include <QDialog>
+#include <QList>
+#include <QSslCertificate>
QT_BEGIN_NAMESPACE
class Ui_CertificateInfo;
@@ -62,7 +63,7 @@ class CertificateInfo : public QDialog
{
Q_OBJECT
public:
- CertificateInfo(QWidget *parent = 0);
+ explicit CertificateInfo(QWidget *parent = nullptr);
~CertificateInfo();
void setCertificateChain(const QList<QSslCertificate> &chain);
@@ -71,8 +72,8 @@ private slots:
void updateCertificateInfo(int index);
private:
- Ui_CertificateInfo *form;
- QList<QSslCertificate> chain;
+ Ui_CertificateInfo *form = nullptr;
+ QList<QSslCertificate> certificateChain;
};
#endif
diff --git a/examples/network/securesocketclient/certificateinfo.ui b/examples/network/securesocketclient/certificateinfo.ui
index c5238eb3e1..3bea255e9e 100644
--- a/examples/network/securesocketclient/certificateinfo.ui
+++ b/examples/network/securesocketclient/certificateinfo.ui
@@ -42,7 +42,7 @@
<widget class="QListWidget" name="certificateInfoView">
<property name="font">
<font>
- <pointsize>8</pointsize>
+ <pointsize>10</pointsize>
</font>
</property>
<property name="wordWrap">
diff --git a/examples/network/securesocketclient/main.cpp b/examples/network/securesocketclient/main.cpp
index e6dc60736f..e9c413577f 100644
--- a/examples/network/securesocketclient/main.cpp
+++ b/examples/network/securesocketclient/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -50,6 +50,9 @@
#include <QApplication>
#include <QMessageBox>
+#include <QtNetwork>
+
+QT_REQUIRE_CONFIG(ssl);
#include "sslclient.h"
@@ -61,7 +64,7 @@ int main(int argc, char **argv)
if (!QSslSocket::supportsSsl()) {
QMessageBox::information(0, "Secure Socket Client",
- "This system does not support OpenSSL.");
+ "This system does not support SSL/TLS.");
return -1;
}
diff --git a/examples/network/securesocketclient/securesocketclient.pro b/examples/network/securesocketclient/securesocketclient.pro
index f13ed57247..98d2041754 100644
--- a/examples/network/securesocketclient/securesocketclient.pro
+++ b/examples/network/securesocketclient/securesocketclient.pro
@@ -1,3 +1,5 @@
+requires(qtHaveModule(network))
+
HEADERS += certificateinfo.h \
sslclient.h
SOURCES += certificateinfo.cpp \
diff --git a/examples/network/securesocketclient/sslclient.cpp b/examples/network/securesocketclient/sslclient.cpp
index 46d1919fd0..afeec033ff 100644
--- a/examples/network/securesocketclient/sslclient.cpp
+++ b/examples/network/securesocketclient/sslclient.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -50,29 +50,17 @@
#include "certificateinfo.h"
#include "sslclient.h"
+
#include "ui_sslclient.h"
#include "ui_sslerrors.h"
-#include <QtWidgets/QScrollBar>
-#include <QtWidgets/QStyle>
-#include <QtWidgets/QToolButton>
-#include <QtWidgets/QMessageBox>
-#include <QtNetwork/QSslCipher>
+#include <QtCore>
SslClient::SslClient(QWidget *parent)
- : QWidget(parent), socket(0), padLock(0), executingDialog(false)
+ : QWidget(parent)
{
- form = new Ui_Form;
- form->setupUi(this);
- form->hostNameEdit->setSelection(0, form->hostNameEdit->text().size());
- form->sessionOutput->setHtml(tr("&lt;not connected&gt;"));
-
- connect(form->hostNameEdit, SIGNAL(textChanged(QString)),
- this, SLOT(updateEnabledState()));
- connect(form->connectButton, SIGNAL(clicked()),
- this, SLOT(secureConnect()));
- connect(form->sendButton, SIGNAL(clicked()),
- this, SLOT(sendData()));
+ setupUi();
+ setupSecureSocket();
}
SslClient::~SslClient()
@@ -82,17 +70,15 @@ SslClient::~SslClient()
void SslClient::updateEnabledState()
{
- bool unconnected = !socket || socket->state() == QAbstractSocket::UnconnectedState;
-
+ const bool unconnected = socket->state() == QAbstractSocket::UnconnectedState;
form->hostNameEdit->setReadOnly(!unconnected);
form->hostNameEdit->setFocusPolicy(unconnected ? Qt::StrongFocus : Qt::NoFocus);
-
form->hostNameLabel->setEnabled(unconnected);
form->portBox->setEnabled(unconnected);
form->portLabel->setEnabled(unconnected);
form->connectButton->setEnabled(unconnected && !form->hostNameEdit->text().isEmpty());
- bool connected = socket && socket->state() == QAbstractSocket::ConnectedState;
+ const bool connected = socket->state() == QAbstractSocket::ConnectedState;
form->sessionOutput->setEnabled(connected);
form->sessionInput->setEnabled(connected);
form->sessionInputLabel->setEnabled(connected);
@@ -101,20 +87,6 @@ void SslClient::updateEnabledState()
void SslClient::secureConnect()
{
- if (!socket) {
- socket = new QSslSocket(this);
- connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
- this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
- connect(socket, SIGNAL(encrypted()),
- this, SLOT(socketEncrypted()));
- connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
- this, SLOT(socketError(QAbstractSocket::SocketError)));
- connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
- this, SLOT(sslErrors(QList<QSslError>)));
- connect(socket, SIGNAL(readyRead()),
- this, SLOT(socketReadyRead()));
- }
-
socket->connectToHostEncrypted(form->hostNameEdit->text(), form->portBox->value());
updateEnabledState();
}
@@ -125,20 +97,18 @@ void SslClient::socketStateChanged(QAbstractSocket::SocketState state)
return;
updateEnabledState();
+
if (state == QAbstractSocket::UnconnectedState) {
+ form->sessionInput->clear();
form->hostNameEdit->setPalette(QPalette());
form->hostNameEdit->setFocus();
form->cipherLabel->setText(tr("<none>"));
- if (padLock)
- padLock->hide();
+ padLock->hide();
}
}
void SslClient::socketEncrypted()
{
- if (!socket)
- return; // might have disconnected already
-
form->sessionOutput->clear();
form->sessionInput->setFocus();
@@ -146,36 +116,12 @@ void SslClient::socketEncrypted()
palette.setColor(QPalette::Base, QColor(255, 255, 192));
form->hostNameEdit->setPalette(palette);
- QSslCipher ciph = socket->sessionCipher();
- QString cipher = QString("%1, %2 (%3/%4)").arg(ciph.authenticationMethod())
- .arg(ciph.name()).arg(ciph.usedBits()).arg(ciph.supportedBits());;
- form->cipherLabel->setText(cipher);
-
- if (!padLock) {
- padLock = new QToolButton;
- padLock->setIcon(QIcon(":/encrypted.png"));
-#ifndef QT_NO_CURSOR
- padLock->setCursor(Qt::ArrowCursor);
-#endif
- padLock->setToolTip(tr("Display encryption details."));
-
- int extent = form->hostNameEdit->height() - 2;
- padLock->resize(extent, extent);
- padLock->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
-
- QHBoxLayout *layout = new QHBoxLayout(form->hostNameEdit);
- layout->setMargin(form->hostNameEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
- layout->setSpacing(0);
- layout->addStretch();
- layout->addWidget(padLock);
-
- form->hostNameEdit->setLayout(layout);
-
- connect(padLock, SIGNAL(clicked()),
- this, SLOT(displayCertificateInfo()));
- } else {
- padLock->show();
- }
+ const QSslCipher cipher = socket->sessionCipher();
+ const QString cipherInfo = QString("%1, %2 (%3/%4)").arg(cipher.authenticationMethod())
+ .arg(cipher.name()).arg(cipher.usedBits())
+ .arg(cipher.supportedBits());;
+ form->cipherLabel->setText(cipherInfo);
+ padLock->show();
}
void SslClient::socketReadyRead()
@@ -185,7 +131,7 @@ void SslClient::socketReadyRead()
void SslClient::sendData()
{
- QString input = form->sessionInput->text();
+ const QString input = form->sessionInput->text();
appendString(input + '\n');
socket->write(input.toUtf8() + "\r\n");
form->sessionInput->clear();
@@ -193,7 +139,12 @@ void SslClient::sendData()
void SslClient::socketError(QAbstractSocket::SocketError)
{
+ if (handlingSocketError)
+ return;
+
+ handlingSocketError = true;
QMessageBox::critical(this, tr("Connection error"), socket->errorString());
+ handlingSocketError = false;
}
void SslClient::sslErrors(const QList<QSslError> &errors)
@@ -201,10 +152,10 @@ void SslClient::sslErrors(const QList<QSslError> &errors)
QDialog errorDialog(this);
Ui_SslErrors ui;
ui.setupUi(&errorDialog);
- connect(ui.certificateChainButton, SIGNAL(clicked()),
- this, SLOT(displayCertificateInfo()));
+ connect(ui.certificateChainButton, &QPushButton::clicked,
+ this, &SslClient::displayCertificateInfo);
- foreach (const QSslError &error, errors)
+ for (const auto &error : errors)
ui.sslErrorList->addItem(error.errorString());
executingDialog = true;
@@ -219,10 +170,69 @@ void SslClient::sslErrors(const QList<QSslError> &errors)
void SslClient::displayCertificateInfo()
{
- CertificateInfo *info = new CertificateInfo(this);
- info->setCertificateChain(socket->peerCertificateChain());
- info->exec();
- info->deleteLater();
+ CertificateInfo info;
+ info.setCertificateChain(socket->peerCertificateChain());
+ info.exec();
+}
+
+void SslClient::setupUi()
+{
+ if (form)
+ return;
+
+ form = new Ui_Form;
+ form->setupUi(this);
+ form->hostNameEdit->setSelection(0, form->hostNameEdit->text().size());
+ form->sessionOutput->setHtml(tr("&lt;not connected&gt;"));
+
+ connect(form->hostNameEdit, SIGNAL(textChanged(QString)),
+ this, SLOT(updateEnabledState()));
+ connect(form->connectButton, SIGNAL(clicked()),
+ this, SLOT(secureConnect()));
+ connect(form->sendButton, SIGNAL(clicked()),
+ this, SLOT(sendData()));
+
+ padLock = new QToolButton;
+ padLock->setIcon(QIcon(":/encrypted.png"));
+ connect(padLock, SIGNAL(clicked()), this, SLOT(displayCertificateInfo()));
+
+#if QT_CONFIG(cursor)
+ padLock->setCursor(Qt::ArrowCursor);
+#endif
+ padLock->setToolTip(tr("Display encryption details."));
+
+ const int extent = form->hostNameEdit->height() - 2;
+ padLock->resize(extent, extent);
+ padLock->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
+
+ QHBoxLayout *layout = new QHBoxLayout(form->hostNameEdit);
+ layout->setMargin(form->hostNameEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
+ layout->setSpacing(0);
+ layout->addStretch();
+ layout->addWidget(padLock);
+
+ form->hostNameEdit->setLayout(layout);
+ padLock->hide();
+}
+
+void SslClient::setupSecureSocket()
+{
+ if (socket)
+ return;
+
+ socket = new QSslSocket(this);
+
+ connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+ connect(socket, SIGNAL(encrypted()),
+ this, SLOT(socketEncrypted()));
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(socketError(QAbstractSocket::SocketError)));
+ connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
+ this, SLOT(sslErrors(QList<QSslError>)));
+ connect(socket, SIGNAL(readyRead()),
+ this, SLOT(socketReadyRead()));
+
}
void SslClient::appendString(const QString &line)
diff --git a/examples/network/securesocketclient/sslclient.h b/examples/network/securesocketclient/sslclient.h
index d3baefbc56..63fdbef77d 100644
--- a/examples/network/securesocketclient/sslclient.h
+++ b/examples/network/securesocketclient/sslclient.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -51,13 +51,13 @@
#ifndef SSLCLIENT_H
#define SSLCLIENT_H
-#include <QtWidgets/QWidget>
-#include <QtNetwork/QAbstractSocket>
-#include <QtNetwork/QSslSocket>
+#include <QtNetwork>
+
+QT_REQUIRE_CONFIG(ssl);
+
+#include <QtWidgets>
QT_BEGIN_NAMESPACE
-class QSslSocket;
-class QToolButton;
class Ui_Form;
QT_END_NAMESPACE
@@ -65,7 +65,7 @@ class SslClient : public QWidget
{
Q_OBJECT
public:
- SslClient(QWidget *parent = 0);
+ explicit SslClient(QWidget *parent = nullptr);
~SslClient();
private slots:
@@ -80,12 +80,15 @@ private slots:
void displayCertificateInfo();
private:
+ void setupUi();
+ void setupSecureSocket();
void appendString(const QString &line);
- QSslSocket *socket;
- QToolButton *padLock;
- Ui_Form *form;
- bool executingDialog;
+ QSslSocket *socket = nullptr;
+ QToolButton *padLock = nullptr;
+ Ui_Form *form = nullptr;
+ bool handlingSocketError = false;
+ bool executingDialog = false;
};
#endif
diff --git a/examples/network/securesocketclient/sslclient.ui b/examples/network/securesocketclient/sslclient.ui
index 19bae83a09..7821b04e76 100644
--- a/examples/network/securesocketclient/sslclient.ui
+++ b/examples/network/securesocketclient/sslclient.ui
@@ -10,6 +10,12 @@
<height>320</height>
</rect>
</property>
+ <property name="minimumSize">
+ <size>
+ <width>343</width>
+ <height>320</height>
+ </size>
+ </property>
<property name="windowTitle">
<string>Secure Socket Client</string>
</property>
@@ -114,8 +120,8 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.SF NS Text'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
diff --git a/examples/network/threadedfortuneserver/fortuneserver.cpp b/examples/network/threadedfortuneserver/fortuneserver.cpp
index 01b77e2aba..791ffc71f4 100644
--- a/examples/network/threadedfortuneserver/fortuneserver.cpp
+++ b/examples/network/threadedfortuneserver/fortuneserver.cpp
@@ -51,6 +51,8 @@
#include "fortuneserver.h"
#include "fortunethread.h"
+#include <QRandomGenerator>
+
#include <stdlib.h>
//! [0]
@@ -70,7 +72,7 @@ FortuneServer::FortuneServer(QObject *parent)
//! [1]
void FortuneServer::incomingConnection(qintptr socketDescriptor)
{
- QString fortune = fortunes.at(qrand() % fortunes.size());
+ QString fortune = fortunes.at(QRandomGenerator::global()->bounded(fortunes.size()));
FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
diff --git a/examples/network/threadedfortuneserver/main.cpp b/examples/network/threadedfortuneserver/main.cpp
index 3a54585fbc..fdacb28945 100644
--- a/examples/network/threadedfortuneserver/main.cpp
+++ b/examples/network/threadedfortuneserver/main.cpp
@@ -60,6 +60,5 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
Dialog dialog;
dialog.show();
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
return app.exec();
}
diff --git a/examples/network/torrent/main.cpp b/examples/network/torrent/main.cpp
index de7516ed3f..6430d2e5f3 100644
--- a/examples/network/torrent/main.cpp
+++ b/examples/network/torrent/main.cpp
@@ -55,7 +55,6 @@
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
Q_INIT_RESOURCE(icons);
diff --git a/examples/network/torrent/torrentclient.cpp b/examples/network/torrent/torrentclient.cpp
index ba87924ff9..95232646ab 100644
--- a/examples/network/torrent/torrentclient.cpp
+++ b/examples/network/torrent/torrentclient.cpp
@@ -692,7 +692,7 @@ void TorrentClient::connectToPeers()
// Start as many connections as we can
while (!weighedPeers.isEmpty() && ConnectionManager::instance()->canAddConnection()
- && (qrand() % (ConnectionManager::instance()->maxConnections() / 2))) {
+ && (QRandomGenerator::global()->bounded(ConnectionManager::instance()->maxConnections() / 2))) {
PeerWireClient *client = new PeerWireClient(ConnectionManager::instance()->clientId(), this);
RateController::instance()->addSocket(client);
ConnectionManager::instance()->addConnection(client);
@@ -701,7 +701,7 @@ void TorrentClient::connectToPeers()
d->connections << client;
// Pick a random peer from the list of weighed peers.
- TorrentPeer *peer = weighedPeers.takeAt(qrand() % weighedPeers.size());
+ TorrentPeer *peer = weighedPeers.takeAt(QRandomGenerator::global()->bounded(weighedPeers.size()));
weighedPeers.removeAll(peer);
peer->connectStart = QDateTime::currentSecsSinceEpoch();
peer->lastVisited = peer->connectStart;
@@ -1114,7 +1114,7 @@ void TorrentClient::scheduleUploads()
}
if ((client->peerWireState() & PeerWireClient::ChokingPeer) == 0) {
- if ((qrand() % 10) == 0)
+ if ((QRandomGenerator::global()->bounded(10)) == 0)
client->abort();
else
client->chokePeer();
@@ -1128,7 +1128,7 @@ void TorrentClient::scheduleUploads()
// random peer to allow it to compete for a position among the
// downloaders. (This is known as an "optimistic unchoke".)
if (!allClients.isEmpty()) {
- PeerWireClient *client = allClients[qrand() % allClients.size()];
+ PeerWireClient *client = allClients[QRandomGenerator::global()->bounded(allClients.size())];
if (client->peerWireState() & PeerWireClient::ChokingPeer)
client->unchokePeer();
}
@@ -1189,7 +1189,7 @@ void TorrentClient::schedulePieceForClient(PeerWireClient *client)
piece = d->payloads.value(client);
if (!piece) {
QList<TorrentPiece *> values = d->pendingPieces.values();
- piece = values.value(qrand() % values.size());
+ piece = values.value(QRandomGenerator::global()->bounded(values.size()));
piece->inProgress = true;
d->payloads.insert(client, piece);
}
@@ -1246,14 +1246,14 @@ void TorrentClient::schedulePieceForClient(PeerWireClient *client)
++it;
}
if (!partialPieces.isEmpty())
- piece = partialPieces.value(qrand() % partialPieces.size());
+ piece = partialPieces.value(QRandomGenerator::global()->bounded(partialPieces.size()));
if (!piece) {
// Pick a random piece 3 out of 4 times; otherwise, pick either
// one of the most common or the least common pieces available,
// depending on the state we're in.
int pieceIndex = 0;
- if (d->state == WarmingUp || (qrand() & 4) == 0) {
+ if (d->state == WarmingUp || (QRandomGenerator::global()->generate() & 4) == 0) {
int *occurrences = new int[d->pieceCount];
memset(occurrences, 0, d->pieceCount * sizeof(int));
@@ -1293,7 +1293,7 @@ void TorrentClient::schedulePieceForClient(PeerWireClient *client)
}
// Select one piece randomly
- pieceIndex = piecesReadyForDownload.at(qrand() % piecesReadyForDownload.size());
+ pieceIndex = piecesReadyForDownload.at(QRandomGenerator::global()->bounded(piecesReadyForDownload.size()));
delete [] occurrences;
} else {
// Make up a list of available piece indices, and pick
@@ -1304,7 +1304,7 @@ void TorrentClient::schedulePieceForClient(PeerWireClient *client)
if (incompletePiecesAvailableToClient.testBit(i))
values << i;
}
- pieceIndex = values.at(qrand() % values.size());
+ pieceIndex = values.at(QRandomGenerator::global()->bounded(values.size()));
}
// Create a new TorrentPiece and fill in all initial
@@ -1396,8 +1396,8 @@ int TorrentClient::requestBlocks(PeerWireClient *client, TorrentPiece *piece, in
// speedup comes from an increased chance of receiving
// different blocks from the different peers.
for (int i = 0; i < bits.size(); ++i) {
- int a = qrand() % bits.size();
- int b = qrand() % bits.size();
+ int a = QRandomGenerator::global()->bounded(bits.size());
+ int b = QRandomGenerator::global()->bounded(bits.size());
int tmp = bits[a];
bits[a] = bits[b];
bits[b] = tmp;
diff --git a/examples/opengl/hellowindow/hellowindow.cpp b/examples/opengl/hellowindow/hellowindow.cpp
index dc48cc4b76..a978e19b79 100644
--- a/examples/opengl/hellowindow/hellowindow.cpp
+++ b/examples/opengl/hellowindow/hellowindow.cpp
@@ -52,6 +52,7 @@
#include <QOpenGLContext>
#include <QOpenGLFunctions>
+#include <QRandomGenerator>
#include <qmath.h>
Renderer::Renderer(const QSurfaceFormat &format, Renderer *share, QScreen *screen)
@@ -68,9 +69,9 @@ Renderer::Renderer(const QSurfaceFormat &format, Renderer *share, QScreen *scree
m_context->create();
m_backgroundColor = QColor::fromRgbF(0.1f, 0.1f, 0.2f, 1.0f);
- m_backgroundColor.setRed(qrand() % 64);
- m_backgroundColor.setGreen(qrand() % 128);
- m_backgroundColor.setBlue(qrand() % 256);
+ m_backgroundColor.setRed(QRandomGenerator::global()->bounded(64));
+ m_backgroundColor.setGreen(QRandomGenerator::global()->bounded(128));
+ m_backgroundColor.setBlue(QRandomGenerator::global()->bounded(256));
}
HelloWindow::HelloWindow(const QSharedPointer<Renderer> &renderer, QScreen *screen)
@@ -93,6 +94,8 @@ HelloWindow::HelloWindow(const QSharedPointer<Renderer> &renderer, QScreen *scre
void HelloWindow::exposeEvent(QExposeEvent *)
{
m_renderer->setAnimating(this, isExposed());
+ if (isExposed())
+ m_renderer->render();
}
void HelloWindow::mousePressEvent(QMouseEvent *)
@@ -276,21 +279,20 @@ void Renderer::createGeometry()
extrude(x4, y4, y4, x4);
extrude(y4, x4, y3, x3);
- const qreal Pi = 3.14159f;
const int NumSectors = 100;
-
+ const qreal sectorAngle = 2 * qreal(M_PI) / NumSectors;
for (int i = 0; i < NumSectors; ++i) {
- qreal angle1 = (i * 2 * Pi) / NumSectors;
- qreal x5 = 0.30 * qSin(angle1);
- qreal y5 = 0.30 * qCos(angle1);
- qreal x6 = 0.20 * qSin(angle1);
- qreal y6 = 0.20 * qCos(angle1);
-
- qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors;
- qreal x7 = 0.20 * qSin(angle2);
- qreal y7 = 0.20 * qCos(angle2);
- qreal x8 = 0.30 * qSin(angle2);
- qreal y8 = 0.30 * qCos(angle2);
+ qreal angle = i * sectorAngle;
+ qreal x5 = 0.30 * qSin(angle);
+ qreal y5 = 0.30 * qCos(angle);
+ qreal x6 = 0.20 * qSin(angle);
+ qreal y6 = 0.20 * qCos(angle);
+
+ angle += sectorAngle;
+ qreal x7 = 0.20 * qSin(angle);
+ qreal y7 = 0.20 * qCos(angle);
+ qreal x8 = 0.30 * qSin(angle);
+ qreal y8 = 0.30 * qCos(angle);
quad(x5, y5, x6, y6, x7, y7, x8, y8);
diff --git a/examples/opengl/hellowindow/hellowindow.h b/examples/opengl/hellowindow/hellowindow.h
index 1372152e93..e92e45a125 100644
--- a/examples/opengl/hellowindow/hellowindow.h
+++ b/examples/opengl/hellowindow/hellowindow.h
@@ -70,7 +70,7 @@ public:
void setAnimating(HelloWindow *window, bool animating);
-private slots:
+public slots:
void render();
private:
diff --git a/examples/opengl/legacy/framebufferobject2/glwidget.cpp b/examples/opengl/legacy/framebufferobject2/glwidget.cpp
index ac8deddd1f..f14d31aff6 100644
--- a/examples/opengl/legacy/framebufferobject2/glwidget.cpp
+++ b/examples/opengl/legacy/framebufferobject2/glwidget.cpp
@@ -50,8 +50,7 @@
#include "glwidget.h"
#include <QtGui/QImage>
-
-#include <math.h>
+#include <qmath.h>
static GLint cubeArray[][3] = {
{0, 0, 0}, {0, 1, 0}, {1, 1, 0}, {1, 0, 0},
@@ -253,6 +252,6 @@ void GLWidget::drawCube(int i, GLfloat z, GLfloat rotation, GLfloat jmp, GLfloat
xOffs[i] = xOffs[i] > 1.0f ? 1.0f : -1.0f;
}
xOffs[i] += xInc[i];
- yOffs[i] = qAbs(cos((-3.141592f * jmp) * xOffs[i]) * amp) - 1;
+ yOffs[i] = qAbs(cos((-GLfloat(M_PI) * jmp) * xOffs[i]) * amp) - 1;
rot[i] += rotation;
}
diff --git a/examples/opengl/legacy/grabber/glwidget.cpp b/examples/opengl/legacy/grabber/glwidget.cpp
index 958b8055cd..6be4d30597 100644
--- a/examples/opengl/legacy/grabber/glwidget.cpp
+++ b/examples/opengl/legacy/grabber/glwidget.cpp
@@ -52,8 +52,7 @@
#include <QMouseEvent>
#include <QTimer>
-
-#include <math.h>
+#include <qmath.h>
GLWidget::GLWidget(QWidget *parent)
: QGLWidget(parent)
@@ -190,8 +189,6 @@ GLuint GLWidget::makeGear(const GLfloat *reflectance, GLdouble innerRadius,
GLdouble outerRadius, GLdouble thickness,
GLdouble toothSize, GLint toothCount)
{
- const double Pi = 3.14159265358979323846;
-
GLuint list = glGenLists(1);
glNewList(list, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, reflectance);
@@ -199,7 +196,8 @@ GLuint GLWidget::makeGear(const GLfloat *reflectance, GLdouble innerRadius,
GLdouble r0 = innerRadius;
GLdouble r1 = outerRadius - toothSize / 2.0;
GLdouble r2 = outerRadius + toothSize / 2.0;
- GLdouble delta = (2.0 * Pi / toothCount) / 4.0;
+ GLdouble toothAngle = 2 * M_PI / toothCount;
+ GLdouble delta = toothAngle / 4.0;
GLdouble z = thickness / 2.0;
glShadeModel(GL_FLAT);
@@ -211,7 +209,7 @@ GLuint GLWidget::makeGear(const GLfloat *reflectance, GLdouble innerRadius,
glBegin(GL_QUAD_STRIP);
for (int j = 0; j <= toothCount; ++j) {
- GLdouble angle = 2.0 * Pi * j / toothCount;
+ GLdouble angle = j * toothAngle;
glVertex3d(r0 * cos(angle), r0 * sin(angle), sign * z);
glVertex3d(r1 * cos(angle), r1 * sin(angle), sign * z);
glVertex3d(r0 * cos(angle), r0 * sin(angle), sign * z);
@@ -221,7 +219,7 @@ GLuint GLWidget::makeGear(const GLfloat *reflectance, GLdouble innerRadius,
glBegin(GL_QUADS);
for (int j = 0; j < toothCount; ++j) {
- GLdouble angle = 2.0 * Pi * j / toothCount;
+ GLdouble angle = j * toothAngle;
glVertex3d(r1 * cos(angle), r1 * sin(angle), sign * z);
glVertex3d(r2 * cos(angle + delta), r2 * sin(angle + delta), sign * z);
glVertex3d(r2 * cos(angle + 2 * delta), r2 * sin(angle + 2 * delta), sign * z);
@@ -233,7 +231,7 @@ GLuint GLWidget::makeGear(const GLfloat *reflectance, GLdouble innerRadius,
glBegin(GL_QUAD_STRIP);
for (int i = 0; i < toothCount; ++i) {
for (int j = 0; j < 2; ++j) {
- GLdouble angle = 2.0 * Pi * (i + j / 2.0) / toothCount;
+ GLdouble angle = (i + j / 2.0) * toothAngle;
GLdouble s1 = r1;
GLdouble s2 = r2;
if (j == 1)
@@ -257,7 +255,7 @@ GLuint GLWidget::makeGear(const GLfloat *reflectance, GLdouble innerRadius,
glBegin(GL_QUAD_STRIP);
for (int i = 0; i <= toothCount; ++i) {
- GLdouble angle = i * 2.0 * Pi / toothCount;
+ GLdouble angle = i * toothAngle;
glNormal3d(-cos(angle), -sin(angle), 0.0);
glVertex3d(r0 * cos(angle), r0 * sin(angle), +z);
glVertex3d(r0 * cos(angle), r0 * sin(angle), -z);
diff --git a/examples/opengl/legacy/overpainting/bubble.cpp b/examples/opengl/legacy/overpainting/bubble.cpp
index afc50117d0..352e359cf9 100644
--- a/examples/opengl/legacy/overpainting/bubble.cpp
+++ b/examples/opengl/legacy/overpainting/bubble.cpp
@@ -50,6 +50,8 @@
#include "bubble.h"
+#include <QRandomGenerator>
+
Bubble::Bubble(const QPointF &position, qreal radius, const QPointF &velocity)
: position(position), vel(velocity), radius(radius)
{
@@ -80,10 +82,10 @@ void Bubble::drawBubble(QPainter *painter)
QColor Bubble::randomColor()
{
- int red = int(205 + 50.0*qrand()/(RAND_MAX+1.0));
- int green = int(205 + 50.0*qrand()/(RAND_MAX+1.0));
- int blue = int(205 + 50.0*qrand()/(RAND_MAX+1.0));
- int alpha = int(91 + 100.0*qrand()/(RAND_MAX+1.0));
+ int red = int(205 + QRandomGenerator::global()->bounded(50));
+ int green = int(205 + QRandomGenerator::global()->bounded(50));
+ int blue = int(205 + QRandomGenerator::global()->bounded(50));
+ int alpha = int(91 + QRandomGenerator::global()->bounded(100));
return QColor(red, green, blue, alpha);
}
diff --git a/examples/opengl/legacy/overpainting/glwidget.cpp b/examples/opengl/legacy/overpainting/glwidget.cpp
index 7e9f4a5beb..1ec7bd731c 100644
--- a/examples/opengl/legacy/overpainting/glwidget.cpp
+++ b/examples/opengl/legacy/overpainting/glwidget.cpp
@@ -53,6 +53,7 @@
#include "glwidget.h"
#include <QMouseEvent>
+#include <QRandomGenerator>
#include <QTime>
#include <math.h>
@@ -67,7 +68,6 @@ GLWidget::GLWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
QTime midnight(0, 0, 0);
- qsrand(midnight.secsTo(QTime::currentTime()));
logo = 0;
xRot = 0;
@@ -234,11 +234,11 @@ QSize GLWidget::sizeHint() const
void GLWidget::createBubbles(int number)
{
for (int i = 0; i < number; ++i) {
- QPointF position(width()*(0.1 + (0.8*qrand()/(RAND_MAX+1.0))),
- height()*(0.1 + (0.8*qrand()/(RAND_MAX+1.0))));
- qreal radius = qMin(width(), height())*(0.0125 + 0.0875*qrand()/(RAND_MAX+1.0));
- QPointF velocity(width()*0.0125*(-0.5 + qrand()/(RAND_MAX+1.0)),
- height()*0.0125*(-0.5 + qrand()/(RAND_MAX+1.0)));
+ QPointF position(width()*(0.1 + QRandomGenerator::global()->bounded(0.8)),
+ height()*(0.1 + QRandomGenerator::global()->bounded(0.8)));
+ qreal radius = qMin(width(), height())*(0.0125 + QRandomGenerator::global()->bounded(0.0875));
+ QPointF velocity(width()*0.0125*(-0.5 + QRandomGenerator::global()->bounded(1.0)),
+ height()*0.0125*(-0.5 + QRandomGenerator::global()->bounded(1.0)));
bubbles.append(new Bubble(position, radius, velocity));
}
diff --git a/examples/opengl/legacy/pbuffers2/glwidget.cpp b/examples/opengl/legacy/pbuffers2/glwidget.cpp
index c99f9e40fa..c710d03cab 100644
--- a/examples/opengl/legacy/pbuffers2/glwidget.cpp
+++ b/examples/opengl/legacy/pbuffers2/glwidget.cpp
@@ -49,10 +49,9 @@
****************************************************************************/
#include <QtGui/QImage>
+#include <qmath.h>
#include "glwidget.h"
-#include <math.h>
-
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif
@@ -291,8 +290,6 @@ void GLWidget::restoreGLState()
glPopAttrib();
}
-#define PI 3.14159
-
void GLWidget::timerEvent(QTimerEvent *)
{
if (QApplication::mouseButtons() != 0)
@@ -305,31 +302,27 @@ void GLWidget::timerEvent(QTimerEvent *)
else if (!scale_in && scale < .5f)
scale_in = true;
- scale = scale_in ? scale + scale*0.01f : scale-scale*0.01f;
+ scale *= scale_in ? 1.01f : 0.99f;
rot_z += 0.3f;
rot_x += 0.1f;
- int dx, dy; // disturbance point
- float s, v, W, t;
- int i, j;
- static float wt[128][128];
+ static float wt = 0.0;
+ wt += 0.1f;
+
const int width = logo.width();
+ const int dx = width >> 1, dy = dx; // disturbance point
+ const float v = -4; // wave speed
+ const float W = .3f;
const int AMP = 5;
- dx = dy = width >> 1;
-
- W = .3f;
- v = -4; // wave speed
-
- for (i = 0; i < width; ++i) {
- for ( j = 0; j < width; ++j) {
- s = sqrt((double) ((j - dx) * (j - dx) + (i - dy) * (i - dy)));
- wt[i][j] += 0.1f;
- t = s / v;
+ for (int i = 0; i < width; ++i) {
+ for (int j = 0; j < width; ++j) {
+ const float s = hypot(j - dx, i - dy);
+ const double raw = AMP * sin(2 * M_PI * W * (wt + s / v));
if (s != 0)
- wave[i*width + j] = AMP * sin(2 * PI * W * (wt[i][j] + t)) / (0.2*(s + 2));
+ wave[i * width + j] = raw / (0.2 * (s + 2));
else
- wave[i*width + j] = AMP * sin(2 * PI * W * (wt[i][j] + t));
+ wave[i * width + j] = raw;
}
}
}
diff --git a/examples/opengl/legacy/samplebuffers/glwidget.cpp b/examples/opengl/legacy/samplebuffers/glwidget.cpp
index 14c59c9143..da30de4d55 100644
--- a/examples/opengl/legacy/samplebuffers/glwidget.cpp
+++ b/examples/opengl/legacy/samplebuffers/glwidget.cpp
@@ -49,7 +49,7 @@
****************************************************************************/
#include "glwidget.h"
-#include <math.h>
+#include <qmath.h>
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
@@ -116,7 +116,6 @@ void GLWidget::timerEvent(QTimerEvent *)
void GLWidget::makeObject()
{
QColor qtGreen(QColor::fromCmykF(0.40, 0.0, 1.0, 0.0));
- const double Pi = 3.14159265358979323846;
const int NumSectors = 15;
GLdouble x1 = +0.06;
GLdouble y1 = -0.14;
@@ -130,18 +129,19 @@ void GLWidget::makeObject()
list = glGenLists(1);
glNewList(list, GL_COMPILE);
{
+ const double sectorAngle = 2 * M_PI / NumSectors;
for (int i = 0; i < NumSectors; ++i) {
- double angle1 = (i * 2 * Pi) / NumSectors;
- GLdouble x5 = 0.30 * sin(angle1);
- GLdouble y5 = 0.30 * cos(angle1);
- GLdouble x6 = 0.20 * sin(angle1);
- GLdouble y6 = 0.20 * cos(angle1);
-
- double angle2 = ((i + 1) * 2 * Pi) / NumSectors;
- GLdouble x7 = 0.20 * sin(angle2);
- GLdouble y7 = 0.20 * cos(angle2);
- GLdouble x8 = 0.30 * sin(angle2);
- GLdouble y8 = 0.30 * cos(angle2);
+ double angle = i * sectorAngle;
+ GLdouble x5 = 0.30 * sin(angle);
+ GLdouble y5 = 0.30 * cos(angle);
+ GLdouble x6 = 0.20 * sin(angle);
+ GLdouble y6 = 0.20 * cos(angle);
+
+ angle += sectorAngle;
+ GLdouble x7 = 0.20 * sin(angle);
+ GLdouble y7 = 0.20 * cos(angle);
+ GLdouble x8 = 0.30 * sin(angle);
+ GLdouble y8 = 0.30 * cos(angle);
qglColor(qtGreen);
quad(GL_QUADS, x5, y5, x6, y6, x7, y7, x8, y8);
diff --git a/examples/opengl/qopenglwidget/bubble.cpp b/examples/opengl/qopenglwidget/bubble.cpp
index adf5742f6a..dbaf460f6f 100644
--- a/examples/opengl/qopenglwidget/bubble.cpp
+++ b/examples/opengl/qopenglwidget/bubble.cpp
@@ -109,10 +109,10 @@ void Bubble::drawBubble(QPainter *painter)
QColor Bubble::randomColor()
{
- int red = int(185 + 70.0*qrand()/(RAND_MAX+1.0));
- int green = int(185 + 70.0*qrand()/(RAND_MAX+1.0));
- int blue = int(205 + 50.0*qrand()/(RAND_MAX+1.0));
- int alpha = int(91 + 100.0*qrand()/(RAND_MAX+1.0));
+ int red = int(185 + QRandomGenerator::global()->bounded(70));
+ int green = int(185 + QRandomGenerator::global()->bounded(70));
+ int blue = int(205 + QRandomGenerator::global()->bounded(50));
+ int alpha = int(91 + QRandomGenerator::global()->bounded(100));
return QColor(red, green, blue, alpha);
}
diff --git a/examples/opengl/qopenglwidget/glwidget.cpp b/examples/opengl/qopenglwidget/glwidget.cpp
index 21d922d713..3fe919f94b 100644
--- a/examples/opengl/qopenglwidget/glwidget.cpp
+++ b/examples/opengl/qopenglwidget/glwidget.cpp
@@ -53,14 +53,19 @@
#include <QPaintEngine>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
+#include <QRandomGenerator>
#include <QCoreApplication>
-#include <math.h>
+#include <qmath.h>
#include "mainwindow.h"
#include "bubble.h"
const int bubbleNum = 8;
+#ifndef GL_SRGB8_ALPHA8
+#define GL_SRGB8_ALPHA8 0x8C43
+#endif
+
GLWidget::GLWidget(MainWindow *mw, bool button, const QColor &background)
: m_mainWindow(mw),
m_showBubbles(true),
@@ -75,6 +80,8 @@ GLWidget::GLWidget(MainWindow *mw, bool button, const QColor &background)
m_background(background)
{
setMinimumSize(300, 250);
+ if (QCoreApplication::arguments().contains(QStringLiteral("--srgb")))
+ setTextureFormat(GL_SRGB8_ALPHA8);
}
GLWidget::~GLWidget()
@@ -414,11 +421,11 @@ void GLWidget::paintGL()
void GLWidget::createBubbles(int number)
{
for (int i = 0; i < number; ++i) {
- QPointF position(width()*(0.1 + (0.8*qrand()/(RAND_MAX+1.0))),
- height()*(0.1 + (0.8*qrand()/(RAND_MAX+1.0))));
- qreal radius = qMin(width(), height())*(0.0175 + 0.0875*qrand()/(RAND_MAX+1.0));
- QPointF velocity(width()*0.0175*(-0.5 + qrand()/(RAND_MAX+1.0)),
- height()*0.0175*(-0.5 + qrand()/(RAND_MAX+1.0)));
+ QPointF position(width()*(0.1 + QRandomGenerator::global()->bounded(0.8)),
+ height()*(0.1 + QRandomGenerator::global()->bounded(0.8)));
+ qreal radius = qMin(width(), height())*(0.0175 + QRandomGenerator::global()->bounded(0.0875));
+ QPointF velocity(width()*0.0175*(-0.5 + QRandomGenerator::global()->bounded(1.0)),
+ height()*0.0175*(-0.5 + QRandomGenerator::global()->bounded(1.0)));
m_bubbles.append(new Bubble(position, radius, velocity));
}
@@ -449,21 +456,21 @@ void GLWidget::createGeometry()
extrude(x4, y4, y4, x4);
extrude(y4, x4, y3, x3);
- const qreal Pi = 3.14159f;
const int NumSectors = 100;
+ const qreal sectorAngle = 2 * qreal(M_PI) / NumSectors;
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);
+ qreal angle = i * sectorAngle;
+ qreal x5 = 0.30 * sin(angle);
+ qreal y5 = 0.30 * cos(angle);
+ qreal x6 = 0.20 * sin(angle);
+ qreal y6 = 0.20 * cos(angle);
+
+ angle += sectorAngle;
+ qreal x7 = 0.20 * sin(angle);
+ qreal y7 = 0.20 * cos(angle);
+ qreal x8 = 0.30 * sin(angle);
+ qreal y8 = 0.30 * cos(angle);
quad(x5, y5, x6, y6, x7, y7, x8, y8);
diff --git a/examples/opengl/qopenglwidget/main.cpp b/examples/opengl/qopenglwidget/main.cpp
index ea90dca62f..42fc772445 100644
--- a/examples/opengl/qopenglwidget/main.cpp
+++ b/examples/opengl/qopenglwidget/main.cpp
@@ -69,11 +69,15 @@ int main( int argc, char ** argv )
parser.addVersionOption();
QCommandLineOption multipleSampleOption("multisample", "Multisampling");
parser.addOption(multipleSampleOption);
+ QCommandLineOption srgbOption("srgb", "Use sRGB Color Space");
+ parser.addOption(srgbOption);
parser.process(a);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
+ if (parser.isSet(srgbOption))
+ format.setColorSpace(QSurfaceFormat::sRGBColorSpace);
if (parser.isSet(multipleSampleOption))
format.setSamples(4);
QSurfaceFormat::setDefaultFormat(format);
diff --git a/examples/opengl/qopenglwidget/mainwindow.cpp b/examples/opengl/qopenglwidget/mainwindow.cpp
index 1bb2aa2bf0..4bd123628f 100644
--- a/examples/opengl/qopenglwidget/mainwindow.cpp
+++ b/examples/opengl/qopenglwidget/mainwindow.cpp
@@ -56,6 +56,7 @@
#include <QSlider>
#include <QLabel>
#include <QCheckBox>
+#include <QRandomGenerator>
#include <QSpinBox>
#include <QScrollArea>
@@ -155,7 +156,9 @@ void MainWindow::addNew()
{
if (m_nextY == 4)
return;
- GLWidget *w = new GLWidget(this, false, qRgb(qrand() % 256, qrand() % 256, qrand() % 256));
+ GLWidget *w = new GLWidget(this, false, qRgb(QRandomGenerator::global()->bounded(256),
+ QRandomGenerator::global()->bounded(256),
+ QRandomGenerator::global()->bounded(256)));
m_glWidgets << w;
connect(m_timer, &QTimer::timeout, w, QOverload<>::of(&QWidget::update));
m_layout->addWidget(w, m_nextY, m_nextX, 1, 1);
diff --git a/examples/opengl/qopenglwindow/background.frag b/examples/opengl/qopenglwindow/background.frag
index eecb6d3120..4af85aae8e 100644
--- a/examples/opengl/qopenglwindow/background.frag
+++ b/examples/opengl/qopenglwindow/background.frag
@@ -1,4 +1,4 @@
-#define M_PI 3.1415926535897932384626433832795
+#define M_PI 3.14159265358979323846
#define SPEED 10000.0
uniform int currentTime;
diff --git a/examples/opengl/threadedqopenglwidget/glwidget.cpp b/examples/opengl/threadedqopenglwidget/glwidget.cpp
index f9738db2e5..cc528a734a 100644
--- a/examples/opengl/threadedqopenglwidget/glwidget.cpp
+++ b/examples/opengl/threadedqopenglwidget/glwidget.cpp
@@ -49,7 +49,7 @@
****************************************************************************/
#include "glwidget.h"
-#include <math.h>
+#include <qmath.h>
#include <QGuiApplication>
GLWidget::GLWidget(QWidget *parent)
@@ -282,21 +282,21 @@ void Renderer::createGeometry()
extrude(x4, y4, y4, x4);
extrude(y4, x4, y3, x3);
- const qreal Pi = 3.14159f;
const int NumSectors = 100;
+ const qreal sectorAngle = 2 * qreal(M_PI) / NumSectors;
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);
+ qreal angle = i * sectorAngle;
+ qreal x5 = 0.30 * sin(angle);
+ qreal y5 = 0.30 * cos(angle);
+ qreal x6 = 0.20 * sin(angle);
+ qreal y6 = 0.20 * cos(angle);
+
+ angle += sectorAngle;
+ qreal x7 = 0.20 * sin(angle);
+ qreal y7 = 0.20 * cos(angle);
+ qreal x8 = 0.30 * sin(angle);
+ qreal y8 = 0.30 * cos(angle);
quad(x5, y5, x6, y6, x7, y7, x8, y8);
diff --git a/examples/sql/doc/src/drilldown.qdoc b/examples/sql/doc/src/drilldown.qdoc
index e8841d2013..7a8aa2037a 100644
--- a/examples/sql/doc/src/drilldown.qdoc
+++ b/examples/sql/doc/src/drilldown.qdoc
@@ -163,7 +163,7 @@
submitted to the database until the user expliclity requests a
submit (the alternative is QDataWidgetMapper::AutoSubmit,
automatically submitting changes when the corresponding widget
- looses focus). Finally, we specify the item delegate the mapper
+ loses focus). Finally, we specify the item delegate the mapper
view should use for its items. The QSqlRelationalDelegate class
represents a delegate that unlike the default delegate, enables
combobox functionality for fields that are foreign keys into other
diff --git a/examples/touch/pinchzoom/main.cpp b/examples/touch/pinchzoom/main.cpp
index 67099618c7..938432600f 100644
--- a/examples/touch/pinchzoom/main.cpp
+++ b/examples/touch/pinchzoom/main.cpp
@@ -61,7 +61,6 @@ static const int MouseCount = 7;
int main(int argc, char **argv)
{
QApplication app(argc, argv);
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
//! [0]
//! [1]
diff --git a/examples/touch/pinchzoom/mouse.cpp b/examples/touch/pinchzoom/mouse.cpp
index f063e96654..1e6814be13 100644
--- a/examples/touch/pinchzoom/mouse.cpp
+++ b/examples/touch/pinchzoom/mouse.cpp
@@ -52,12 +52,12 @@
#include <QGraphicsScene>
#include <QPainter>
+#include <QRandomGenerator>
#include <QStyleOption>
+#include <qmath.h>
-#include <math.h>
-
-static const double Pi = 3.14159265358979323846264338327950288419717;
-static double TwoPi = 2.0 * Pi;
+const qreal Pi = M_PI;
+const qreal TwoPi = 2 * M_PI;
static qreal normalizeAngle(qreal angle)
{
@@ -71,9 +71,9 @@ static qreal normalizeAngle(qreal angle)
//! [0]
Mouse::Mouse()
: angle(0), speed(0), mouseEyeDirection(0),
- color(qrand() % 256, qrand() % 256, qrand() % 256)
+ color(QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256))
{
- setTransform(QTransform().rotate(qrand() % (360 * 16)), true);
+ setTransform(QTransform().rotate(QRandomGenerator::global()->bounded(360 * 16)), true);
startTimer(1000 / 33);
}
//! [0]
@@ -139,9 +139,7 @@ void Mouse::timerEvent(QTimerEvent *)
//! [5]
QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0));
if (lineToCenter.length() > 150) {
- qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length());
- if (lineToCenter.dy() < 0)
- angleToCenter = TwoPi - angleToCenter;
+ qreal angleToCenter = std::atan2(lineToCenter.dy(), lineToCenter.dx());
angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2);
if (angleToCenter < Pi && angleToCenter > Pi / 4) {
@@ -170,9 +168,7 @@ void Mouse::timerEvent(QTimerEvent *)
continue;
QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0));
- qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length());
- if (lineToMouse.dy() < 0)
- angleToMouse = TwoPi - angleToMouse;
+ qreal angleToMouse = std::atan2(lineToMouse.dy(), lineToMouse.dx());
angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2);
if (angleToMouse >= 0 && angleToMouse < Pi / 2) {
@@ -189,16 +185,16 @@ void Mouse::timerEvent(QTimerEvent *)
// Add some random movement
//! [10]
- if (dangerMice.size() > 1 && (qrand() % 10) == 0) {
- if (qrand() % 1)
- angle += (qrand() % 100) / 500.0;
+ if (dangerMice.size() > 1 && QRandomGenerator::global()->bounded(10) == 0) {
+ if (QRandomGenerator::global()->bounded(1))
+ angle += QRandomGenerator::global()->bounded(1 / 500.0);
else
- angle -= (qrand() % 100) / 500.0;
+ angle -= QRandomGenerator::global()->bounded(1 / 500.0);
}
//! [10]
//! [11]
- speed += (-50 + qrand() % 100) / 100.0;
+ speed += (-50 + QRandomGenerator::global()->bounded(100)) / 100.0;
qreal dx = ::sin(angle) * 10;
mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5;
diff --git a/examples/vulkan/doc/images/hellovulkancubes.png b/examples/vulkan/doc/images/hellovulkancubes.png
new file mode 100644
index 0000000000..c3d819c047
--- /dev/null
+++ b/examples/vulkan/doc/images/hellovulkancubes.png
Binary files differ
diff --git a/examples/vulkan/doc/images/hellovulkantexture.png b/examples/vulkan/doc/images/hellovulkantexture.png
new file mode 100644
index 0000000000..0cb47a70be
--- /dev/null
+++ b/examples/vulkan/doc/images/hellovulkantexture.png
Binary files differ
diff --git a/examples/vulkan/doc/images/hellovulkantriangle.png b/examples/vulkan/doc/images/hellovulkantriangle.png
new file mode 100644
index 0000000000..f88b27a873
--- /dev/null
+++ b/examples/vulkan/doc/images/hellovulkantriangle.png
Binary files differ
diff --git a/examples/vulkan/doc/images/hellovulkanwidget.png b/examples/vulkan/doc/images/hellovulkanwidget.png
new file mode 100644
index 0000000000..b85d4dc596
--- /dev/null
+++ b/examples/vulkan/doc/images/hellovulkanwidget.png
Binary files differ
diff --git a/examples/vulkan/doc/images/hellovulkanwindow.png b/examples/vulkan/doc/images/hellovulkanwindow.png
new file mode 100644
index 0000000000..c55029312c
--- /dev/null
+++ b/examples/vulkan/doc/images/hellovulkanwindow.png
Binary files differ
diff --git a/examples/vulkan/doc/src/hellovulkancubes.qdoc b/examples/vulkan/doc/src/hellovulkancubes.qdoc
new file mode 100644
index 0000000000..934d2015a1
--- /dev/null
+++ b/examples/vulkan/doc/src/hellovulkancubes.qdoc
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example hellovulkancubes
+ \title Hello Vulkan Cubes Example
+ \ingroup examples-vulkan
+ \brief Shows the basics of using QVulkanWindow
+
+ The \e{Hello Vulkan Cubes Example} shows more advanced usage of QVulkanWindow.
+
+ \image hellovulkancubes.png
+
+ In this example there is a mesh loaded from a file and two different
+ materials and corresponding graphics pipelines. The rounded cubes are drawn
+ using instancing and feature a Phong lighting model with a single
+ directional light.
+
+ Unlike hellovulkantexture and hellovulkantriangle, the uniform buffer
+ handling takes an alternative approach here: dynamic uniform buffers are
+ used instead of multiple descriptor sets.
+
+ The example requires QtConcurrent since it demonstrates simple usage of
+ QtConcurrent::run(), QFuture, and QFutureWatcher in combination of
+ QVulkanWindow. Mesh and shader data loading, the potentially expensive
+ graphics pipeline construction, and the building of the frame command buffer
+ are all done in separate worker threads.
+
+ The scene is embedded into a widget-based user interface. The QVulkanWindow
+ subclass handles mouse and keyboard input as well since it provides a
+ first-person style camera in order to allow moving around in the scene.
+
+ \include examples-run.qdocinc
+*/
diff --git a/examples/widgets/doc/src/appchooser.qdoc b/examples/vulkan/doc/src/hellovulkantexture.qdoc
index e74860214a..d0e0ca90a8 100644
--- a/examples/widgets/doc/src/appchooser.qdoc
+++ b/examples/vulkan/doc/src/hellovulkantexture.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -26,13 +26,16 @@
****************************************************************************/
/*!
- \example animation/appchooser
- \title Application Chooser Example
+ \example hellovulkantexture
+ \ingroup examples-vulkan
+ \title Hello Vulkan Texture Vulkan Example
+ \brief Shows the basics of rendering with textures in a QVulkanWindow
- \brief The Application Chooser example shows how to use the Qt state
- machine and the animation framework to select between
- applications.
-
- \image appchooser-example.png
+ The \e{Hello Vulkan Texture Example} builds on \l hellovulkantriangle. Here
+ instead of drawing a single triangle, a triangle strip is drawn in order to
+ get a quad on the screen. This is then textured using a QImage loaded from
+ a .png image file.
+ \image hellovulkantexture.png
+ \include examples-run.qdocinc
*/
diff --git a/examples/vulkan/doc/src/hellovulkantriangle.qdoc b/examples/vulkan/doc/src/hellovulkantriangle.qdoc
new file mode 100644
index 0000000000..81af776ea1
--- /dev/null
+++ b/examples/vulkan/doc/src/hellovulkantriangle.qdoc
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example hellovulkantriangle
+ \ingroup examples-vulkan
+ \title Hello Vulkan Triangle Example
+ \brief Shows the basics of rendering with QVulkanWindow and the Vulkan API
+
+ The \e{Hello Vulkan Triangle Example} builds on \l hellovulkanwindow. This
+ time a full graphics pipeline is created, including a vertex and fragment
+ shader. This pipeline is then used to render a triangle.
+
+ \image hellovulkantriangle.png
+
+ The example also demonstrates multisample antialiasing. Based on the
+ supported sample counts reported by QVulkanWindow::supportedSampleCounts()
+ the example chooses between 8x, 4x, or no multisampling. Once configured
+ via QVulkanWindow::setSamples(), QVulkanWindow takes care of the rest: the
+ additional multisample color buffers are created automatically, and
+ resolving into the swapchain buffers is performed at the end of the default
+ render pass for each frame.
+
+ \include examples-run.qdocinc
+*/
diff --git a/examples/widgets/doc/src/lighting.qdoc b/examples/vulkan/doc/src/hellovulkanwidget.qdoc
index 994172cf5d..7987bdeff9 100644
--- a/examples/widgets/doc/src/lighting.qdoc
+++ b/examples/vulkan/doc/src/hellovulkanwidget.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -26,10 +26,24 @@
****************************************************************************/
/*!
- \example effects/lighting
- \title Lighting Effect Example
- \ingroup examples-graphicsview-graphicseffects
- \brief Demonstrates how to apply effects on items in the view
+ \example hellovulkanwidget
+ \ingroup examples-vulkan
+ \title Hello Vulkan Widget Example
+ \brief Shows the usage of QVulkanWindow in QWidget applications
- \image lightingeffect-example.png
+ The \e{Hello Vulkan Widget Example} is a variant of \l hellovulkantriangle
+ that embeds the QVulkanWindow into a QWidget-based user interface using
+ QWidget::createWindowContainer().
+
+ \image hellovulkanwidget.png
+
+ The code to set up the Vulkan pipeline and render the triangle is the same
+ as in \l hellovulkantriangle. In addition, this example demonstrates
+ another feature of QVulkanWindow: reading the image content back from the
+ color buffer into a QImage. By clicking the Grab button, the example
+ renders the next frame and follows it up with a transfer operation in order
+ to get the swapchain color buffer content copied into host accessible
+ memory. The image is then saved to disk via QImage::save().
+
+ \include examples-run.qdocinc
*/
diff --git a/examples/vulkan/doc/src/hellovulkanwindow.qdoc b/examples/vulkan/doc/src/hellovulkanwindow.qdoc
new file mode 100644
index 0000000000..06cc9c1c28
--- /dev/null
+++ b/examples/vulkan/doc/src/hellovulkanwindow.qdoc
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example hellovulkanwindow
+ \title Hello Vulkan Window Example
+ \ingroup examples-vulkan
+ \brief Shows the basics of using QVulkanWindow
+
+ The \e{Hello Vulkan Window Example} shows the basics of using QVulkanWindow
+ in order to display rendering with the Vulkan graphics API on systems that
+ support this.
+
+ \image hellovulkanwindow.png
+
+ In this example there will be no actual rendering: it simply begins and
+ ends a render pass, which results in clearing the buffers to a fixed value.
+ The color buffer clear value changes on every frame.
+
+ \section1 Startup
+
+ Each Qt application using Vulkan will have to have a \c{Vulkan instance}
+ which encapsulates application-level state and initializes a Vulkan library.
+
+ A QVulkanWindow must always be associated with a QVulkanInstance and hence
+ the example performs instance creation before the window. The
+ QVulkanInstance object must also outlive the window.
+
+ \snippet hellovulkanwindow/main.cpp 0
+
+ The example enables validation layers, when supported. When the requested
+ layers are not present, the request will be ignored. Additional layers and
+ extensions can be enabled in a similar manner.
+
+ \snippet hellovulkanwindow/main.cpp 1
+
+ Once the instance is ready, it is time to create a window. Note that \c w
+ lives on the stack and is declared after \c inst.
+
+ \section1 The QVulkanWindow Subclass
+
+ To add custom functionality to a QVulkanWindow, subclassing is used. This
+ follows the existing patterns from QOpenGLWindow and QOpenGLWidget.
+ However, QVulkanWindow utilizes a separate QVulkanWindowRenderer object.
+ This resembles QQuickFramebufferObject, and allows better separation of the
+ functions that are supposed to be reimplemented.
+
+ \snippet hellovulkanwindow/hellovulkanwindow.h 0
+
+ The QVulkanWindow subclass reimplements the factory function
+ QVulkanWindow::createRenderer(). This simply returns a new instance of the
+ QVulkanWindowRenderer subclass. In order to be able to access various
+ Vulkan resources via the window object, a pointer to the window is passed
+ and stored via the constructor.
+
+ \snippet hellovulkanwindow/hellovulkanwindow.cpp 0
+
+ Graphics resource creation and destruction is typically done in one of the
+ init - resource functions.
+
+ \snippet hellovulkanwindow/hellovulkanwindow.cpp 1
+
+ \section1 The Actual Rendering
+
+ QVulkanWindow subclasses queue their draw calls in their reimplementation
+ of QVulkanWindowRenderer::startNextFrame(). Once done, they are required to
+ call back QVulkanWindow::frameReady(). The example has no asynchronous
+ command generation, so the frameReady() call is made directly from
+ startNextFrame().
+
+ \snippet hellovulkanwindow/hellovulkanwindow.cpp 2
+
+ To get continuous updates, the example simply invokes
+ QWindow::requestUpdate() in order to schedule a repaint.
+
+ \include examples-run.qdocinc
+*/
diff --git a/examples/vulkan/hellovulkancubes/camera.cpp b/examples/vulkan/hellovulkancubes/camera.cpp
new file mode 100644
index 0000000000..64dee03154
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/camera.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "camera.h"
+
+Camera::Camera(const QVector3D &pos)
+ : m_forward(0.0f, 0.0f, -1.0f),
+ m_right(1.0f, 0.0f, 0.0f),
+ m_up(0.0f, 1.0f, 0.0f),
+ m_pos(pos),
+ m_yaw(0.0f),
+ m_pitch(0.0f)
+{
+}
+
+static inline void clamp360(float *v)
+{
+ if (*v > 360.0f)
+ *v -= 360.0f;
+ if (*v < -360.0f)
+ *v += 360.0f;
+}
+
+void Camera::yaw(float degrees)
+{
+ m_yaw += degrees;
+ clamp360(&m_yaw);
+ m_yawMatrix.setToIdentity();
+ m_yawMatrix.rotate(m_yaw, 0, 1, 0);
+
+ QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix;
+ m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D();
+ m_right = (QVector4D(1.0f, 0.0f, 0.0f, 0.0f) * rotMat).toVector3D();
+}
+
+void Camera::pitch(float degrees)
+{
+ m_pitch += degrees;
+ clamp360(&m_pitch);
+ m_pitchMatrix.setToIdentity();
+ m_pitchMatrix.rotate(m_pitch, 1, 0, 0);
+
+ QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix;
+ m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D();
+ m_up = (QVector4D(0.0f, 1.0f, 0.0f, 0.0f) * rotMat).toVector3D();
+}
+
+void Camera::walk(float amount)
+{
+ m_pos[0] += amount * m_forward.x();
+ m_pos[2] += amount * m_forward.z();
+}
+
+void Camera::strafe(float amount)
+{
+ m_pos[0] += amount * m_right.x();
+ m_pos[2] += amount * m_right.z();
+}
+
+QMatrix4x4 Camera::viewMatrix() const
+{
+ QMatrix4x4 m = m_pitchMatrix * m_yawMatrix;
+ m.translate(-m_pos);
+ return m;
+}
diff --git a/examples/widgets/effects/lighting/main.cpp b/examples/vulkan/hellovulkancubes/camera.h
index 22e55c0985..c5c579f066 100644
--- a/examples/widgets/effects/lighting/main.cpp
+++ b/examples/vulkan/hellovulkancubes/camera.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -48,18 +48,33 @@
**
****************************************************************************/
-#include "lighting.h"
-#include <QApplication>
+#ifndef CAMERA_H
+#define CAMERA_H
-int main(int argc, char **argv)
+#include <QVector3D>
+#include <QMatrix4x4>
+
+class Camera
{
- QApplication app(argc, argv);
+public:
+ Camera(const QVector3D &pos);
+
+ void yaw(float degrees);
+ void pitch(float degrees);
+ void walk(float amount);
+ void strafe(float amount);
- Lighting lighting;
- lighting.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Lighting and Shadows"));
+ QMatrix4x4 viewMatrix() const;
- lighting.resize(640, 480);
- lighting.show();
+private:
+ QVector3D m_forward;
+ QVector3D m_right;
+ QVector3D m_up;
+ QVector3D m_pos;
+ float m_yaw;
+ float m_pitch;
+ QMatrix4x4 m_yawMatrix;
+ QMatrix4x4 m_pitchMatrix;
+};
- return app.exec();
-}
+#endif
diff --git a/examples/vulkan/hellovulkancubes/color.frag b/examples/vulkan/hellovulkancubes/color.frag
new file mode 100644
index 0000000000..3b04955963
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color.frag
@@ -0,0 +1,12 @@
+#version 440
+
+layout(push_constant) uniform PC {
+ layout(offset = 64) vec3 color;
+} pc;
+
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(pc.color, 1.0);
+}
diff --git a/examples/vulkan/hellovulkancubes/color.vert b/examples/vulkan/hellovulkancubes/color.vert
new file mode 100644
index 0000000000..19bf815819
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color.vert
@@ -0,0 +1,14 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+layout(push_constant) uniform PC {
+ mat4 mvp;
+} pc;
+
+void main()
+{
+ gl_Position = pc.mvp * position;
+}
diff --git a/examples/vulkan/hellovulkancubes/color_frag.spv b/examples/vulkan/hellovulkancubes/color_frag.spv
new file mode 100644
index 0000000000..bd72984ffe
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color_frag.spv
Binary files differ
diff --git a/examples/vulkan/hellovulkancubes/color_phong.frag b/examples/vulkan/hellovulkancubes/color_phong.frag
new file mode 100644
index 0000000000..8b0c715f3b
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color_phong.frag
@@ -0,0 +1,39 @@
+#version 440
+
+layout(location = 0) in vec3 vECVertNormal;
+layout(location = 1) in vec3 vECVertPos;
+layout(location = 2) flat in vec3 vDiffuseAdjust;
+
+layout(std140, binding = 1) uniform buf {
+ vec3 ECCameraPosition;
+ vec3 ka;
+ vec3 kd;
+ vec3 ks;
+ // Have one light only for now.
+ vec3 ECLightPosition;
+ vec3 attenuation;
+ vec3 color;
+ float intensity;
+ float specularExp;
+} ubuf;
+
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ vec3 unnormL = ubuf.ECLightPosition - vECVertPos;
+ float dist = length(unnormL);
+ float att = 1.0 / (ubuf.attenuation.x + ubuf.attenuation.y * dist + ubuf.attenuation.z * dist * dist);
+
+ vec3 N = normalize(vECVertNormal);
+ vec3 L = normalize(unnormL);
+ float NL = max(0.0, dot(N, L));
+ vec3 dColor = att * ubuf.intensity * ubuf.color * NL;
+
+ vec3 R = reflect(-L, N);
+ vec3 V = normalize(ubuf.ECCameraPosition - vECVertPos);
+ float RV = max(0.0, dot(R, V));
+ vec3 sColor = att * ubuf.intensity * ubuf.color * pow(RV, ubuf.specularExp);
+
+ fragColor = vec4(ubuf.ka + (ubuf.kd + vDiffuseAdjust) * dColor + ubuf.ks * sColor, 1.0);
+}
diff --git a/examples/vulkan/hellovulkancubes/color_phong.vert b/examples/vulkan/hellovulkancubes/color_phong.vert
new file mode 100644
index 0000000000..a1d1552685
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color_phong.vert
@@ -0,0 +1,32 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 normal;
+
+// Instanced attributes to variate the translation of the model and the diffuse
+// color of the material.
+layout(location = 2) in vec3 instTranslate;
+layout(location = 3) in vec3 instDiffuseAdjust;
+
+out gl_PerVertex { vec4 gl_Position; };
+layout(location = 0) out vec3 vECVertNormal;
+layout(location = 1) out vec3 vECVertPos;
+layout(location = 2) flat out vec3 vDiffuseAdjust;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 vp;
+ mat4 model;
+ mat3 modelNormal;
+} ubuf;
+
+void main()
+{
+ vECVertNormal = normalize(ubuf.modelNormal * normal);
+ mat4 t = mat4(1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ instTranslate.x, instTranslate.y, instTranslate.z, 1);
+ vECVertPos = vec3(t * ubuf.model * position);
+ vDiffuseAdjust = instDiffuseAdjust;
+ gl_Position = ubuf.vp * t * ubuf.model * position;
+}
diff --git a/examples/vulkan/hellovulkancubes/color_phong_frag.spv b/examples/vulkan/hellovulkancubes/color_phong_frag.spv
new file mode 100644
index 0000000000..a1a413533b
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color_phong_frag.spv
Binary files differ
diff --git a/examples/vulkan/hellovulkancubes/color_phong_vert.spv b/examples/vulkan/hellovulkancubes/color_phong_vert.spv
new file mode 100644
index 0000000000..3ede21e007
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color_phong_vert.spv
Binary files differ
diff --git a/examples/vulkan/hellovulkancubes/color_vert.spv b/examples/vulkan/hellovulkancubes/color_vert.spv
new file mode 100644
index 0000000000..3f708b7d07
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/color_vert.spv
Binary files differ
diff --git a/examples/vulkan/hellovulkancubes/hellovulkancubes.pro b/examples/vulkan/hellovulkancubes/hellovulkancubes.pro
new file mode 100644
index 0000000000..f9a9c3cff1
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/hellovulkancubes.pro
@@ -0,0 +1,24 @@
+QT += widgets concurrent
+
+HEADERS += \
+ mainwindow.h \
+ vulkanwindow.h \
+ renderer.h \
+ mesh.h \
+ shader.h \
+ camera.h
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ vulkanwindow.cpp \
+ renderer.cpp \
+ mesh.cpp \
+ shader.cpp \
+ camera.cpp
+
+RESOURCES += hellovulkancubes.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkancubes
+INSTALLS += target
diff --git a/examples/vulkan/hellovulkancubes/hellovulkancubes.qrc b/examples/vulkan/hellovulkancubes/hellovulkancubes.qrc
new file mode 100644
index 0000000000..7b085e1875
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/hellovulkancubes.qrc
@@ -0,0 +1,10 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file alias="block.buf">../shared/block.buf</file>
+ <file alias="qt_logo.buf">../shared/qt_logo.buf</file>
+ <file>color_phong_vert.spv</file>
+ <file>color_phong_frag.spv</file>
+ <file>color_vert.spv</file>
+ <file>color_frag.spv</file>
+</qresource>
+</RCC>
diff --git a/examples/vulkan/hellovulkancubes/main.cpp b/examples/vulkan/hellovulkancubes/main.cpp
new file mode 100644
index 0000000000..4ec4d48645
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/main.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QLoggingCategory>
+#include "mainwindow.h"
+#include "vulkanwindow.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ const bool dbg = qEnvironmentVariableIntValue("QT_VK_DEBUG");
+
+ QVulkanInstance inst;
+
+ if (dbg) {
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
+
+#ifndef Q_OS_ANDROID
+ inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation");
+#else
+ inst.setLayers(QByteArrayList()
+ << "VK_LAYER_GOOGLE_threading"
+ << "VK_LAYER_LUNARG_parameter_validation"
+ << "VK_LAYER_LUNARG_object_tracker"
+ << "VK_LAYER_LUNARG_core_validation"
+ << "VK_LAYER_LUNARG_image"
+ << "VK_LAYER_LUNARG_swapchain"
+ << "VK_LAYER_GOOGLE_unique_objects");
+#endif
+ }
+
+ if (!inst.create())
+ qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
+
+ VulkanWindow *vulkanWindow = new VulkanWindow(dbg);
+ vulkanWindow->setVulkanInstance(&inst);
+
+ MainWindow mainWindow(vulkanWindow);
+ mainWindow.resize(1024, 768);
+ mainWindow.show();
+
+ return app.exec();
+}
diff --git a/examples/vulkan/hellovulkancubes/mainwindow.cpp b/examples/vulkan/hellovulkancubes/mainwindow.cpp
new file mode 100644
index 0000000000..2be7d237af
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/mainwindow.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "vulkanwindow.h"
+#include <QApplication>
+#include <QLabel>
+#include <QPushButton>
+#include <QLCDNumber>
+#include <QCheckBox>
+#include <QGridLayout>
+
+MainWindow::MainWindow(VulkanWindow *vulkanWindow)
+{
+ QWidget *wrapper = QWidget::createWindowContainer(vulkanWindow);
+ wrapper->setFocusPolicy(Qt::StrongFocus);
+ wrapper->setFocus();
+
+ infoLabel = new QLabel;
+ infoLabel->setFrameStyle(QFrame::Box | QFrame::Raised);
+ infoLabel->setAlignment(Qt::AlignCenter);
+ infoLabel->setText(tr("This example demonstrates instanced drawing\nof a mesh loaded from a file.\n"
+ "Uses a Phong material with a single light.\n"
+ "Also demonstrates dynamic uniform buffers\nand a bit of threading with QtConcurrent.\n"
+ "Uses 4x MSAA when available.\n"
+ "Comes with an FPS camera.\n"
+ "Hit [Shift+]WASD to walk and strafe.\nPress and move mouse to look around.\n"
+ "Click Add New to increase the number of instances."));
+
+ meshSwitch = new QCheckBox(tr("&Use Qt logo"));
+ meshSwitch->setFocusPolicy(Qt::NoFocus); // do not interfere with vulkanWindow's keyboard input
+
+ counterLcd = new QLCDNumber(5);
+ counterLcd->setSegmentStyle(QLCDNumber::Filled);
+ counterLcd->display(m_count);
+
+ newButton = new QPushButton(tr("&Add new"));
+ newButton->setFocusPolicy(Qt::NoFocus);
+ quitButton = new QPushButton(tr("&Quit"));
+ quitButton->setFocusPolicy(Qt::NoFocus);
+ pauseButton = new QPushButton(tr("&Pause"));
+ pauseButton->setFocusPolicy(Qt::NoFocus);
+
+ connect(quitButton, &QPushButton::clicked, qApp, &QCoreApplication::quit);
+ connect(newButton, &QPushButton::clicked, vulkanWindow, [=] {
+ vulkanWindow->addNew();
+ m_count = vulkanWindow->instanceCount();
+ counterLcd->display(m_count);
+ });
+ connect(pauseButton, &QPushButton::clicked, vulkanWindow, &VulkanWindow::togglePaused);
+ connect(meshSwitch, &QCheckBox::clicked, vulkanWindow, &VulkanWindow::meshSwitched);
+
+ QGridLayout *layout = new QGridLayout;
+ layout->addWidget(infoLabel, 0, 2);
+ layout->addWidget(meshSwitch, 1, 2);
+ layout->addWidget(createLabel(tr("INSTANCES")), 2, 2);
+ layout->addWidget(counterLcd, 3, 2);
+ layout->addWidget(newButton, 4, 2);
+ layout->addWidget(pauseButton, 5, 2);
+ layout->addWidget(quitButton, 6, 2);
+ layout->addWidget(wrapper, 0, 0, 7, 2);
+ setLayout(layout);
+}
+
+QLabel *MainWindow::createLabel(const QString &text)
+{
+ QLabel *lbl = new QLabel(text);
+ lbl->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
+ return lbl;
+}
diff --git a/examples/vulkan/hellovulkancubes/mainwindow.h b/examples/vulkan/hellovulkancubes/mainwindow.h
new file mode 100644
index 0000000000..4109709959
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/mainwindow.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QLCDNumber;
+class QLabel;
+class QPushButton;
+class QCheckBox;
+QT_END_NAMESPACE
+
+class VulkanWindow;
+
+class MainWindow : public QWidget
+{
+public:
+ MainWindow(VulkanWindow *vulkanWindow);
+
+private:
+ QLabel *createLabel(const QString &text);
+
+ QLabel *infoLabel;
+ QCheckBox *meshSwitch;
+ QLCDNumber *counterLcd;
+ QPushButton *newButton;
+ QPushButton *quitButton;
+ QPushButton *pauseButton;
+
+ int m_count = 128;
+};
+
+#endif
diff --git a/examples/vulkan/hellovulkancubes/mesh.cpp b/examples/vulkan/hellovulkancubes/mesh.cpp
new file mode 100644
index 0000000000..fcc45bfd57
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/mesh.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mesh.h"
+#include <QtConcurrentRun>
+#include <QFile>
+
+void Mesh::load(const QString &fn)
+{
+ reset();
+ m_maybeRunning = true;
+ m_future = QtConcurrent::run([fn]() {
+ MeshData md;
+ QFile f(fn);
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning("Failed to open %s", qPrintable(fn));
+ return md;
+ }
+ QByteArray buf = f.readAll();
+ const char *p = buf.constData();
+ quint32 format;
+ memcpy(&format, p, 4);
+ if (format != 1) {
+ qWarning("Invalid format in %s", qPrintable(fn));
+ return md;
+ }
+ int ofs = 4;
+ memcpy(&md.vertexCount, p + ofs, 4);
+ ofs += 4;
+ memcpy(md.aabb, p + ofs, 6 * 4);
+ ofs += 6 * 4;
+ const int byteCount = md.vertexCount * 8 * 4;
+ md.geom.resize(byteCount);
+ memcpy(md.geom.data(), p + ofs, byteCount);
+ return md;
+ });
+}
+
+MeshData *Mesh::data()
+{
+ if (m_maybeRunning && !m_data.isValid())
+ m_data = m_future.result();
+
+ return &m_data;
+}
+
+void Mesh::reset()
+{
+ *data() = MeshData();
+ m_maybeRunning = false;
+}
diff --git a/examples/widgets/effects/lighting/lighting.h b/examples/vulkan/hellovulkancubes/mesh.h
index 615824d46f..cb6ee9c830 100644
--- a/examples/widgets/effects/lighting/lighting.h
+++ b/examples/vulkan/hellovulkancubes/mesh.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -48,33 +48,32 @@
**
****************************************************************************/
-#ifndef LIGHTING_H
-#define LIGHTING_H
+#ifndef MESH_H
+#define MESH_H
-#include <QGraphicsEffect>
-#include <QGraphicsView>
+#include <QString>
+#include <QFuture>
-class Lighting: public QGraphicsView
+struct MeshData
{
- Q_OBJECT
+ bool isValid() const { return vertexCount > 0; }
+ int vertexCount = 0;
+ float aabb[6];
+ QByteArray geom; // x, y, z, u, v, nx, ny, nz
+};
+class Mesh
+{
public:
- Lighting(QWidget *parent = 0);
-
-private slots:
- void animate();
-
-private:
- void setupScene();
-
-protected:
- void resizeEvent(QResizeEvent *event) override;
+ void load(const QString &fn);
+ MeshData *data();
+ bool isValid() { return data()->isValid(); }
+ void reset();
private:
- qreal angle;
- QGraphicsScene m_scene;
- QGraphicsItem *m_lightSource;
- QList<QGraphicsItem*> m_items;
+ bool m_maybeRunning = false;
+ QFuture<MeshData> m_future;
+ MeshData m_data;
};
-#endif // LIGHTING_H
+#endif
diff --git a/examples/vulkan/hellovulkancubes/renderer.cpp b/examples/vulkan/hellovulkancubes/renderer.cpp
new file mode 100644
index 0000000000..523511337d
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/renderer.cpp
@@ -0,0 +1,1048 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "renderer.h"
+#include <QVulkanFunctions>
+#include <QtConcurrentRun>
+#include <QTime>
+
+static float quadVert[] = {
+ -1, -1, 0,
+ -1, 1, 0,
+ 1, -1, 0,
+ 1, 1, 0
+};
+
+#define DBG Q_UNLIKELY(m_window->isDebugEnabled())
+
+const int MAX_INSTANCES = 16384;
+const VkDeviceSize PER_INSTANCE_DATA_SIZE = 6 * sizeof(float); // instTranslate, instDiffuseAdjust
+
+static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)
+{
+ return (v + byteAlign - 1) & ~(byteAlign - 1);
+}
+
+Renderer::Renderer(VulkanWindow *w, int initialCount)
+ : m_window(w),
+ // Have the light positioned just behind the default camera position, looking forward.
+ m_lightPos(0.0f, 0.0f, 25.0f),
+ m_cam(QVector3D(0.0f, 0.0f, 20.0f)), // starting camera position
+ m_instCount(initialCount)
+{
+ qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
+
+ m_floorModel.translate(0, -5, 0);
+ m_floorModel.rotate(-90, 1, 0, 0);
+ m_floorModel.scale(20, 100, 1);
+
+ m_blockMesh.load(QStringLiteral(":/block.buf"));
+ m_logoMesh.load(QStringLiteral(":/qt_logo.buf"));
+
+ QObject::connect(&m_frameWatcher, &QFutureWatcherBase::finished, [this] {
+ if (m_framePending) {
+ m_framePending = false;
+ m_window->frameReady();
+ m_window->requestUpdate();
+ }
+ });
+}
+
+void Renderer::preInitResources()
+{
+ const QVector<int> sampleCounts = m_window->supportedSampleCounts();
+ if (DBG)
+ qDebug() << "Supported sample counts:" << sampleCounts;
+ if (sampleCounts.contains(4)) {
+ if (DBG)
+ qDebug("Requesting 4x MSAA");
+ m_window->setSampleCount(4);
+ }
+}
+
+void Renderer::initResources()
+{
+ if (DBG)
+ qDebug("Renderer init");
+
+ m_animating = true;
+ m_framePending = false;
+
+ QVulkanInstance *inst = m_window->vulkanInstance();
+ VkDevice dev = m_window->device();
+ const VkPhysicalDeviceLimits *pdevLimits = &m_window->physicalDeviceProperties()->limits;
+ const VkDeviceSize uniAlign = pdevLimits->minUniformBufferOffsetAlignment;
+
+ m_devFuncs = inst->deviceFunctions(dev);
+
+ // Note the std140 packing rules. A vec3 still has an alignment of 16,
+ // while a mat3 is like 3 * vec3.
+ m_itemMaterial.vertUniSize = aligned(2 * 64 + 48, uniAlign); // see color_phong.vert
+ m_itemMaterial.fragUniSize = aligned(6 * 16 + 12 + 2 * 4, uniAlign); // see color_phong.frag
+
+ if (!m_itemMaterial.vs.isValid())
+ m_itemMaterial.vs.load(inst, dev, QStringLiteral(":/color_phong_vert.spv"));
+ if (!m_itemMaterial.fs.isValid())
+ m_itemMaterial.fs.load(inst, dev, QStringLiteral(":/color_phong_frag.spv"));
+
+ if (!m_floorMaterial.vs.isValid())
+ m_floorMaterial.vs.load(inst, dev, QStringLiteral(":/color_vert.spv"));
+ if (!m_floorMaterial.fs.isValid())
+ m_floorMaterial.fs.load(inst, dev, QStringLiteral(":/color_frag.spv"));
+
+ m_pipelinesFuture = QtConcurrent::run(this, &Renderer::createPipelines);
+}
+
+void Renderer::createPipelines()
+{
+ VkDevice dev = m_window->device();
+
+ VkPipelineCacheCreateInfo pipelineCacheInfo;
+ memset(&pipelineCacheInfo, 0, sizeof(pipelineCacheInfo));
+ pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+ VkResult err = m_devFuncs->vkCreatePipelineCache(dev, &pipelineCacheInfo, nullptr, &m_pipelineCache);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline cache: %d", err);
+
+ createItemPipeline();
+ createFloorPipeline();
+}
+
+void Renderer::createItemPipeline()
+{
+ VkDevice dev = m_window->device();
+
+ // Vertex layout.
+ VkVertexInputBindingDescription vertexBindingDesc[] = {
+ {
+ 0, // binding
+ 8 * sizeof(float),
+ VK_VERTEX_INPUT_RATE_VERTEX
+ },
+ {
+ 1,
+ 6 * sizeof(float),
+ VK_VERTEX_INPUT_RATE_INSTANCE
+ }
+ };
+ VkVertexInputAttributeDescription vertexAttrDesc[] = {
+ { // position
+ 0, // location
+ 0, // binding
+ VK_FORMAT_R32G32B32_SFLOAT,
+ 0 // offset
+ },
+ { // normal
+ 1,
+ 0,
+ VK_FORMAT_R32G32B32_SFLOAT,
+ 5 * sizeof(float)
+ },
+ { // instTranslate
+ 2,
+ 1,
+ VK_FORMAT_R32G32B32_SFLOAT,
+ 0
+ },
+ { // instDiffuseAdjust
+ 3,
+ 1,
+ VK_FORMAT_R32G32B32_SFLOAT,
+ 3 * sizeof(float)
+ }
+ };
+
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo;
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.pNext = nullptr;
+ vertexInputInfo.flags = 0;
+ vertexInputInfo.vertexBindingDescriptionCount = sizeof(vertexBindingDesc) / sizeof(vertexBindingDesc[0]);
+ vertexInputInfo.pVertexBindingDescriptions = vertexBindingDesc;
+ vertexInputInfo.vertexAttributeDescriptionCount = sizeof(vertexAttrDesc) / sizeof(vertexAttrDesc[0]);
+ vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc;
+
+ // Descriptor set layout.
+ VkDescriptorPoolSize descPoolSizes[] = {
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 2 }
+ };
+ VkDescriptorPoolCreateInfo descPoolInfo;
+ memset(&descPoolInfo, 0, sizeof(descPoolInfo));
+ descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ descPoolInfo.maxSets = 1; // a single set is enough due to the dynamic uniform buffer
+ descPoolInfo.poolSizeCount = sizeof(descPoolSizes) / sizeof(descPoolSizes[0]);
+ descPoolInfo.pPoolSizes = descPoolSizes;
+ VkResult err = m_devFuncs->vkCreateDescriptorPool(dev, &descPoolInfo, nullptr, &m_itemMaterial.descPool);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor pool: %d", err);
+
+ VkDescriptorSetLayoutBinding layoutBindings[] =
+ {
+ {
+ 0, // binding
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ 1, // descriptorCount
+ VK_SHADER_STAGE_VERTEX_BIT,
+ nullptr
+ },
+ {
+ 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ 1,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ nullptr
+ }
+ };
+ VkDescriptorSetLayoutCreateInfo descLayoutInfo = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ nullptr,
+ 0,
+ sizeof(layoutBindings) / sizeof(layoutBindings[0]),
+ layoutBindings
+ };
+ err = m_devFuncs->vkCreateDescriptorSetLayout(dev, &descLayoutInfo, nullptr, &m_itemMaterial.descSetLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor set layout: %d", err);
+
+ VkDescriptorSetAllocateInfo descSetAllocInfo = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ nullptr,
+ m_itemMaterial.descPool,
+ 1,
+ &m_itemMaterial.descSetLayout
+ };
+ err = m_devFuncs->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_itemMaterial.descSet);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate descriptor set: %d", err);
+
+ // Graphics pipeline.
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo;
+ memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo));
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &m_itemMaterial.descSetLayout;
+
+ err = m_devFuncs->vkCreatePipelineLayout(dev, &pipelineLayoutInfo, nullptr, &m_itemMaterial.pipelineLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline layout: %d", err);
+
+ VkGraphicsPipelineCreateInfo pipelineInfo;
+ memset(&pipelineInfo, 0, sizeof(pipelineInfo));
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+
+ VkPipelineShaderStageCreateInfo shaderStages[2] = {
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ m_itemMaterial.vs.data()->shaderModule,
+ "main",
+ nullptr
+ },
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ m_itemMaterial.fs.data()->shaderModule,
+ "main",
+ nullptr
+ }
+ };
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+
+ VkPipelineInputAssemblyStateCreateInfo ia;
+ memset(&ia, 0, sizeof(ia));
+ ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ pipelineInfo.pInputAssemblyState = &ia;
+
+ VkPipelineViewportStateCreateInfo vp;
+ memset(&vp, 0, sizeof(vp));
+ vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vp.viewportCount = 1;
+ vp.scissorCount = 1;
+ pipelineInfo.pViewportState = &vp;
+
+ VkPipelineRasterizationStateCreateInfo rs;
+ memset(&rs, 0, sizeof(rs));
+ rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rs.polygonMode = VK_POLYGON_MODE_FILL;
+ rs.cullMode = VK_CULL_MODE_BACK_BIT;
+ rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rs.lineWidth = 1.0f;
+ pipelineInfo.pRasterizationState = &rs;
+
+ VkPipelineMultisampleStateCreateInfo ms;
+ memset(&ms, 0, sizeof(ms));
+ ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ ms.rasterizationSamples = m_window->sampleCountFlagBits();
+ pipelineInfo.pMultisampleState = &ms;
+
+ VkPipelineDepthStencilStateCreateInfo ds;
+ memset(&ds, 0, sizeof(ds));
+ ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ ds.depthTestEnable = VK_TRUE;
+ ds.depthWriteEnable = VK_TRUE;
+ ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
+ pipelineInfo.pDepthStencilState = &ds;
+
+ VkPipelineColorBlendStateCreateInfo cb;
+ memset(&cb, 0, sizeof(cb));
+ cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ VkPipelineColorBlendAttachmentState att;
+ memset(&att, 0, sizeof(att));
+ att.colorWriteMask = 0xF;
+ cb.attachmentCount = 1;
+ cb.pAttachments = &att;
+ pipelineInfo.pColorBlendState = &cb;
+
+ VkDynamicState dynEnable[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+ VkPipelineDynamicStateCreateInfo dyn;
+ memset(&dyn, 0, sizeof(dyn));
+ dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dyn.dynamicStateCount = sizeof(dynEnable) / sizeof(VkDynamicState);
+ dyn.pDynamicStates = dynEnable;
+ pipelineInfo.pDynamicState = &dyn;
+
+ pipelineInfo.layout = m_itemMaterial.pipelineLayout;
+ pipelineInfo.renderPass = m_window->defaultRenderPass();
+
+ err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_itemMaterial.pipeline);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create graphics pipeline: %d", err);
+}
+
+void Renderer::createFloorPipeline()
+{
+ VkDevice dev = m_window->device();
+
+ // Vertex layout.
+ VkVertexInputBindingDescription vertexBindingDesc = {
+ 0, // binding
+ 3 * sizeof(float),
+ VK_VERTEX_INPUT_RATE_VERTEX
+ };
+ VkVertexInputAttributeDescription vertexAttrDesc[] = {
+ { // position
+ 0, // location
+ 0, // binding
+ VK_FORMAT_R32G32B32_SFLOAT,
+ 0 // offset
+ },
+ };
+
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo;
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.pNext = nullptr;
+ vertexInputInfo.flags = 0;
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDesc;
+ vertexInputInfo.vertexAttributeDescriptionCount = sizeof(vertexAttrDesc) / sizeof(vertexAttrDesc[0]);
+ vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc;
+
+ // Do not bother with uniform buffers and descriptors, all the data fits
+ // into the spec mandated minimum of 128 bytes for push constants.
+ VkPushConstantRange pcr[] = {
+ // mvp
+ {
+ VK_SHADER_STAGE_VERTEX_BIT,
+ 0,
+ 64
+ },
+ // color
+ {
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ 64,
+ 12
+ }
+ };
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo;
+ memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo));
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.pushConstantRangeCount = sizeof(pcr) / sizeof(pcr[0]);
+ pipelineLayoutInfo.pPushConstantRanges = pcr;
+
+ VkResult err = m_devFuncs->vkCreatePipelineLayout(dev, &pipelineLayoutInfo, nullptr, &m_floorMaterial.pipelineLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline layout: %d", err);
+
+ VkGraphicsPipelineCreateInfo pipelineInfo;
+ memset(&pipelineInfo, 0, sizeof(pipelineInfo));
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+
+ VkPipelineShaderStageCreateInfo shaderStages[2] = {
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ m_floorMaterial.vs.data()->shaderModule,
+ "main",
+ nullptr
+ },
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ m_floorMaterial.fs.data()->shaderModule,
+ "main",
+ nullptr
+ }
+ };
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+
+ VkPipelineInputAssemblyStateCreateInfo ia;
+ memset(&ia, 0, sizeof(ia));
+ ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ pipelineInfo.pInputAssemblyState = &ia;
+
+ VkPipelineViewportStateCreateInfo vp;
+ memset(&vp, 0, sizeof(vp));
+ vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vp.viewportCount = 1;
+ vp.scissorCount = 1;
+ pipelineInfo.pViewportState = &vp;
+
+ VkPipelineRasterizationStateCreateInfo rs;
+ memset(&rs, 0, sizeof(rs));
+ rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rs.polygonMode = VK_POLYGON_MODE_FILL;
+ rs.cullMode = VK_CULL_MODE_BACK_BIT;
+ rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ rs.lineWidth = 1.0f;
+ pipelineInfo.pRasterizationState = &rs;
+
+ VkPipelineMultisampleStateCreateInfo ms;
+ memset(&ms, 0, sizeof(ms));
+ ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ ms.rasterizationSamples = m_window->sampleCountFlagBits();
+ pipelineInfo.pMultisampleState = &ms;
+
+ VkPipelineDepthStencilStateCreateInfo ds;
+ memset(&ds, 0, sizeof(ds));
+ ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ ds.depthTestEnable = VK_TRUE;
+ ds.depthWriteEnable = VK_TRUE;
+ ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
+ pipelineInfo.pDepthStencilState = &ds;
+
+ VkPipelineColorBlendStateCreateInfo cb;
+ memset(&cb, 0, sizeof(cb));
+ cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ VkPipelineColorBlendAttachmentState att;
+ memset(&att, 0, sizeof(att));
+ att.colorWriteMask = 0xF;
+ cb.attachmentCount = 1;
+ cb.pAttachments = &att;
+ pipelineInfo.pColorBlendState = &cb;
+
+ VkDynamicState dynEnable[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+ VkPipelineDynamicStateCreateInfo dyn;
+ memset(&dyn, 0, sizeof(dyn));
+ dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dyn.dynamicStateCount = sizeof(dynEnable) / sizeof(VkDynamicState);
+ dyn.pDynamicStates = dynEnable;
+ pipelineInfo.pDynamicState = &dyn;
+
+ pipelineInfo.layout = m_floorMaterial.pipelineLayout;
+ pipelineInfo.renderPass = m_window->defaultRenderPass();
+
+ err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_floorMaterial.pipeline);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create graphics pipeline: %d", err);
+}
+
+void Renderer::initSwapChainResources()
+{
+ m_proj = m_window->clipCorrectionMatrix();
+ const QSize sz = m_window->swapChainImageSize();
+ m_proj.perspective(45.0f, sz.width() / (float) sz.height(), 0.01f, 1000.0f);
+ markViewProjDirty();
+}
+
+void Renderer::releaseSwapChainResources()
+{
+ // It is important to finish the pending frame right here since this is the
+ // last opportunity to act with all resources intact.
+ m_frameWatcher.waitForFinished();
+ // Cannot count on the finished() signal being emitted before returning
+ // from here.
+ if (m_framePending) {
+ m_framePending = false;
+ m_window->frameReady();
+ }
+}
+
+void Renderer::releaseResources()
+{
+ if (DBG)
+ qDebug("Renderer release");
+
+ m_pipelinesFuture.waitForFinished();
+
+ VkDevice dev = m_window->device();
+
+ if (m_itemMaterial.descSetLayout) {
+ m_devFuncs->vkDestroyDescriptorSetLayout(dev, m_itemMaterial.descSetLayout, nullptr);
+ m_itemMaterial.descSetLayout = VK_NULL_HANDLE;
+ }
+
+ if (m_itemMaterial.descPool) {
+ m_devFuncs->vkDestroyDescriptorPool(dev, m_itemMaterial.descPool, nullptr);
+ m_itemMaterial.descPool = VK_NULL_HANDLE;
+ }
+
+ if (m_itemMaterial.pipeline) {
+ m_devFuncs->vkDestroyPipeline(dev, m_itemMaterial.pipeline, nullptr);
+ m_itemMaterial.pipeline = VK_NULL_HANDLE;
+ }
+
+ if (m_itemMaterial.pipelineLayout) {
+ m_devFuncs->vkDestroyPipelineLayout(dev, m_itemMaterial.pipelineLayout, nullptr);
+ m_itemMaterial.pipelineLayout = VK_NULL_HANDLE;
+ }
+
+ if (m_floorMaterial.pipeline) {
+ m_devFuncs->vkDestroyPipeline(dev, m_floorMaterial.pipeline, nullptr);
+ m_floorMaterial.pipeline = VK_NULL_HANDLE;
+ }
+
+ if (m_floorMaterial.pipelineLayout) {
+ m_devFuncs->vkDestroyPipelineLayout(dev, m_floorMaterial.pipelineLayout, nullptr);
+ m_floorMaterial.pipelineLayout = VK_NULL_HANDLE;
+ }
+
+ if (m_pipelineCache) {
+ m_devFuncs->vkDestroyPipelineCache(dev, m_pipelineCache, nullptr);
+ m_pipelineCache = VK_NULL_HANDLE;
+ }
+
+ if (m_blockVertexBuf) {
+ m_devFuncs->vkDestroyBuffer(dev, m_blockVertexBuf, nullptr);
+ m_blockVertexBuf = VK_NULL_HANDLE;
+ }
+
+ if (m_logoVertexBuf) {
+ m_devFuncs->vkDestroyBuffer(dev, m_logoVertexBuf, nullptr);
+ m_logoVertexBuf = VK_NULL_HANDLE;
+ }
+
+ if (m_floorVertexBuf) {
+ m_devFuncs->vkDestroyBuffer(dev, m_floorVertexBuf, nullptr);
+ m_floorVertexBuf = VK_NULL_HANDLE;
+ }
+
+ if (m_uniBuf) {
+ m_devFuncs->vkDestroyBuffer(dev, m_uniBuf, nullptr);
+ m_uniBuf = VK_NULL_HANDLE;
+ }
+
+ if (m_bufMem) {
+ m_devFuncs->vkFreeMemory(dev, m_bufMem, nullptr);
+ m_bufMem = VK_NULL_HANDLE;
+ }
+
+ if (m_instBuf) {
+ m_devFuncs->vkDestroyBuffer(dev, m_instBuf, nullptr);
+ m_instBuf = VK_NULL_HANDLE;
+ }
+
+ if (m_instBufMem) {
+ m_devFuncs->vkFreeMemory(dev, m_instBufMem, nullptr);
+ m_instBufMem = VK_NULL_HANDLE;
+ }
+
+ if (m_itemMaterial.vs.isValid()) {
+ m_devFuncs->vkDestroyShaderModule(dev, m_itemMaterial.vs.data()->shaderModule, nullptr);
+ m_itemMaterial.vs.reset();
+ }
+ if (m_itemMaterial.fs.isValid()) {
+ m_devFuncs->vkDestroyShaderModule(dev, m_itemMaterial.fs.data()->shaderModule, nullptr);
+ m_itemMaterial.fs.reset();
+ }
+
+ if (m_floorMaterial.vs.isValid()) {
+ m_devFuncs->vkDestroyShaderModule(dev, m_floorMaterial.vs.data()->shaderModule, nullptr);
+ m_floorMaterial.vs.reset();
+ }
+ if (m_floorMaterial.fs.isValid()) {
+ m_devFuncs->vkDestroyShaderModule(dev, m_floorMaterial.fs.data()->shaderModule, nullptr);
+ m_floorMaterial.fs.reset();
+ }
+}
+
+void Renderer::ensureBuffers()
+{
+ if (m_blockVertexBuf)
+ return;
+
+ VkDevice dev = m_window->device();
+ const int concurrentFrameCount = m_window->concurrentFrameCount();
+
+ // Vertex buffer for the block.
+ VkBufferCreateInfo bufInfo;
+ memset(&bufInfo, 0, sizeof(bufInfo));
+ bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ const int blockMeshByteCount = m_blockMesh.data()->vertexCount * 8 * sizeof(float);
+ bufInfo.size = blockMeshByteCount;
+ bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ VkResult err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_blockVertexBuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create vertex buffer: %d", err);
+
+ VkMemoryRequirements blockVertMemReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(dev, m_blockVertexBuf, &blockVertMemReq);
+
+ // Vertex buffer for the logo.
+ const int logoMeshByteCount = m_logoMesh.data()->vertexCount * 8 * sizeof(float);
+ bufInfo.size = logoMeshByteCount;
+ bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_logoVertexBuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create vertex buffer: %d", err);
+
+ VkMemoryRequirements logoVertMemReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(dev, m_logoVertexBuf, &logoVertMemReq);
+
+ // Vertex buffer for the floor.
+ bufInfo.size = sizeof(quadVert);
+ err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_floorVertexBuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create vertex buffer: %d", err);
+
+ VkMemoryRequirements floorVertMemReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(dev, m_floorVertexBuf, &floorVertMemReq);
+
+ // Uniform buffer. Instead of using multiple descriptor sets, we take a
+ // different approach: have a single dynamic uniform buffer and specify the
+ // active-frame-specific offset at the time of binding the descriptor set.
+ bufInfo.size = (m_itemMaterial.vertUniSize + m_itemMaterial.fragUniSize) * concurrentFrameCount;
+ bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_uniBuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create uniform buffer: %d", err);
+
+ VkMemoryRequirements uniMemReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(dev, m_uniBuf, &uniMemReq);
+
+ // Allocate memory for everything at once.
+ VkDeviceSize logoVertStartOffset = aligned(0 + blockVertMemReq.size, logoVertMemReq.alignment);
+ VkDeviceSize floorVertStartOffset = aligned(logoVertStartOffset + logoVertMemReq.size, floorVertMemReq.alignment);
+ m_itemMaterial.uniMemStartOffset = aligned(floorVertStartOffset + floorVertMemReq.size, uniMemReq.alignment);
+ VkMemoryAllocateInfo memAllocInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ nullptr,
+ m_itemMaterial.uniMemStartOffset + uniMemReq.size,
+ m_window->hostVisibleMemoryIndex()
+ };
+ err = m_devFuncs->vkAllocateMemory(dev, &memAllocInfo, nullptr, &m_bufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate memory: %d", err);
+
+ err = m_devFuncs->vkBindBufferMemory(dev, m_blockVertexBuf, m_bufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind vertex buffer memory: %d", err);
+ err = m_devFuncs->vkBindBufferMemory(dev, m_logoVertexBuf, m_bufMem, logoVertStartOffset);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind vertex buffer memory: %d", err);
+ err = m_devFuncs->vkBindBufferMemory(dev, m_floorVertexBuf, m_bufMem, floorVertStartOffset);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind vertex buffer memory: %d", err);
+ err = m_devFuncs->vkBindBufferMemory(dev, m_uniBuf, m_bufMem, m_itemMaterial.uniMemStartOffset);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind uniform buffer memory: %d", err);
+
+ // Copy vertex data.
+ quint8 *p;
+ err = m_devFuncs->vkMapMemory(dev, m_bufMem, 0, m_itemMaterial.uniMemStartOffset, 0, reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS)
+ qFatal("Failed to map memory: %d", err);
+ memcpy(p, m_blockMesh.data()->geom.constData(), blockMeshByteCount);
+ memcpy(p + logoVertStartOffset, m_logoMesh.data()->geom.constData(), logoMeshByteCount);
+ memcpy(p + floorVertStartOffset, quadVert, sizeof(quadVert));
+ m_devFuncs->vkUnmapMemory(dev, m_bufMem);
+
+ // Write descriptors for the uniform buffers in the vertex and fragment shaders.
+ VkDescriptorBufferInfo vertUni = { m_uniBuf, 0, m_itemMaterial.vertUniSize };
+ VkDescriptorBufferInfo fragUni = { m_uniBuf, m_itemMaterial.vertUniSize, m_itemMaterial.fragUniSize };
+
+ VkWriteDescriptorSet descWrite[2];
+ memset(descWrite, 0, sizeof(descWrite));
+ descWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descWrite[0].dstSet = m_itemMaterial.descSet;
+ descWrite[0].dstBinding = 0;
+ descWrite[0].descriptorCount = 1;
+ descWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+ descWrite[0].pBufferInfo = &vertUni;
+
+ descWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descWrite[1].dstSet = m_itemMaterial.descSet;
+ descWrite[1].dstBinding = 1;
+ descWrite[1].descriptorCount = 1;
+ descWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+ descWrite[1].pBufferInfo = &fragUni;
+
+ m_devFuncs->vkUpdateDescriptorSets(dev, 2, descWrite, 0, nullptr);
+}
+
+void Renderer::ensureInstanceBuffer()
+{
+ if (m_instCount == m_preparedInstCount && m_instBuf)
+ return;
+
+ Q_ASSERT(m_instCount <= MAX_INSTANCES);
+
+ VkDevice dev = m_window->device();
+
+ // allocate only once, for the maximum instance count
+ if (!m_instBuf) {
+ VkBufferCreateInfo bufInfo;
+ memset(&bufInfo, 0, sizeof(bufInfo));
+ bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufInfo.size = MAX_INSTANCES * PER_INSTANCE_DATA_SIZE;
+ bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+
+ // Keep a copy of the data since we may lose all graphics resources on
+ // unexpose, and reinitializing to new random positions afterwards
+ // would not be nice.
+ m_instData.resize(bufInfo.size);
+
+ VkResult err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_instBuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create instance buffer: %d", err);
+
+ VkMemoryRequirements memReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(dev, m_instBuf, &memReq);
+ if (DBG)
+ qDebug("Allocating %u bytes for instance data", uint32_t(memReq.size));
+
+ VkMemoryAllocateInfo memAllocInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ nullptr,
+ memReq.size,
+ m_window->hostVisibleMemoryIndex()
+ };
+ err = m_devFuncs->vkAllocateMemory(dev, &memAllocInfo, nullptr, &m_instBufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate memory: %d", err);
+
+ err = m_devFuncs->vkBindBufferMemory(dev, m_instBuf, m_instBufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind instance buffer memory: %d", err);
+ }
+
+ if (m_instCount != m_preparedInstCount) {
+ if (DBG)
+ qDebug("Preparing instances %d..%d", m_preparedInstCount, m_instCount - 1);
+ char *p = m_instData.data();
+ p += m_preparedInstCount * PER_INSTANCE_DATA_SIZE;
+ auto gen = [](float a, float b) { return float((qrand() % int(b - a + 1)) + a); };
+ for (int i = m_preparedInstCount; i < m_instCount; ++i) {
+ // Apply a random translation to each instance of the mesh.
+ float t[] = { gen(-5, 5), gen(-4, 6), gen(-30, 5) };
+ memcpy(p, t, 12);
+ // Apply a random adjustment to the diffuse color for each instance. (default is 0.7)
+ float d[] = { gen(-6, 3) / 10.0f, gen(-6, 3) / 10.0f, gen(-6, 3) / 10.0f };
+ memcpy(p + 12, d, 12);
+ p += PER_INSTANCE_DATA_SIZE;
+ }
+ m_preparedInstCount = m_instCount;
+ }
+
+ quint8 *p;
+ VkResult err = m_devFuncs->vkMapMemory(dev, m_instBufMem, 0, m_instCount * PER_INSTANCE_DATA_SIZE, 0,
+ reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS)
+ qFatal("Failed to map memory: %d", err);
+ memcpy(p, m_instData.constData(), m_instData.size());
+ m_devFuncs->vkUnmapMemory(dev, m_instBufMem);
+}
+
+void Renderer::getMatrices(QMatrix4x4 *vp, QMatrix4x4 *model, QMatrix3x3 *modelNormal, QVector3D *eyePos)
+{
+ model->setToIdentity();
+ if (m_useLogo)
+ model->rotate(90, 1, 0, 0);
+ model->rotate(m_rotation, 1, 1, 0);
+
+ *modelNormal = model->normalMatrix();
+
+ QMatrix4x4 view = m_cam.viewMatrix();
+ *vp = m_proj * view;
+
+ *eyePos = view.inverted().column(3).toVector3D();
+}
+
+void Renderer::writeFragUni(quint8 *p, const QVector3D &eyePos)
+{
+ float ECCameraPosition[] = { eyePos.x(), eyePos.y(), eyePos.z() };
+ memcpy(p, ECCameraPosition, 12);
+ p += 16;
+
+ // Material
+ float ka[] = { 0.05f, 0.05f, 0.05f };
+ memcpy(p, ka, 12);
+ p += 16;
+
+ float kd[] = { 0.7f, 0.7f, 0.7f };
+ memcpy(p, kd, 12);
+ p += 16;
+
+ float ks[] = { 0.66f, 0.66f, 0.66f };
+ memcpy(p, ks, 12);
+ p += 16;
+
+ // Light parameters
+ float ECLightPosition[] = { m_lightPos.x(), m_lightPos.y(), m_lightPos.z() };
+ memcpy(p, ECLightPosition, 12);
+ p += 16;
+
+ float att[] = { 1, 0, 0 };
+ memcpy(p, att, 12);
+ p += 16;
+
+ float color[] = { 1.0f, 1.0f, 1.0f };
+ memcpy(p, color, 12);
+ p += 12; // next we have two floats which have an alignment of 4, hence 12 only
+
+ float intensity = 0.8f;
+ memcpy(p, &intensity, 4);
+ p += 4;
+
+ float specularExp = 150.0f;
+ memcpy(p, &specularExp, 4);
+ p += 4;
+}
+
+void Renderer::startNextFrame()
+{
+ // For demonstration purposes offload the command buffer generation onto a
+ // worker thread and continue with the frame submission only when it has
+ // finished.
+ Q_ASSERT(!m_framePending);
+ m_framePending = true;
+ QFuture<void> future = QtConcurrent::run(this, &Renderer::buildFrame);
+ m_frameWatcher.setFuture(future);
+}
+
+void Renderer::buildFrame()
+{
+ QMutexLocker locker(&m_guiMutex);
+
+ ensureBuffers();
+ ensureInstanceBuffer();
+ m_pipelinesFuture.waitForFinished();
+
+ VkCommandBuffer cb = m_window->currentCommandBuffer();
+ const QSize sz = m_window->swapChainImageSize();
+
+ VkClearColorValue clearColor = { 0.67f, 0.84f, 0.9f, 1.0f };
+ VkClearDepthStencilValue clearDS = { 1, 0 };
+ VkClearValue clearValues[3];
+ memset(clearValues, 0, sizeof(clearValues));
+ clearValues[0].color = clearValues[2].color = clearColor;
+ clearValues[1].depthStencil = clearDS;
+
+ VkRenderPassBeginInfo rpBeginInfo;
+ memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
+ rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ rpBeginInfo.renderPass = m_window->defaultRenderPass();
+ rpBeginInfo.framebuffer = m_window->currentFramebuffer();
+ rpBeginInfo.renderArea.extent.width = sz.width();
+ rpBeginInfo.renderArea.extent.height = sz.height();
+ rpBeginInfo.clearValueCount = m_window->sampleCountFlagBits() > VK_SAMPLE_COUNT_1_BIT ? 3 : 2;
+ rpBeginInfo.pClearValues = clearValues;
+ VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
+ m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ VkViewport viewport = {
+ 0, 0,
+ float(sz.width()), float(sz.height()),
+ 0, 1
+ };
+ m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport);
+
+ VkRect2D scissor = {
+ { 0, 0 },
+ { uint32_t(sz.width()), uint32_t(sz.height()) }
+ };
+ m_devFuncs->vkCmdSetScissor(cb, 0, 1, &scissor);
+
+ buildDrawCallsForFloor();
+ buildDrawCallsForItems();
+
+ m_devFuncs->vkCmdEndRenderPass(cmdBuf);
+}
+
+void Renderer::buildDrawCallsForItems()
+{
+ VkDevice dev = m_window->device();
+ VkCommandBuffer cb = m_window->currentCommandBuffer();
+
+ m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_itemMaterial.pipeline);
+
+ VkDeviceSize vbOffset = 0;
+ m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, m_useLogo ? &m_logoVertexBuf : &m_blockVertexBuf, &vbOffset);
+ m_devFuncs->vkCmdBindVertexBuffers(cb, 1, 1, &m_instBuf, &vbOffset);
+
+ // Now provide offsets so that the two dynamic buffers point to the
+ // beginning of the vertex and fragment uniform data for the current frame.
+ uint32_t frameUniOffset = m_window->currentFrame() * (m_itemMaterial.vertUniSize + m_itemMaterial.fragUniSize);
+ uint32_t frameUniOffsets[] = { frameUniOffset, frameUniOffset };
+ m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_itemMaterial.pipelineLayout, 0, 1,
+ &m_itemMaterial.descSet, 2, frameUniOffsets);
+
+ if (m_animating)
+ m_rotation += 0.5;
+
+ if (m_animating || m_vpDirty) {
+ if (m_vpDirty)
+ --m_vpDirty;
+ QMatrix4x4 vp, model;
+ QMatrix3x3 modelNormal;
+ QVector3D eyePos;
+ getMatrices(&vp, &model, &modelNormal, &eyePos);
+
+ // Map the uniform data for the current frame, ignore the geometry data at
+ // the beginning and the uniforms for other frames.
+ quint8 *p;
+ VkResult err = m_devFuncs->vkMapMemory(dev, m_bufMem,
+ m_itemMaterial.uniMemStartOffset + frameUniOffset,
+ m_itemMaterial.vertUniSize + m_itemMaterial.fragUniSize,
+ 0, reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS)
+ qFatal("Failed to map memory: %d", err);
+
+ // Vertex shader uniforms
+ memcpy(p, vp.constData(), 64);
+ memcpy(p + 64, model.constData(), 64);
+ const float *mnp = modelNormal.constData();
+ memcpy(p + 128, mnp, 12);
+ memcpy(p + 128 + 16, mnp + 3, 12);
+ memcpy(p + 128 + 32, mnp + 6, 12);
+
+ // Fragment shader uniforms
+ p += m_itemMaterial.vertUniSize;
+ writeFragUni(p, eyePos);
+
+ m_devFuncs->vkUnmapMemory(dev, m_bufMem);
+ }
+
+ m_devFuncs->vkCmdDraw(cb, (m_useLogo ? m_logoMesh.data() : m_blockMesh.data())->vertexCount, m_instCount, 0, 0);
+}
+
+void Renderer::buildDrawCallsForFloor()
+{
+ VkCommandBuffer cb = m_window->currentCommandBuffer();
+
+ m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_floorMaterial.pipeline);
+
+ VkDeviceSize vbOffset = 0;
+ m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_floorVertexBuf, &vbOffset);
+
+ QMatrix4x4 mvp = m_proj * m_cam.viewMatrix() * m_floorModel;
+ m_devFuncs->vkCmdPushConstants(cb, m_floorMaterial.pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, 64, mvp.constData());
+ float color[] = { 0.67f, 1.0f, 0.2f };
+ m_devFuncs->vkCmdPushConstants(cb, m_floorMaterial.pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 64, 12, color);
+
+ m_devFuncs->vkCmdDraw(cb, 4, 1, 0, 0);
+}
+
+void Renderer::addNew()
+{
+ QMutexLocker locker(&m_guiMutex);
+ m_instCount = qMin(m_instCount + 16, MAX_INSTANCES);
+}
+
+void Renderer::yaw(float degrees)
+{
+ QMutexLocker locker(&m_guiMutex);
+ m_cam.yaw(degrees);
+ markViewProjDirty();
+}
+
+void Renderer::pitch(float degrees)
+{
+ QMutexLocker locker(&m_guiMutex);
+ m_cam.pitch(degrees);
+ markViewProjDirty();
+}
+
+void Renderer::walk(float amount)
+{
+ QMutexLocker locker(&m_guiMutex);
+ m_cam.walk(amount);
+ markViewProjDirty();
+}
+
+void Renderer::strafe(float amount)
+{
+ QMutexLocker locker(&m_guiMutex);
+ m_cam.strafe(amount);
+ markViewProjDirty();
+}
+
+void Renderer::setUseLogo(bool b)
+{
+ QMutexLocker locker(&m_guiMutex);
+ m_useLogo = b;
+ if (!m_animating)
+ m_window->requestUpdate();
+}
diff --git a/examples/vulkan/hellovulkancubes/renderer.h b/examples/vulkan/hellovulkancubes/renderer.h
new file mode 100644
index 0000000000..60bb48377e
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/renderer.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include "vulkanwindow.h"
+#include "mesh.h"
+#include "shader.h"
+#include "camera.h"
+#include <QFutureWatcher>
+#include <QMutex>
+
+class Renderer : public QVulkanWindowRenderer
+{
+public:
+ Renderer(VulkanWindow *w, int initialCount);
+
+ void preInitResources() override;
+ void initResources() override;
+ void initSwapChainResources() override;
+ void releaseSwapChainResources() override;
+ void releaseResources() override;
+
+ void startNextFrame() override;
+
+ bool animating() const { return m_animating; }
+ void setAnimating(bool a) { m_animating = a; }
+
+ int instanceCount() const { return m_instCount; }
+ void addNew();
+
+ void yaw(float degrees);
+ void pitch(float degrees);
+ void walk(float amount);
+ void strafe(float amount);
+
+ void setUseLogo(bool b);
+
+private:
+ void createPipelines();
+ void createItemPipeline();
+ void createFloorPipeline();
+ void ensureBuffers();
+ void ensureInstanceBuffer();
+ void getMatrices(QMatrix4x4 *mvp, QMatrix4x4 *model, QMatrix3x3 *modelNormal, QVector3D *eyePos);
+ void writeFragUni(quint8 *p, const QVector3D &eyePos);
+ void buildFrame();
+ void buildDrawCallsForItems();
+ void buildDrawCallsForFloor();
+
+ void markViewProjDirty() { m_vpDirty = m_window->concurrentFrameCount(); }
+
+ VulkanWindow *m_window;
+ QVulkanDeviceFunctions *m_devFuncs;
+
+ bool m_useLogo = false;
+ Mesh m_blockMesh;
+ Mesh m_logoMesh;
+ VkBuffer m_blockVertexBuf = VK_NULL_HANDLE;
+ VkBuffer m_logoVertexBuf = VK_NULL_HANDLE;
+ struct {
+ VkDeviceSize vertUniSize;
+ VkDeviceSize fragUniSize;
+ VkDeviceSize uniMemStartOffset;
+ Shader vs;
+ Shader fs;
+ VkDescriptorPool descPool = VK_NULL_HANDLE;
+ VkDescriptorSetLayout descSetLayout = VK_NULL_HANDLE;
+ VkDescriptorSet descSet;
+ VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ } m_itemMaterial;
+
+ VkBuffer m_floorVertexBuf = VK_NULL_HANDLE;
+ struct {
+ Shader vs;
+ Shader fs;
+ VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ } m_floorMaterial;
+
+ VkDeviceMemory m_bufMem = VK_NULL_HANDLE;
+ VkBuffer m_uniBuf = VK_NULL_HANDLE;
+
+ VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
+ QFuture<void> m_pipelinesFuture;
+
+ QVector3D m_lightPos;
+ Camera m_cam;
+
+ QMatrix4x4 m_proj;
+ int m_vpDirty = 0;
+ QMatrix4x4 m_floorModel;
+
+ bool m_animating;
+ float m_rotation = 0.0f;
+
+ int m_instCount;
+ int m_preparedInstCount = 0;
+ QByteArray m_instData;
+ VkBuffer m_instBuf = VK_NULL_HANDLE;
+ VkDeviceMemory m_instBufMem = VK_NULL_HANDLE;
+
+ QFutureWatcher<void> m_frameWatcher;
+ bool m_framePending;
+
+ QMutex m_guiMutex;
+};
+
+#endif
diff --git a/examples/vulkan/hellovulkancubes/shader.cpp b/examples/vulkan/hellovulkancubes/shader.cpp
new file mode 100644
index 0000000000..e1c01c6842
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/shader.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "shader.h"
+#include <QtConcurrentRun>
+#include <QFile>
+#include <QVulkanDeviceFunctions>
+
+void Shader::load(QVulkanInstance *inst, VkDevice dev, const QString &fn)
+{
+ reset();
+ m_maybeRunning = true;
+ m_future = QtConcurrent::run([inst, dev, fn]() {
+ ShaderData sd;
+ QFile f(fn);
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning("Failed to open %s", qPrintable(fn));
+ return sd;
+ }
+ QByteArray blob = f.readAll();
+ VkShaderModuleCreateInfo shaderInfo;
+ memset(&shaderInfo, 0, sizeof(shaderInfo));
+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shaderInfo.codeSize = blob.size();
+ shaderInfo.pCode = reinterpret_cast<const uint32_t *>(blob.constData());
+ VkResult err = inst->deviceFunctions(dev)->vkCreateShaderModule(dev, &shaderInfo, nullptr, &sd.shaderModule);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create shader module: %d", err);
+ return sd;
+ }
+ return sd;
+ });
+}
+
+ShaderData *Shader::data()
+{
+ if (m_maybeRunning && !m_data.isValid())
+ m_data = m_future.result();
+
+ return &m_data;
+}
+
+void Shader::reset()
+{
+ *data() = ShaderData();
+ m_maybeRunning = false;
+}
diff --git a/examples/vulkan/hellovulkancubes/shader.h b/examples/vulkan/hellovulkancubes/shader.h
new file mode 100644
index 0000000000..265868d2b0
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/shader.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHADER_H
+#define SHADER_H
+
+#include <QVulkanInstance>
+#include <QFuture>
+
+struct ShaderData
+{
+ bool isValid() const { return shaderModule != VK_NULL_HANDLE; }
+ VkShaderModule shaderModule = VK_NULL_HANDLE;
+};
+
+class Shader
+{
+public:
+ void load(QVulkanInstance *inst, VkDevice dev, const QString &fn);
+ ShaderData *data();
+ bool isValid() { return data()->isValid(); }
+ void reset();
+
+private:
+ bool m_maybeRunning = false;
+ QFuture<ShaderData> m_future;
+ ShaderData m_data;
+};
+
+#endif
diff --git a/examples/vulkan/hellovulkancubes/vulkanwindow.cpp b/examples/vulkan/hellovulkancubes/vulkanwindow.cpp
new file mode 100644
index 0000000000..9a4eaf1901
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/vulkanwindow.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "vulkanwindow.h"
+#include "renderer.h"
+#include <QMouseEvent>
+#include <QKeyEvent>
+
+VulkanWindow::VulkanWindow(bool dbg)
+ : m_debug(dbg)
+{
+}
+
+QVulkanWindowRenderer *VulkanWindow::createRenderer()
+{
+ m_renderer = new Renderer(this, 128);
+ return m_renderer;
+}
+
+void VulkanWindow::addNew()
+{
+ m_renderer->addNew();
+}
+
+void VulkanWindow::togglePaused()
+{
+ m_renderer->setAnimating(!m_renderer->animating());
+}
+
+void VulkanWindow::meshSwitched(bool enable)
+{
+ m_renderer->setUseLogo(enable);
+}
+
+void VulkanWindow::mousePressEvent(QMouseEvent *e)
+{
+ m_pressed = true;
+ m_lastPos = e->pos();
+}
+
+void VulkanWindow::mouseReleaseEvent(QMouseEvent *)
+{
+ m_pressed = false;
+}
+
+void VulkanWindow::mouseMoveEvent(QMouseEvent *e)
+{
+ if (!m_pressed)
+ return;
+
+ int dx = e->pos().x() - m_lastPos.x();
+ int dy = e->pos().y() - m_lastPos.y();
+
+ if (dy)
+ m_renderer->pitch(dy / 10.0f);
+
+ if (dx)
+ m_renderer->yaw(dx / 10.0f);
+
+ m_lastPos = e->pos();
+}
+
+void VulkanWindow::keyPressEvent(QKeyEvent *e)
+{
+ const float amount = e->modifiers().testFlag(Qt::ShiftModifier) ? 1.0f : 0.1f;
+ switch (e->key()) {
+ case Qt::Key_W:
+ m_renderer->walk(amount);
+ break;
+ case Qt::Key_S:
+ m_renderer->walk(-amount);
+ break;
+ case Qt::Key_A:
+ m_renderer->strafe(-amount);
+ break;
+ case Qt::Key_D:
+ m_renderer->strafe(amount);
+ break;
+ default:
+ break;
+ }
+}
+
+int VulkanWindow::instanceCount() const
+{
+ return m_renderer->instanceCount();
+}
diff --git a/examples/vulkan/hellovulkancubes/vulkanwindow.h b/examples/vulkan/hellovulkancubes/vulkanwindow.h
new file mode 100644
index 0000000000..d085c0bde7
--- /dev/null
+++ b/examples/vulkan/hellovulkancubes/vulkanwindow.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VULKANWINDOW_H
+#define VULKANWINDOW_H
+
+#include <QVulkanWindow>
+
+class Renderer;
+
+class VulkanWindow : public QVulkanWindow
+{
+public:
+ VulkanWindow(bool dbg);
+
+ QVulkanWindowRenderer *createRenderer() override;
+
+ bool isDebugEnabled() const { return m_debug; }
+ int instanceCount() const;
+
+public slots:
+ void addNew();
+ void togglePaused();
+ void meshSwitched(bool enable);
+
+private:
+ void mousePressEvent(QMouseEvent *) override;
+ void mouseReleaseEvent(QMouseEvent *) override;
+ void mouseMoveEvent(QMouseEvent *) override;
+ void keyPressEvent(QKeyEvent *) override;
+
+ bool m_debug;
+ Renderer *m_renderer;
+ bool m_pressed = false;
+ QPoint m_lastPos;
+};
+
+#endif
diff --git a/examples/vulkan/hellovulkantexture/hellovulkantexture.cpp b/examples/vulkan/hellovulkantexture/hellovulkantexture.cpp
new file mode 100644
index 0000000000..543eb7884a
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/hellovulkantexture.cpp
@@ -0,0 +1,829 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "hellovulkantexture.h"
+#include <QVulkanFunctions>
+#include <QCoreApplication>
+#include <QFile>
+
+// Use a triangle strip to get a quad.
+//
+// Note that the vertex data and the projection matrix assume OpenGL. With
+// Vulkan Y is negated in clip space and the near/far plane is at 0/1 instead
+// of -1/1. These will be corrected for by an extra transformation when
+// calculating the modelview-projection matrix.
+static float vertexData[] = {
+ // x, y, z, u, v
+ -1, -1, 0, 0, 1,
+ -1, 1, 0, 0, 0,
+ 1, -1, 0, 1, 1,
+ 1, 1, 0, 1, 0
+};
+
+static const int UNIFORM_DATA_SIZE = 16 * sizeof(float);
+
+static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)
+{
+ return (v + byteAlign - 1) & ~(byteAlign - 1);
+}
+
+QVulkanWindowRenderer *VulkanWindow::createRenderer()
+{
+ return new VulkanRenderer(this);
+}
+
+VulkanRenderer::VulkanRenderer(QVulkanWindow *w)
+ : m_window(w)
+{
+}
+
+VkShaderModule VulkanRenderer::createShader(const QString &name)
+{
+ QFile file(name);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning("Failed to read shader %s", qPrintable(name));
+ return VK_NULL_HANDLE;
+ }
+ QByteArray blob = file.readAll();
+ file.close();
+
+ VkShaderModuleCreateInfo shaderInfo;
+ memset(&shaderInfo, 0, sizeof(shaderInfo));
+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shaderInfo.codeSize = blob.size();
+ shaderInfo.pCode = reinterpret_cast<const uint32_t *>(blob.constData());
+ VkShaderModule shaderModule;
+ VkResult err = m_devFuncs->vkCreateShaderModule(m_window->device(), &shaderInfo, nullptr, &shaderModule);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create shader module: %d", err);
+ return VK_NULL_HANDLE;
+ }
+
+ return shaderModule;
+}
+
+bool VulkanRenderer::createTexture(const QString &name)
+{
+ QImage img(name);
+ if (img.isNull()) {
+ qWarning("Failed to load image %s", qPrintable(name));
+ return false;
+ }
+
+ // Convert to byte ordered RGBA8. Use premultiplied alpha, see pColorBlendState in the pipeline.
+ img = img.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
+
+ QVulkanFunctions *f = m_window->vulkanInstance()->functions();
+ VkDevice dev = m_window->device();
+
+ const bool srgb = QCoreApplication::arguments().contains(QStringLiteral("--srgb"));
+ if (srgb)
+ qDebug("sRGB swapchain was requested, making texture sRGB too");
+
+ m_texFormat = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
+
+ // Now we can either map and copy the image data directly, or have to go
+ // through a staging buffer to copy and convert into the internal optimal
+ // tiling format.
+ VkFormatProperties props;
+ f->vkGetPhysicalDeviceFormatProperties(m_window->physicalDevice(), m_texFormat, &props);
+ const bool canSampleLinear = (props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
+ const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
+ if (!canSampleLinear && !canSampleOptimal) {
+ qWarning("Neither linear nor optimal image sampling is supported for RGBA8");
+ return false;
+ }
+
+ static bool alwaysStage = qEnvironmentVariableIntValue("QT_VK_FORCE_STAGE_TEX");
+
+ if (canSampleLinear && !alwaysStage) {
+ if (!createTextureImage(img.size(), &m_texImage, &m_texMem,
+ VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT,
+ m_window->hostVisibleMemoryIndex()))
+ return false;
+
+ if (!writeLinearImage(img, m_texImage, m_texMem))
+ return false;
+
+ m_texLayoutPending = true;
+ } else {
+ if (!createTextureImage(img.size(), &m_texStaging, &m_texStagingMem,
+ VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
+ m_window->hostVisibleMemoryIndex()))
+ return false;
+
+ if (!createTextureImage(img.size(), &m_texImage, &m_texMem,
+ VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+ m_window->deviceLocalMemoryIndex()))
+ return false;
+
+ if (!writeLinearImage(img, m_texStaging, m_texStagingMem))
+ return false;
+
+ m_texStagingPending = true;
+ }
+
+ VkImageViewCreateInfo viewInfo;
+ memset(&viewInfo, 0, sizeof(viewInfo));
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.image = m_texImage;
+ viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = m_texFormat;
+ viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
+ viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
+ viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
+ viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
+ viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.subresourceRange.levelCount = viewInfo.subresourceRange.layerCount = 1;
+
+ VkResult err = m_devFuncs->vkCreateImageView(dev, &viewInfo, nullptr, &m_texView);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create image view for texture: %d", err);
+ return false;
+ }
+
+ m_texSize = img.size();
+
+ return true;
+}
+
+bool VulkanRenderer::createTextureImage(const QSize &size, VkImage *image, VkDeviceMemory *mem,
+ VkImageTiling tiling, VkImageUsageFlags usage, uint32_t memIndex)
+{
+ VkDevice dev = m_window->device();
+
+ VkImageCreateInfo imageInfo;
+ memset(&imageInfo, 0, sizeof(imageInfo));
+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ imageInfo.imageType = VK_IMAGE_TYPE_2D;
+ imageInfo.format = m_texFormat;
+ imageInfo.extent.width = size.width();
+ imageInfo.extent.height = size.height();
+ imageInfo.extent.depth = 1;
+ imageInfo.mipLevels = 1;
+ imageInfo.arrayLayers = 1;
+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.tiling = tiling;
+ imageInfo.usage = usage;
+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+
+ VkResult err = m_devFuncs->vkCreateImage(dev, &imageInfo, nullptr, image);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create linear image for texture: %d", err);
+ return false;
+ }
+
+ VkMemoryRequirements memReq;
+ m_devFuncs->vkGetImageMemoryRequirements(dev, *image, &memReq);
+
+ VkMemoryAllocateInfo allocInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ nullptr,
+ memReq.size,
+ memIndex
+ };
+ qDebug("allocating %u bytes for texture image", uint32_t(memReq.size));
+
+ err = m_devFuncs->vkAllocateMemory(dev, &allocInfo, nullptr, mem);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to allocate memory for linear image: %d", err);
+ return false;
+ }
+
+ err = m_devFuncs->vkBindImageMemory(dev, *image, *mem, 0);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to bind linear image memory: %d", err);
+ return false;
+ }
+
+ return true;
+}
+
+bool VulkanRenderer::writeLinearImage(const QImage &img, VkImage image, VkDeviceMemory memory)
+{
+ VkDevice dev = m_window->device();
+
+ VkImageSubresource subres = {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, // mip level
+ 0
+ };
+ VkSubresourceLayout layout;
+ m_devFuncs->vkGetImageSubresourceLayout(dev, image, &subres, &layout);
+
+ uchar *p;
+ VkResult err = m_devFuncs->vkMapMemory(dev, memory, layout.offset, layout.size, 0, reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to map memory for linear image: %d", err);
+ return false;
+ }
+
+ for (int y = 0; y < img.height(); ++y) {
+ const uchar *line = img.constScanLine(y);
+ memcpy(p, line, img.width() * 4);
+ p += layout.rowPitch;
+ }
+
+ m_devFuncs->vkUnmapMemory(dev, memory);
+ return true;
+}
+
+void VulkanRenderer::ensureTexture()
+{
+ if (!m_texLayoutPending && !m_texStagingPending)
+ return;
+
+ Q_ASSERT(m_texLayoutPending != m_texStagingPending);
+ VkCommandBuffer cb = m_window->currentCommandBuffer();
+
+ VkImageMemoryBarrier barrier;
+ memset(&barrier, 0, sizeof(barrier));
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier.subresourceRange.levelCount = barrier.subresourceRange.layerCount = 1;
+
+ if (m_texLayoutPending) {
+ m_texLayoutPending = false;
+
+ barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+ barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ barrier.srcAccessMask = 0; // VK_ACCESS_HOST_WRITE_BIT ### no, keep validation layer happy (??)
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ barrier.image = m_texImage;
+
+ m_devFuncs->vkCmdPipelineBarrier(cb,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ 0, 0, nullptr, 0, nullptr,
+ 1, &barrier);
+ } else {
+ m_texStagingPending = false;
+
+ barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+ barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ barrier.image = m_texStaging;
+ m_devFuncs->vkCmdPipelineBarrier(cb,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0, 0, nullptr, 0, nullptr,
+ 1, &barrier);
+
+ barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+ barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ barrier.image = m_texImage;
+ m_devFuncs->vkCmdPipelineBarrier(cb,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0, 0, nullptr, 0, nullptr,
+ 1, &barrier);
+
+ VkImageCopy copyInfo;
+ memset(&copyInfo, 0, sizeof(copyInfo));
+ copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ copyInfo.srcSubresource.layerCount = 1;
+ copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ copyInfo.dstSubresource.layerCount = 1;
+ copyInfo.extent.width = m_texSize.width();
+ copyInfo.extent.height = m_texSize.height();
+ copyInfo.extent.depth = 1;
+ m_devFuncs->vkCmdCopyImage(cb, m_texStaging, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ m_texImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyInfo);
+
+ barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ barrier.image = m_texImage;
+ m_devFuncs->vkCmdPipelineBarrier(cb,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ 0, 0, nullptr, 0, nullptr,
+ 1, &barrier);
+ }
+}
+
+void VulkanRenderer::initResources()
+{
+ qDebug("initResources");
+
+ VkDevice dev = m_window->device();
+ m_devFuncs = m_window->vulkanInstance()->deviceFunctions(dev);
+
+ // The setup is similar to hellovulkantriangle. The difference is the
+ // presence of a second vertex attribute (texcoord), a sampler, and that we
+ // need blending.
+
+ const int concurrentFrameCount = m_window->concurrentFrameCount();
+ const VkPhysicalDeviceLimits *pdevLimits = &m_window->physicalDeviceProperties()->limits;
+ const VkDeviceSize uniAlign = pdevLimits->minUniformBufferOffsetAlignment;
+ qDebug("uniform buffer offset alignment is %u", (uint) uniAlign);
+ VkBufferCreateInfo bufInfo;
+ memset(&bufInfo, 0, sizeof(bufInfo));
+ bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ // Our internal layout is vertex, uniform, uniform, ... with each uniform buffer start offset aligned to uniAlign.
+ const VkDeviceSize vertexAllocSize = aligned(sizeof(vertexData), uniAlign);
+ const VkDeviceSize uniformAllocSize = aligned(UNIFORM_DATA_SIZE, uniAlign);
+ bufInfo.size = vertexAllocSize + concurrentFrameCount * uniformAllocSize;
+ bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+
+ VkResult err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_buf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create buffer: %d", err);
+
+ VkMemoryRequirements memReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(dev, m_buf, &memReq);
+
+ VkMemoryAllocateInfo memAllocInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ nullptr,
+ memReq.size,
+ m_window->hostVisibleMemoryIndex()
+ };
+
+ err = m_devFuncs->vkAllocateMemory(dev, &memAllocInfo, nullptr, &m_bufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate memory: %d", err);
+
+ err = m_devFuncs->vkBindBufferMemory(dev, m_buf, m_bufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind buffer memory: %d", err);
+
+ quint8 *p;
+ err = m_devFuncs->vkMapMemory(dev, m_bufMem, 0, memReq.size, 0, reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS)
+ qFatal("Failed to map memory: %d", err);
+ memcpy(p, vertexData, sizeof(vertexData));
+ QMatrix4x4 ident;
+ memset(m_uniformBufInfo, 0, sizeof(m_uniformBufInfo));
+ for (int i = 0; i < concurrentFrameCount; ++i) {
+ const VkDeviceSize offset = vertexAllocSize + i * uniformAllocSize;
+ memcpy(p + offset, ident.constData(), 16 * sizeof(float));
+ m_uniformBufInfo[i].buffer = m_buf;
+ m_uniformBufInfo[i].offset = offset;
+ m_uniformBufInfo[i].range = uniformAllocSize;
+ }
+ m_devFuncs->vkUnmapMemory(dev, m_bufMem);
+
+ VkVertexInputBindingDescription vertexBindingDesc = {
+ 0, // binding
+ 5 * sizeof(float),
+ VK_VERTEX_INPUT_RATE_VERTEX
+ };
+ VkVertexInputAttributeDescription vertexAttrDesc[] = {
+ { // position
+ 0, // location
+ 0, // binding
+ VK_FORMAT_R32G32B32_SFLOAT,
+ 0
+ },
+ { // texcoord
+ 1,
+ 0,
+ VK_FORMAT_R32G32_SFLOAT,
+ 3 * sizeof(float)
+ }
+ };
+
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo;
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.pNext = nullptr;
+ vertexInputInfo.flags = 0;
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDesc;
+ vertexInputInfo.vertexAttributeDescriptionCount = 2;
+ vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc;
+
+ // Sampler.
+ VkSamplerCreateInfo samplerInfo;
+ memset(&samplerInfo, 0, sizeof(samplerInfo));
+ samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ samplerInfo.magFilter = VK_FILTER_NEAREST;
+ samplerInfo.minFilter = VK_FILTER_NEAREST;
+ samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.maxAnisotropy = 1.0f;
+ err = m_devFuncs->vkCreateSampler(dev, &samplerInfo, nullptr, &m_sampler);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create sampler: %d", err);
+
+ // Texture.
+ if (!createTexture(QStringLiteral(":/qt256.png")))
+ qFatal("Failed to create texture");
+
+ // Set up descriptor set and its layout.
+ VkDescriptorPoolSize descPoolSizes[2] = {
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uint32_t(concurrentFrameCount) },
+ { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32_t(concurrentFrameCount) }
+ };
+ VkDescriptorPoolCreateInfo descPoolInfo;
+ memset(&descPoolInfo, 0, sizeof(descPoolInfo));
+ descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ descPoolInfo.maxSets = concurrentFrameCount;
+ descPoolInfo.poolSizeCount = 2;
+ descPoolInfo.pPoolSizes = descPoolSizes;
+ err = m_devFuncs->vkCreateDescriptorPool(dev, &descPoolInfo, nullptr, &m_descPool);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor pool: %d", err);
+
+ VkDescriptorSetLayoutBinding layoutBinding[2] =
+ {
+ {
+ 0, // binding
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1, // descriptorCount
+ VK_SHADER_STAGE_VERTEX_BIT,
+ nullptr
+ },
+ {
+ 1, // binding
+ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ 1, // descriptorCount
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ nullptr
+ }
+ };
+ VkDescriptorSetLayoutCreateInfo descLayoutInfo = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ nullptr,
+ 0,
+ 2, // bindingCount
+ layoutBinding
+ };
+ err = m_devFuncs->vkCreateDescriptorSetLayout(dev, &descLayoutInfo, nullptr, &m_descSetLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor set layout: %d", err);
+
+ for (int i = 0; i < concurrentFrameCount; ++i) {
+ VkDescriptorSetAllocateInfo descSetAllocInfo = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ nullptr,
+ m_descPool,
+ 1,
+ &m_descSetLayout
+ };
+ err = m_devFuncs->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_descSet[i]);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate descriptor set: %d", err);
+
+ VkWriteDescriptorSet descWrite[2];
+ memset(descWrite, 0, sizeof(descWrite));
+ descWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descWrite[0].dstSet = m_descSet[i];
+ descWrite[0].dstBinding = 0;
+ descWrite[0].descriptorCount = 1;
+ descWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descWrite[0].pBufferInfo = &m_uniformBufInfo[i];
+
+ VkDescriptorImageInfo descImageInfo = {
+ m_sampler,
+ m_texView,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+ };
+
+ descWrite[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descWrite[1].dstSet = m_descSet[i];
+ descWrite[1].dstBinding = 1;
+ descWrite[1].descriptorCount = 1;
+ descWrite[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descWrite[1].pImageInfo = &descImageInfo;
+
+ m_devFuncs->vkUpdateDescriptorSets(dev, 2, descWrite, 0, nullptr);
+ }
+
+ // Pipeline cache
+ VkPipelineCacheCreateInfo pipelineCacheInfo;
+ memset(&pipelineCacheInfo, 0, sizeof(pipelineCacheInfo));
+ pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+ err = m_devFuncs->vkCreatePipelineCache(dev, &pipelineCacheInfo, nullptr, &m_pipelineCache);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline cache: %d", err);
+
+ // Pipeline layout
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo;
+ memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo));
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &m_descSetLayout;
+ err = m_devFuncs->vkCreatePipelineLayout(dev, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline layout: %d", err);
+
+ // Shaders
+ VkShaderModule vertShaderModule = createShader(QStringLiteral(":/texture_vert.spv"));
+ VkShaderModule fragShaderModule = createShader(QStringLiteral(":/texture_frag.spv"));
+
+ // Graphics pipeline
+ VkGraphicsPipelineCreateInfo pipelineInfo;
+ memset(&pipelineInfo, 0, sizeof(pipelineInfo));
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+
+ VkPipelineShaderStageCreateInfo shaderStages[2] = {
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ vertShaderModule,
+ "main",
+ nullptr
+ },
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fragShaderModule,
+ "main",
+ nullptr
+ }
+ };
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+
+ VkPipelineInputAssemblyStateCreateInfo ia;
+ memset(&ia, 0, sizeof(ia));
+ ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ pipelineInfo.pInputAssemblyState = &ia;
+
+ // The viewport and scissor will be set dynamically via vkCmdSetViewport/Scissor.
+ // This way the pipeline does not need to be touched when resizing the window.
+ VkPipelineViewportStateCreateInfo vp;
+ memset(&vp, 0, sizeof(vp));
+ vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vp.viewportCount = 1;
+ vp.scissorCount = 1;
+ pipelineInfo.pViewportState = &vp;
+
+ VkPipelineRasterizationStateCreateInfo rs;
+ memset(&rs, 0, sizeof(rs));
+ rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rs.polygonMode = VK_POLYGON_MODE_FILL;
+ rs.cullMode = VK_CULL_MODE_BACK_BIT;
+ rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ rs.lineWidth = 1.0f;
+ pipelineInfo.pRasterizationState = &rs;
+
+ VkPipelineMultisampleStateCreateInfo ms;
+ memset(&ms, 0, sizeof(ms));
+ ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ pipelineInfo.pMultisampleState = &ms;
+
+ VkPipelineDepthStencilStateCreateInfo ds;
+ memset(&ds, 0, sizeof(ds));
+ ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ ds.depthTestEnable = VK_TRUE;
+ ds.depthWriteEnable = VK_TRUE;
+ ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
+ pipelineInfo.pDepthStencilState = &ds;
+
+ VkPipelineColorBlendStateCreateInfo cb;
+ memset(&cb, 0, sizeof(cb));
+ cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ // assume pre-multiplied alpha, blend, write out all of rgba
+ VkPipelineColorBlendAttachmentState att;
+ memset(&att, 0, sizeof(att));
+ att.colorWriteMask = 0xF;
+ att.blendEnable = VK_TRUE;
+ att.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ att.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ att.colorBlendOp = VK_BLEND_OP_ADD;
+ att.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ att.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ att.alphaBlendOp = VK_BLEND_OP_ADD;
+ cb.attachmentCount = 1;
+ cb.pAttachments = &att;
+ pipelineInfo.pColorBlendState = &cb;
+
+ VkDynamicState dynEnable[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+ VkPipelineDynamicStateCreateInfo dyn;
+ memset(&dyn, 0, sizeof(dyn));
+ dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dyn.dynamicStateCount = sizeof(dynEnable) / sizeof(VkDynamicState);
+ dyn.pDynamicStates = dynEnable;
+ pipelineInfo.pDynamicState = &dyn;
+
+ pipelineInfo.layout = m_pipelineLayout;
+ pipelineInfo.renderPass = m_window->defaultRenderPass();
+
+ err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create graphics pipeline: %d", err);
+
+ if (vertShaderModule)
+ m_devFuncs->vkDestroyShaderModule(dev, vertShaderModule, nullptr);
+ if (fragShaderModule)
+ m_devFuncs->vkDestroyShaderModule(dev, fragShaderModule, nullptr);
+}
+
+void VulkanRenderer::initSwapChainResources()
+{
+ qDebug("initSwapChainResources");
+
+ // Projection matrix
+ m_proj = m_window->clipCorrectionMatrix(); // adjust for Vulkan-OpenGL clip space differences
+ const QSize sz = m_window->swapChainImageSize();
+ m_proj.perspective(45.0f, sz.width() / (float) sz.height(), 0.01f, 100.0f);
+ m_proj.translate(0, 0, -4);
+}
+
+void VulkanRenderer::releaseSwapChainResources()
+{
+ qDebug("releaseSwapChainResources");
+}
+
+void VulkanRenderer::releaseResources()
+{
+ qDebug("releaseResources");
+
+ VkDevice dev = m_window->device();
+
+ if (m_sampler) {
+ m_devFuncs->vkDestroySampler(dev, m_sampler, nullptr);
+ m_sampler = VK_NULL_HANDLE;
+ }
+
+ if (m_texStaging) {
+ m_devFuncs->vkDestroyImage(dev, m_texStaging, nullptr);
+ m_texStaging = VK_NULL_HANDLE;
+ }
+
+ if (m_texStagingMem) {
+ m_devFuncs->vkFreeMemory(dev, m_texStagingMem, nullptr);
+ m_texStagingMem = VK_NULL_HANDLE;
+ }
+
+ if (m_texView) {
+ m_devFuncs->vkDestroyImageView(dev, m_texView, nullptr);
+ m_texView = VK_NULL_HANDLE;
+ }
+
+ if (m_texImage) {
+ m_devFuncs->vkDestroyImage(dev, m_texImage, nullptr);
+ m_texImage = VK_NULL_HANDLE;
+ }
+
+ if (m_texMem) {
+ m_devFuncs->vkFreeMemory(dev, m_texMem, nullptr);
+ m_texMem = VK_NULL_HANDLE;
+ }
+
+ if (m_pipeline) {
+ m_devFuncs->vkDestroyPipeline(dev, m_pipeline, nullptr);
+ m_pipeline = VK_NULL_HANDLE;
+ }
+
+ if (m_pipelineLayout) {
+ m_devFuncs->vkDestroyPipelineLayout(dev, m_pipelineLayout, nullptr);
+ m_pipelineLayout = VK_NULL_HANDLE;
+ }
+
+ if (m_pipelineCache) {
+ m_devFuncs->vkDestroyPipelineCache(dev, m_pipelineCache, nullptr);
+ m_pipelineCache = VK_NULL_HANDLE;
+ }
+
+ if (m_descSetLayout) {
+ m_devFuncs->vkDestroyDescriptorSetLayout(dev, m_descSetLayout, nullptr);
+ m_descSetLayout = VK_NULL_HANDLE;
+ }
+
+ if (m_descPool) {
+ m_devFuncs->vkDestroyDescriptorPool(dev, m_descPool, nullptr);
+ m_descPool = VK_NULL_HANDLE;
+ }
+
+ if (m_buf) {
+ m_devFuncs->vkDestroyBuffer(dev, m_buf, nullptr);
+ m_buf = VK_NULL_HANDLE;
+ }
+
+ if (m_bufMem) {
+ m_devFuncs->vkFreeMemory(dev, m_bufMem, nullptr);
+ m_bufMem = VK_NULL_HANDLE;
+ }
+}
+
+void VulkanRenderer::startNextFrame()
+{
+ VkDevice dev = m_window->device();
+ VkCommandBuffer cb = m_window->currentCommandBuffer();
+ const QSize sz = m_window->swapChainImageSize();
+
+ // Add the necessary barriers and do the host-linear -> device-optimal copy, if not yet done.
+ ensureTexture();
+
+ VkClearColorValue clearColor = { 0, 0, 0, 1 };
+ VkClearDepthStencilValue clearDS = { 1, 0 };
+ VkClearValue clearValues[2];
+ memset(clearValues, 0, sizeof(clearValues));
+ clearValues[0].color = clearColor;
+ clearValues[1].depthStencil = clearDS;
+
+ VkRenderPassBeginInfo rpBeginInfo;
+ memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
+ rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ rpBeginInfo.renderPass = m_window->defaultRenderPass();
+ rpBeginInfo.framebuffer = m_window->currentFramebuffer();
+ rpBeginInfo.renderArea.extent.width = sz.width();
+ rpBeginInfo.renderArea.extent.height = sz.height();
+ rpBeginInfo.clearValueCount = 2;
+ rpBeginInfo.pClearValues = clearValues;
+ VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
+ m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ quint8 *p;
+ VkResult err = m_devFuncs->vkMapMemory(dev, m_bufMem, m_uniformBufInfo[m_window->currentFrame()].offset,
+ UNIFORM_DATA_SIZE, 0, reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS)
+ qFatal("Failed to map memory: %d", err);
+ QMatrix4x4 m = m_proj;
+ m.rotate(m_rotation, 0, 0, 1);
+ memcpy(p, m.constData(), 16 * sizeof(float));
+ m_devFuncs->vkUnmapMemory(dev, m_bufMem);
+
+ // Not exactly a real animation system, just advance on every frame for now.
+ m_rotation += 1.0f;
+
+ m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
+ m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1,
+ &m_descSet[m_window->currentFrame()], 0, nullptr);
+ VkDeviceSize vbOffset = 0;
+ m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_buf, &vbOffset);
+
+ VkViewport viewport;
+ viewport.x = viewport.y = 0;
+ viewport.width = sz.width();
+ viewport.height = sz.height();
+ viewport.minDepth = 0;
+ viewport.maxDepth = 1;
+ m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport);
+
+ VkRect2D scissor;
+ scissor.offset.x = scissor.offset.y = 0;
+ scissor.extent.width = viewport.width;
+ scissor.extent.height = viewport.height;
+ m_devFuncs->vkCmdSetScissor(cb, 0, 1, &scissor);
+
+ m_devFuncs->vkCmdDraw(cb, 4, 1, 0, 0);
+
+ m_devFuncs->vkCmdEndRenderPass(cmdBuf);
+
+ m_window->frameReady();
+ m_window->requestUpdate(); // render continuously, throttled by the presentation rate
+}
diff --git a/examples/vulkan/hellovulkantexture/hellovulkantexture.h b/examples/vulkan/hellovulkantexture/hellovulkantexture.h
new file mode 100644
index 0000000000..a8c96d1987
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/hellovulkantexture.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QVulkanWindow>
+#include <QImage>
+
+class VulkanRenderer : public QVulkanWindowRenderer
+{
+public:
+ VulkanRenderer(QVulkanWindow *w);
+
+ void initResources() override;
+ void initSwapChainResources() override;
+ void releaseSwapChainResources() override;
+ void releaseResources() override;
+
+ void startNextFrame() override;
+
+private:
+ VkShaderModule createShader(const QString &name);
+ bool createTexture(const QString &name);
+ bool createTextureImage(const QSize &size, VkImage *image, VkDeviceMemory *mem,
+ VkImageTiling tiling, VkImageUsageFlags usage, uint32_t memIndex);
+ bool writeLinearImage(const QImage &img, VkImage image, VkDeviceMemory memory);
+ void ensureTexture();
+
+ QVulkanWindow *m_window;
+ QVulkanDeviceFunctions *m_devFuncs;
+
+ VkDeviceMemory m_bufMem = VK_NULL_HANDLE;
+ VkBuffer m_buf = VK_NULL_HANDLE;
+ VkDescriptorBufferInfo m_uniformBufInfo[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT];
+
+ VkDescriptorPool m_descPool = VK_NULL_HANDLE;
+ VkDescriptorSetLayout m_descSetLayout = VK_NULL_HANDLE;
+ VkDescriptorSet m_descSet[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT];
+
+ VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
+ VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
+ VkPipeline m_pipeline = VK_NULL_HANDLE;
+
+ VkSampler m_sampler = VK_NULL_HANDLE;
+ VkImage m_texImage = VK_NULL_HANDLE;
+ VkDeviceMemory m_texMem = VK_NULL_HANDLE;
+ bool m_texLayoutPending = false;
+ VkImageView m_texView = VK_NULL_HANDLE;
+ VkImage m_texStaging = VK_NULL_HANDLE;
+ VkDeviceMemory m_texStagingMem = VK_NULL_HANDLE;
+ bool m_texStagingPending = false;
+ QSize m_texSize;
+ VkFormat m_texFormat;
+
+ QMatrix4x4 m_proj;
+ float m_rotation = 0.0f;
+};
+
+class VulkanWindow : public QVulkanWindow
+{
+public:
+ QVulkanWindowRenderer *createRenderer() override;
+};
diff --git a/examples/vulkan/hellovulkantexture/hellovulkantexture.pro b/examples/vulkan/hellovulkantexture/hellovulkantexture.pro
new file mode 100644
index 0000000000..59bfcda715
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/hellovulkantexture.pro
@@ -0,0 +1,7 @@
+HEADERS += hellovulkantexture.h
+SOURCES += hellovulkantexture.cpp main.cpp
+RESOURCES += hellovulkantexture.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkantexture
+INSTALLS += target
diff --git a/examples/vulkan/hellovulkantexture/hellovulkantexture.qrc b/examples/vulkan/hellovulkantexture/hellovulkantexture.qrc
new file mode 100644
index 0000000000..04e7cda859
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/hellovulkantexture.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>texture_vert.spv</file>
+ <file>texture_frag.spv</file>
+ <file>qt256.png</file>
+</qresource>
+</RCC>
diff --git a/examples/vulkan/hellovulkantexture/main.cpp b/examples/vulkan/hellovulkantexture/main.cpp
new file mode 100644
index 0000000000..1144463b70
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/main.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QVulkanInstance>
+#include <QLoggingCategory>
+#include "hellovulkantexture.h"
+
+Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
+
+ QVulkanInstance inst;
+
+#ifndef Q_OS_ANDROID
+ inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation");
+#else
+ inst.setLayers(QByteArrayList()
+ << "VK_LAYER_GOOGLE_threading"
+ << "VK_LAYER_LUNARG_parameter_validation"
+ << "VK_LAYER_LUNARG_object_tracker"
+ << "VK_LAYER_LUNARG_core_validation"
+ << "VK_LAYER_LUNARG_image"
+ << "VK_LAYER_LUNARG_swapchain"
+ << "VK_LAYER_GOOGLE_unique_objects");
+#endif
+
+ if (!inst.create())
+ qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
+
+ VulkanWindow w;
+ w.setVulkanInstance(&inst);
+ if (QCoreApplication::arguments().contains(QStringLiteral("--srgb")))
+ w.setPreferredColorFormats(QVector<VkFormat>() << VK_FORMAT_B8G8R8A8_SRGB);
+
+ w.resize(1024, 768);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/vulkan/hellovulkantexture/qt256.png b/examples/vulkan/hellovulkantexture/qt256.png
new file mode 100644
index 0000000000..30c621c9c6
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/qt256.png
Binary files differ
diff --git a/examples/vulkan/hellovulkantexture/texture.frag b/examples/vulkan/hellovulkantexture/texture.frag
new file mode 100644
index 0000000000..e6021fe905
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/texture.frag
@@ -0,0 +1,12 @@
+#version 440
+
+layout(location = 0) in vec2 v_texcoord;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D tex;
+
+void main()
+{
+ fragColor = texture(tex, v_texcoord);
+}
diff --git a/examples/vulkan/hellovulkantexture/texture.vert b/examples/vulkan/hellovulkantexture/texture.vert
new file mode 100644
index 0000000000..de486cb772
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/texture.vert
@@ -0,0 +1,18 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec2 texcoord;
+
+layout(location = 0) out vec2 v_texcoord;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+} ubuf;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main()
+{
+ v_texcoord = texcoord;
+ gl_Position = ubuf.mvp * position;
+}
diff --git a/examples/vulkan/hellovulkantexture/texture_frag.spv b/examples/vulkan/hellovulkantexture/texture_frag.spv
new file mode 100644
index 0000000000..7521ef6eef
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/texture_frag.spv
Binary files differ
diff --git a/examples/vulkan/hellovulkantexture/texture_vert.spv b/examples/vulkan/hellovulkantexture/texture_vert.spv
new file mode 100644
index 0000000000..6292c0de31
--- /dev/null
+++ b/examples/vulkan/hellovulkantexture/texture_vert.spv
Binary files differ
diff --git a/examples/vulkan/hellovulkantriangle/hellovulkantriangle.pro b/examples/vulkan/hellovulkantriangle/hellovulkantriangle.pro
new file mode 100644
index 0000000000..db016da3ac
--- /dev/null
+++ b/examples/vulkan/hellovulkantriangle/hellovulkantriangle.pro
@@ -0,0 +1,12 @@
+HEADERS += \
+ ../shared/trianglerenderer.h
+
+SOURCES += \
+ main.cpp \
+ ../shared/trianglerenderer.cpp
+
+RESOURCES += hellovulkantriangle.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkantriangle
+INSTALLS += target
diff --git a/examples/vulkan/hellovulkantriangle/hellovulkantriangle.qrc b/examples/vulkan/hellovulkantriangle/hellovulkantriangle.qrc
new file mode 100644
index 0000000000..489fc7295a
--- /dev/null
+++ b/examples/vulkan/hellovulkantriangle/hellovulkantriangle.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file alias="color_vert.spv">../shared/color_vert.spv</file>
+ <file alias="color_frag.spv">../shared/color_frag.spv</file>
+</qresource>
+</RCC>
diff --git a/examples/vulkan/hellovulkantriangle/main.cpp b/examples/vulkan/hellovulkantriangle/main.cpp
new file mode 100644
index 0000000000..d3eef2e14a
--- /dev/null
+++ b/examples/vulkan/hellovulkantriangle/main.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QVulkanInstance>
+#include <QLoggingCategory>
+#include "../shared/trianglerenderer.h"
+
+Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
+
+class VulkanWindow : public QVulkanWindow
+{
+public:
+ QVulkanWindowRenderer *createRenderer() override;
+};
+
+QVulkanWindowRenderer *VulkanWindow::createRenderer()
+{
+ return new TriangleRenderer(this, true); // try MSAA, when available
+}
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
+
+ QVulkanInstance inst;
+
+#ifndef Q_OS_ANDROID
+ inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation");
+#else
+ inst.setLayers(QByteArrayList()
+ << "VK_LAYER_GOOGLE_threading"
+ << "VK_LAYER_LUNARG_parameter_validation"
+ << "VK_LAYER_LUNARG_object_tracker"
+ << "VK_LAYER_LUNARG_core_validation"
+ << "VK_LAYER_LUNARG_image"
+ << "VK_LAYER_LUNARG_swapchain"
+ << "VK_LAYER_GOOGLE_unique_objects");
+#endif
+
+ if (!inst.create())
+ qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
+
+ VulkanWindow w;
+ w.setVulkanInstance(&inst);
+
+ w.resize(1024, 768);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/vulkan/hellovulkanwidget/hellovulkanwidget.cpp b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.cpp
new file mode 100644
index 0000000000..81daa9bb96
--- /dev/null
+++ b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "hellovulkanwidget.h"
+#include <QVulkanFunctions>
+#include <QApplication>
+#include <QVBoxLayout>
+#include <QPlainTextEdit>
+#include <QPushButton>
+#include <QLCDNumber>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QTabWidget>
+
+MainWindow::MainWindow(VulkanWindow *w, QPlainTextEdit *logWidget)
+ : m_window(w)
+{
+ QWidget *wrapper = QWidget::createWindowContainer(w);
+
+ m_info = new QPlainTextEdit;
+ m_info->setReadOnly(true);
+
+ m_number = new QLCDNumber(3);
+ m_number->setSegmentStyle(QLCDNumber::Filled);
+
+ QPushButton *grabButton = new QPushButton(tr("&Grab"));
+ grabButton->setFocusPolicy(Qt::NoFocus);
+
+ connect(grabButton, &QPushButton::clicked, this, &MainWindow::onGrabRequested);
+
+ QPushButton *quitButton = new QPushButton(tr("&Quit"));
+ quitButton->setFocusPolicy(Qt::NoFocus);
+
+ connect(quitButton, &QPushButton::clicked, qApp, &QCoreApplication::quit);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ m_infoTab = new QTabWidget(this);
+ m_infoTab->addTab(m_info, tr("Vulkan Info"));
+ m_infoTab->addTab(logWidget, tr("Debug Log"));
+ layout->addWidget(m_infoTab, 2);
+ layout->addWidget(m_number, 1);
+ layout->addWidget(wrapper, 5);
+ layout->addWidget(grabButton, 1);
+ layout->addWidget(quitButton, 1);
+ setLayout(layout);
+}
+
+void MainWindow::onVulkanInfoReceived(const QString &text)
+{
+ m_info->setPlainText(text);
+}
+
+void MainWindow::onFrameQueued(int colorValue)
+{
+ m_number->display(colorValue);
+}
+
+void MainWindow::onGrabRequested()
+{
+ if (!m_window->supportsGrab()) {
+ QMessageBox::warning(this, tr("Cannot grab"), tr("This swapchain does not support readbacks."));
+ return;
+ }
+
+ QImage img = m_window->grab();
+
+ // Our startNextFrame() implementation is synchronous so img is ready to be
+ // used right here.
+
+ QFileDialog fd(this);
+ fd.setAcceptMode(QFileDialog::AcceptSave);
+ fd.setDefaultSuffix("png");
+ fd.selectFile("test.png");
+ if (fd.exec() == QDialog::Accepted)
+ img.save(fd.selectedFiles().first());
+}
+
+QVulkanWindowRenderer *VulkanWindow::createRenderer()
+{
+ return new VulkanRenderer(this);
+}
+
+VulkanRenderer::VulkanRenderer(VulkanWindow *w)
+ : TriangleRenderer(w)
+{
+}
+
+void VulkanRenderer::initResources()
+{
+ TriangleRenderer::initResources();
+
+ QVulkanInstance *inst = m_window->vulkanInstance();
+ m_devFuncs = inst->deviceFunctions(m_window->device());
+
+ QString info;
+ info += QString().sprintf("Number of physical devices: %d\n", m_window->availablePhysicalDevices().count());
+
+ QVulkanFunctions *f = inst->functions();
+ VkPhysicalDeviceProperties props;
+ f->vkGetPhysicalDeviceProperties(m_window->physicalDevice(), &props);
+ info += QString().sprintf("Active physical device name: '%s' version %d.%d.%d\nAPI version %d.%d.%d\n",
+ props.deviceName,
+ VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion),
+ VK_VERSION_PATCH(props.driverVersion),
+ VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion),
+ VK_VERSION_PATCH(props.apiVersion));
+
+ info += QStringLiteral("Supported instance layers:\n");
+ for (const QVulkanLayer &layer : inst->supportedLayers())
+ info += QString().sprintf(" %s v%u\n", layer.name.constData(), layer.version);
+ info += QStringLiteral("Enabled instance layers:\n");
+ for (const QByteArray &layer : inst->layers())
+ info += QString().sprintf(" %s\n", layer.constData());
+
+ info += QStringLiteral("Supported instance extensions:\n");
+ for (const QVulkanExtension &ext : inst->supportedExtensions())
+ info += QString().sprintf(" %s v%u\n", ext.name.constData(), ext.version);
+ info += QStringLiteral("Enabled instance extensions:\n");
+ for (const QByteArray &ext : inst->extensions())
+ info += QString().sprintf(" %s\n", ext.constData());
+
+ info += QString().sprintf("Color format: %u\nDepth-stencil format: %u\n",
+ m_window->colorFormat(), m_window->depthStencilFormat());
+
+ info += QStringLiteral("Supported sample counts:");
+ const QVector<int> sampleCounts = m_window->supportedSampleCounts();
+ for (int count : sampleCounts)
+ info += QLatin1Char(' ') + QString::number(count);
+ info += QLatin1Char('\n');
+
+ emit static_cast<VulkanWindow *>(m_window)->vulkanInfoReceived(info);
+}
+
+void VulkanRenderer::startNextFrame()
+{
+ TriangleRenderer::startNextFrame();
+ emit static_cast<VulkanWindow *>(m_window)->frameQueued(int(m_rotation) % 360);
+}
diff --git a/examples/vulkan/hellovulkanwidget/hellovulkanwidget.h b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.h
new file mode 100644
index 0000000000..e70d331ae8
--- /dev/null
+++ b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../shared/trianglerenderer.h"
+#include <QWidget>
+
+class VulkanWindow;
+
+QT_BEGIN_NAMESPACE
+class QTabWidget;
+class QPlainTextEdit;
+class QLCDNumber;
+QT_END_NAMESPACE
+
+class MainWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(VulkanWindow *w, QPlainTextEdit *logWidget);
+
+public slots:
+ void onVulkanInfoReceived(const QString &text);
+ void onFrameQueued(int colorValue);
+ void onGrabRequested();
+
+private:
+ VulkanWindow *m_window;
+ QTabWidget *m_infoTab;
+ QPlainTextEdit *m_info;
+ QLCDNumber *m_number;
+};
+
+class VulkanRenderer : public TriangleRenderer
+{
+public:
+ VulkanRenderer(VulkanWindow *w);
+
+ void initResources() override;
+ void startNextFrame() override;
+};
+
+class VulkanWindow : public QVulkanWindow
+{
+ Q_OBJECT
+
+public:
+ QVulkanWindowRenderer *createRenderer() override;
+
+signals:
+ void vulkanInfoReceived(const QString &text);
+ void frameQueued(int colorValue);
+};
diff --git a/examples/vulkan/hellovulkanwidget/hellovulkanwidget.pro b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.pro
new file mode 100644
index 0000000000..7b87d7f210
--- /dev/null
+++ b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.pro
@@ -0,0 +1,16 @@
+QT += widgets
+
+HEADERS += \
+ hellovulkanwidget.h \
+ ../shared/trianglerenderer.h
+
+SOURCES += \
+ hellovulkanwidget.cpp \
+ main.cpp \
+ ../shared/trianglerenderer.cpp
+
+RESOURCES += hellovulkanwidget.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkanwidget
+INSTALLS += target
diff --git a/examples/vulkan/hellovulkanwidget/hellovulkanwidget.qrc b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.qrc
new file mode 100644
index 0000000000..489fc7295a
--- /dev/null
+++ b/examples/vulkan/hellovulkanwidget/hellovulkanwidget.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file alias="color_vert.spv">../shared/color_vert.spv</file>
+ <file alias="color_frag.spv">../shared/color_frag.spv</file>
+</qresource>
+</RCC>
diff --git a/examples/vulkan/hellovulkanwidget/main.cpp b/examples/vulkan/hellovulkanwidget/main.cpp
new file mode 100644
index 0000000000..5ddaf90224
--- /dev/null
+++ b/examples/vulkan/hellovulkanwidget/main.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QPlainTextEdit>
+#include <QVulkanInstance>
+#include <QLibraryInfo>
+#include <QLoggingCategory>
+#include <QPointer>
+#include "hellovulkanwidget.h"
+
+Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
+
+static QPointer<QPlainTextEdit> messageLogWidget;
+static QtMessageHandler oldMessageHandler = nullptr;
+
+static void messageHandler(QtMsgType msgType, const QMessageLogContext &logContext, const QString &text)
+{
+ if (!messageLogWidget.isNull())
+ messageLogWidget->appendPlainText(text);
+ if (oldMessageHandler)
+ oldMessageHandler(msgType, logContext, text);
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ messageLogWidget = new QPlainTextEdit(QLatin1String(QLibraryInfo::build()) + QLatin1Char('\n'));
+ messageLogWidget->setReadOnly(true);
+
+ oldMessageHandler = qInstallMessageHandler(messageHandler);
+
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
+
+ QVulkanInstance inst;
+
+#ifndef Q_OS_ANDROID
+ inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation");
+#else
+ inst.setLayers(QByteArrayList()
+ << "VK_LAYER_GOOGLE_threading"
+ << "VK_LAYER_LUNARG_parameter_validation"
+ << "VK_LAYER_LUNARG_object_tracker"
+ << "VK_LAYER_LUNARG_core_validation"
+ << "VK_LAYER_LUNARG_image"
+ << "VK_LAYER_LUNARG_swapchain"
+ << "VK_LAYER_GOOGLE_unique_objects");
+#endif
+
+ if (!inst.create())
+ qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
+
+ VulkanWindow *vulkanWindow = new VulkanWindow;
+ vulkanWindow->setVulkanInstance(&inst);
+
+ MainWindow mainWindow(vulkanWindow, messageLogWidget.data());
+ QObject::connect(vulkanWindow, &VulkanWindow::vulkanInfoReceived, &mainWindow, &MainWindow::onVulkanInfoReceived);
+ QObject::connect(vulkanWindow, &VulkanWindow::frameQueued, &mainWindow, &MainWindow::onFrameQueued);
+
+ mainWindow.resize(1024, 768);
+ mainWindow.show();
+
+ return app.exec();
+}
diff --git a/examples/vulkan/hellovulkanwindow/hellovulkanwindow.cpp b/examples/vulkan/hellovulkanwindow/hellovulkanwindow.cpp
new file mode 100644
index 0000000000..0a7d1d4174
--- /dev/null
+++ b/examples/vulkan/hellovulkanwindow/hellovulkanwindow.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "hellovulkanwindow.h"
+#include <QVulkanFunctions>
+
+//! [0]
+QVulkanWindowRenderer *VulkanWindow::createRenderer()
+{
+ return new VulkanRenderer(this);
+}
+
+VulkanRenderer::VulkanRenderer(QVulkanWindow *w)
+ : m_window(w)
+{
+}
+//! [0]
+
+//! [1]
+void VulkanRenderer::initResources()
+{
+ qDebug("initResources");
+
+ m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
+}
+//! [1]
+
+void VulkanRenderer::initSwapChainResources()
+{
+ qDebug("initSwapChainResources");
+}
+
+void VulkanRenderer::releaseSwapChainResources()
+{
+ qDebug("releaseSwapChainResources");
+}
+
+void VulkanRenderer::releaseResources()
+{
+ qDebug("releaseResources");
+}
+
+//! [2]
+void VulkanRenderer::startNextFrame()
+{
+ m_green += 0.005f;
+ if (m_green > 1.0f)
+ m_green = 0.0f;
+
+ VkClearColorValue clearColor = { 0.0f, m_green, 0.0f, 1.0f };
+ VkClearDepthStencilValue clearDS = { 1.0f, 0 };
+ VkClearValue clearValues[2];
+ memset(clearValues, 0, sizeof(clearValues));
+ clearValues[0].color = clearColor;
+ clearValues[1].depthStencil = clearDS;
+
+ VkRenderPassBeginInfo rpBeginInfo;
+ memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
+ rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ rpBeginInfo.renderPass = m_window->defaultRenderPass();
+ rpBeginInfo.framebuffer = m_window->currentFramebuffer();
+ const QSize sz = m_window->swapChainImageSize();
+ rpBeginInfo.renderArea.extent.width = sz.width();
+ rpBeginInfo.renderArea.extent.height = sz.height();
+ rpBeginInfo.clearValueCount = 2;
+ rpBeginInfo.pClearValues = clearValues;
+ VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
+ m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ // Do nothing else. We will just clear to green, changing the component on
+ // every invocation. This also helps verifying the rate to which the thread
+ // is throttled to. (The elapsed time between startNextFrame calls should
+ // typically be around 16 ms. Note that rendering is 2 frames ahead of what
+ // is displayed.)
+
+ m_devFuncs->vkCmdEndRenderPass(cmdBuf);
+
+ m_window->frameReady();
+ m_window->requestUpdate(); // render continuously, throttled by the presentation rate
+}
+//! [2]
diff --git a/examples/vulkan/hellovulkanwindow/hellovulkanwindow.h b/examples/vulkan/hellovulkanwindow/hellovulkanwindow.h
new file mode 100644
index 0000000000..5f52e402ca
--- /dev/null
+++ b/examples/vulkan/hellovulkanwindow/hellovulkanwindow.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QVulkanWindow>
+
+//! [0]
+class VulkanRenderer : public QVulkanWindowRenderer
+{
+public:
+ VulkanRenderer(QVulkanWindow *w);
+
+ void initResources() override;
+ void initSwapChainResources() override;
+ void releaseSwapChainResources() override;
+ void releaseResources() override;
+
+ void startNextFrame() override;
+
+private:
+ QVulkanWindow *m_window;
+ QVulkanDeviceFunctions *m_devFuncs;
+ float m_green = 0;
+};
+
+class VulkanWindow : public QVulkanWindow
+{
+public:
+ QVulkanWindowRenderer *createRenderer() override;
+};
+//! [0]
diff --git a/examples/vulkan/hellovulkanwindow/hellovulkanwindow.pro b/examples/vulkan/hellovulkanwindow/hellovulkanwindow.pro
new file mode 100644
index 0000000000..8f7d9494e2
--- /dev/null
+++ b/examples/vulkan/hellovulkanwindow/hellovulkanwindow.pro
@@ -0,0 +1,6 @@
+HEADERS += hellovulkanwindow.h
+SOURCES += hellovulkanwindow.cpp main.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkanwindow
+INSTALLS += target
diff --git a/examples/vulkan/hellovulkanwindow/main.cpp b/examples/vulkan/hellovulkanwindow/main.cpp
new file mode 100644
index 0000000000..313c28f9e0
--- /dev/null
+++ b/examples/vulkan/hellovulkanwindow/main.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QVulkanInstance>
+#include <QLoggingCategory>
+#include "hellovulkanwindow.h"
+
+Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
+
+//! [0]
+ QVulkanInstance inst;
+
+#ifndef Q_OS_ANDROID
+ inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation");
+#else
+ inst.setLayers(QByteArrayList()
+ << "VK_LAYER_GOOGLE_threading"
+ << "VK_LAYER_LUNARG_parameter_validation"
+ << "VK_LAYER_LUNARG_object_tracker"
+ << "VK_LAYER_LUNARG_core_validation"
+ << "VK_LAYER_LUNARG_image"
+ << "VK_LAYER_LUNARG_swapchain"
+ << "VK_LAYER_GOOGLE_unique_objects");
+#endif
+
+ if (!inst.create())
+ qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
+//! [0]
+
+//! [1]
+ VulkanWindow w;
+ w.setVulkanInstance(&inst);
+
+ w.resize(1024, 768);
+ w.show();
+//! [1]
+
+ return app.exec();
+}
diff --git a/examples/vulkan/shared/block.buf b/examples/vulkan/shared/block.buf
new file mode 100644
index 0000000000..28ec2620bd
--- /dev/null
+++ b/examples/vulkan/shared/block.buf
Binary files differ
diff --git a/examples/vulkan/shared/block.txt b/examples/vulkan/shared/block.txt
new file mode 100644
index 0000000000..a6b66b83cc
--- /dev/null
+++ b/examples/vulkan/shared/block.txt
@@ -0,0 +1,100 @@
+# Blender v2.78 (sub 0) OBJ File: ''
+# www.blender.org
+mtllib block.mtl
+o Cube_Cube.001
+v 0.450000 -0.500000 -0.450000
+v 0.450000 -0.500000 0.450000
+v -0.450000 -0.500000 0.450000
+v -0.450000 -0.500000 -0.450000
+v -0.500000 0.450000 0.450000
+v -0.500000 0.450000 -0.450000
+v -0.500000 -0.450000 -0.450000
+v -0.500000 -0.450000 0.450000
+v -0.450000 0.500000 -0.450000
+v -0.450000 0.500000 0.450000
+v 0.450000 0.500000 0.450000
+v 0.450000 0.500000 -0.450000
+v -0.450000 0.450000 -0.500000
+v 0.450000 0.450000 -0.500000
+v 0.450000 -0.450000 -0.500000
+v -0.450000 -0.450000 -0.500000
+v 0.450000 0.450000 0.500000
+v -0.450000 0.450000 0.500000
+v -0.450000 -0.450000 0.500000
+v 0.450000 -0.450000 0.500000
+v 0.500000 -0.450000 -0.450000
+v 0.500000 0.450000 -0.450000
+v 0.500000 -0.450000 0.450000
+v 0.500000 0.450000 0.450000
+vn 0.0000 -1.0000 -0.0000
+vn -1.0000 0.0000 0.0000
+vn 0.0000 1.0000 0.0000
+vn 0.0000 0.0000 -1.0000
+vn 0.0000 -0.0000 1.0000
+vn 0.5774 -0.5773 -0.5774
+vn 0.5774 0.5774 -0.5774
+vn 0.5774 -0.5774 0.5774
+vn 0.5774 0.5773 0.5774
+vn -0.5774 -0.5773 -0.5774
+vn -0.5773 0.5774 -0.5774
+vn -0.5774 -0.5774 0.5774
+vn -0.5774 0.5773 0.5774
+vn 0.7071 0.0000 -0.7071
+vn 0.7071 0.7071 0.0000
+vn 0.7071 -0.0000 0.7071
+vn 0.7071 -0.7071 -0.0000
+vn 0.0000 0.7071 0.7071
+vn -0.7071 -0.0000 0.7071
+vn 0.0000 -0.7071 0.7071
+vn -0.7071 0.7071 0.0000
+vn -0.7071 0.0000 -0.7071
+vn -0.7071 -0.7071 -0.0000
+vn 0.0000 0.7071 -0.7071
+vn 0.0000 -0.7071 -0.7071
+vn 1.0000 0.0000 0.0000
+usemtl None
+s 1
+f 2//1 4//1 1//1
+f 6//2 8//2 5//2
+f 10//3 12//3 9//3
+f 14//4 16//4 13//4
+f 18//5 20//5 17//5
+f 15//6 21//6 1//6
+f 14//7 12//7 22//7
+f 20//8 2//8 23//8
+f 11//9 17//9 24//9
+f 16//10 4//10 7//10
+f 9//11 13//11 6//11
+f 8//12 3//12 19//12
+f 10//13 5//13 18//13
+f 14//14 21//14 15//14
+f 11//15 22//15 12//15
+f 20//16 24//16 17//16
+f 1//17 23//17 2//17
+f 10//18 17//18 11//18
+f 8//19 18//19 5//19
+f 2//20 19//20 3//20
+f 9//21 5//21 10//21
+f 16//22 6//22 13//22
+f 3//23 7//23 4//23
+f 12//24 13//24 9//24
+f 4//25 15//25 1//25
+f 24//26 21//26 22//26
+f 2//1 3//1 4//1
+f 6//2 7//2 8//2
+f 10//3 11//3 12//3
+f 14//4 15//4 16//4
+f 18//5 19//5 20//5
+f 14//14 22//14 21//14
+f 11//15 24//15 22//15
+f 20//16 23//16 24//16
+f 1//17 21//17 23//17
+f 10//18 18//18 17//18
+f 8//19 19//19 18//19
+f 2//20 20//20 19//20
+f 9//21 6//21 5//21
+f 16//22 7//22 6//22
+f 3//23 8//23 7//23
+f 12//24 14//24 13//24
+f 4//25 16//25 15//25
+f 24//26 23//26 21//26
diff --git a/examples/vulkan/shared/color.frag b/examples/vulkan/shared/color.frag
new file mode 100644
index 0000000000..375587662f
--- /dev/null
+++ b/examples/vulkan/shared/color.frag
@@ -0,0 +1,10 @@
+#version 440
+
+layout(location = 0) in vec3 v_color;
+
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(v_color, 1.0);
+}
diff --git a/examples/vulkan/shared/color.vert b/examples/vulkan/shared/color.vert
new file mode 100644
index 0000000000..02492c0e65
--- /dev/null
+++ b/examples/vulkan/shared/color.vert
@@ -0,0 +1,18 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+
+layout(location = 0) out vec3 v_color;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+} ubuf;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main()
+{
+ v_color = color;
+ gl_Position = ubuf.mvp * position;
+}
diff --git a/examples/vulkan/shared/color_frag.spv b/examples/vulkan/shared/color_frag.spv
new file mode 100644
index 0000000000..30e33b76ca
--- /dev/null
+++ b/examples/vulkan/shared/color_frag.spv
Binary files differ
diff --git a/examples/vulkan/shared/color_vert.spv b/examples/vulkan/shared/color_vert.spv
new file mode 100644
index 0000000000..a1f42e3119
--- /dev/null
+++ b/examples/vulkan/shared/color_vert.spv
Binary files differ
diff --git a/examples/vulkan/shared/objconvert.js b/examples/vulkan/shared/objconvert.js
new file mode 100644
index 0000000000..9b49e3cdac
--- /dev/null
+++ b/examples/vulkan/shared/objconvert.js
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+var fs = require('fs');
+
+var metadata = {
+ vertexCount: 0,
+ aabb: [[null, null], [null, null], [null, null]],
+ emitVertex: function(v) {
+ ++metadata.vertexCount;
+ var aabb = metadata.aabb;
+ if (aabb[0][0] === null || v[0] < aabb[0][0]) // min x
+ aabb[0][0] = v[0];
+ if (aabb[0][1] === null || v[0] > aabb[0][1]) // max x
+ aabb[0][1] = v[0];
+ if (aabb[1][0] === null || v[1] < aabb[1][0]) // min y
+ aabb[1][0] = v[1];
+ if (aabb[1][1] === null || v[1] > aabb[1][1]) // max y
+ aabb[1][1] = v[1];
+ if (aabb[2][0] === null || v[2] < aabb[2][0]) // min z
+ aabb[2][0] = v[2];
+ if (aabb[2][1] === null || v[2] > aabb[2][1]) // max z
+ aabb[2][1] = v[2];
+ },
+ getBuffer: function() {
+ var aabb = metadata.aabb;
+ console.log(metadata.vertexCount + " vertices");
+ console.log("AABB: " + aabb[0][0] + ".." + aabb[0][1]
+ + ", " + aabb[1][0] + ".." + aabb[1][1]
+ + ", " + aabb[2][0] + ".." + aabb[2][1]);
+ var buf = new Buffer((2 + 6) * 4);
+ var format = 1, p = 0;
+ buf.writeUInt32LE(format, p++);
+ buf.writeUInt32LE(metadata.vertexCount, p++ * 4);
+ for (var i = 0; i < 3; ++i) {
+ buf.writeFloatLE(aabb[i][0], p++ * 4);
+ buf.writeFloatLE(aabb[i][1], p++ * 4);
+ }
+ return buf;
+ }
+};
+
+function makeVec(s, n) {
+ var v = [];
+ s.split(' ').forEach(function (coordStr) {
+ var coord = parseFloat(coordStr);
+ if (!isNaN(coord))
+ v.push(coord);
+ });
+ if (v.length != n) {
+ console.error("Wrong vector size, expected " + n + ", got " + v.length);
+ process.exit();
+ }
+ return v;
+}
+
+function parseObj(filename, callback) {
+ fs.readFile(filename, "ascii", function (err, data) {
+ if (err)
+ throw err;
+ var groupCount = 0;
+ var parsed = { 'vertices': [], 'normals': [], 'texcoords': [], 'links': [] };
+ var missingTexCount = 0, missingNormCount = 0;
+ data.split('\n').forEach(function (line) {
+ var s = line.trim();
+ if (!s.length || groupCount > 1)
+ return;
+ if (s[0] === '#')
+ return;
+ if (s[0] === 'g') {
+ ++groupCount;
+ } else if (s.substr(0, 2) === "v ") {
+ parsed.vertices.push(makeVec(s, 3));
+ } else if (s.substr(0, 3) === "vn ") {
+ parsed.normals.push(makeVec(s, 3));
+ } else if (s.substr(0, 3) === "vt ") {
+ parsed.texcoords.push(makeVec(s, 2));
+ } else if (s.substr(0, 2) === "f ") {
+ var refs = s.split(' ');
+ var vertCount = refs.length - 1;
+ if (vertCount != 3)
+ console.warn("Face " + parsed.links.length / 3 + " has " + vertCount + " vertices! (not triangulated?)");
+ for (var i = 1, ie = Math.min(4, refs.length); i < ie; ++i) {
+ var refComps = refs[i].split('/');
+ var vertIndex = parseInt(refComps[0]) - 1;
+ var texIndex = -1;
+ if (refComps.length >= 2 && refComps[1].length)
+ texIndex = parseInt(refComps[1]) - 1;
+ var normIndex = -1;
+ if (refComps.length >= 3 && refComps[2].length)
+ normIndex = parseInt(refComps[2]) - 1;
+ parsed.links.push([vertIndex, texIndex, normIndex]);
+ if (texIndex == -1)
+ ++missingTexCount;
+ if (normIndex == -1)
+ ++missingNormCount;
+ }
+ }
+ });
+ console.log(missingTexCount + " missing texture coordinates, " + missingNormCount + " missing normals");
+ callback(parsed);
+ });
+}
+
+function fillVert(src, index, dst, elemCount, isVertexCoord) {
+ var vertex = [];
+ if (index >= 0) {
+ for (var i = 0; i < elemCount; ++i) {
+ var elem = src[index][i];
+ if (isVertexCoord)
+ vertex.push(elem);
+ dst.buf.writeFloatLE(elem, dst.bufptr++ * 4);
+ }
+ if (vertex.length == 3)
+ metadata.emitVertex(vertex);
+ } else {
+ if (isVertexCoord) {
+ console.error("Missing vertex");
+ process.exit();
+ }
+ for (var i = 0; i < elemCount; ++i)
+ dst.buf.writeFloatLE(0, dst.bufptr++ * 4);
+ }
+ return vertex;
+}
+
+function normalize(v) {
+ var len = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
+ if (len == 0.0 || len == 1.0)
+ return;
+ len = Math.sqrt(len);
+ return [ v[0] / len, v[1] / len, v[2] / len ];
+}
+
+function surfaceNormal(a, b, c) {
+ var u = [ b[0] - a[0], b[1] - a[1], b[2] - a[2] ];
+ var v = [ c[0] - a[0], c[1] - a[1], c[2] - a[2] ];
+ var result = [ u[1] * v[2] - u[2] * v[1],
+ u[2] * v[0] - u[0] * v[2],
+ u[0] * v[1] - u[1] * v[0] ];
+ return normalize(result);
+}
+
+function objDataToBuf(parsed) {
+ var floatCount = parsed.links.length * (3 + 2 + 3);
+ var buf = new Buffer(floatCount * 4);
+ var dst = { 'buf': buf, 'bufptr': 0 };
+ var tri = [];
+ var genNormals = false;
+ var genNormCount = 0;
+ for (var i = 0; i < parsed.links.length; ++i) {
+ var link = parsed.links[i];
+ var vertIndex = link[0], texIndex = link[1], normIndex = link[2];
+ tri.push(fillVert(parsed.vertices, vertIndex, dst, 3, true));
+ fillVert(parsed.texcoords, texIndex, dst, 2);
+ fillVert(parsed.normals, normIndex, dst, 3);
+ if (normIndex == -1)
+ genNormals = true;
+ if (tri.length == 3) {
+ if (genNormals) {
+ var norm = surfaceNormal(tri[0], tri[1], tri[2]);
+ for (var nvIdx = 0; nvIdx < 3; ++nvIdx) {
+ dst.buf.writeFloatLE(norm[0], (dst.bufptr - 3 - nvIdx * 8) * 4);
+ dst.buf.writeFloatLE(norm[1], (dst.bufptr - 2 - nvIdx * 8) * 4);
+ dst.buf.writeFloatLE(norm[2], (dst.bufptr - 1 - nvIdx * 8) * 4);
+ }
+ genNormCount += 3;
+ }
+ tri = [];
+ }
+ }
+ if (genNormCount)
+ console.log("Generated " + genNormCount + " normals");
+ return buf;
+}
+
+var inFilename = process.argv[2];
+var outFilename = process.argv[3];
+
+if (process.argv.length < 4) {
+ console.log("Usage: objconvert file.obj file.buf");
+ process.exit();
+}
+
+parseObj(inFilename, function (parsed) {
+ var buf = objDataToBuf(parsed);
+ var f = fs.createWriteStream(outFilename);
+ f.on("error", function (e) { console.error(e); });
+ f.write(metadata.getBuffer());
+ f.write(buf);
+ f.end();
+ console.log("Written to " + outFilename + ", format is:");
+ console.log(" uint32 version, uint32 vertex_count, float32 aabb[6], vertex_count * (float32 vertex[3], float32 texcoord[2], float32 normal[3])");
+});
diff --git a/examples/vulkan/shared/qt_logo.buf b/examples/vulkan/shared/qt_logo.buf
new file mode 100644
index 0000000000..316ec41aee
--- /dev/null
+++ b/examples/vulkan/shared/qt_logo.buf
Binary files differ
diff --git a/examples/vulkan/shared/qt_logo.txt b/examples/vulkan/shared/qt_logo.txt
new file mode 100644
index 0000000000..167b8a4caf
--- /dev/null
+++ b/examples/vulkan/shared/qt_logo.txt
@@ -0,0 +1,2912 @@
+# Blender v2.77 (sub 0) OBJ File: 'qt_logo.blend'
+# www.blender.org
+o qt_logo_qt_logo_mesh
+v 0.500000 0.030000 -0.271909
+v 0.500000 0.030000 -0.234087
+v 0.500000 0.030000 0.229669
+v 0.361282 0.030000 0.368353
+v -0.369121 0.030000 0.368353
+v -0.403885 0.030000 0.368353
+v -0.500000 0.030000 0.368353
+v -0.500000 0.030000 0.272263
+v -0.500000 0.030000 0.234440
+v -0.500000 0.030000 -0.229316
+v -0.361282 0.030000 -0.368000
+v 0.369121 0.030000 -0.368000
+v 0.403886 0.030000 -0.368000
+v 0.500000 0.030000 -0.368000
+v -0.014123 0.030000 0.177038
+v -0.008432 0.030000 0.172481
+v -0.003036 0.030000 0.167611
+v 0.002070 0.030000 0.162429
+v 0.006887 0.030000 0.156934
+v 0.011418 0.030000 0.151127
+v 0.015664 0.030000 0.145008
+v 0.019629 0.030000 0.138577
+v 0.023315 0.030000 0.131833
+v 0.026724 0.030000 0.124776
+v 0.029858 0.030000 0.117408
+v 0.032720 0.030000 0.109727
+v 0.035255 0.030000 0.101769
+v 0.037575 0.030000 0.093399
+v 0.039680 0.030000 0.084618
+v 0.041569 0.030000 0.075425
+v 0.043240 0.030000 0.065820
+v 0.044692 0.030000 0.055804
+v 0.045923 0.030000 0.045375
+v 0.046934 0.030000 0.034535
+v 0.047722 0.030000 0.023284
+v 0.048286 0.030000 0.011620
+v 0.048626 0.030000 -0.000455
+v 0.048739 0.030000 -0.012942
+v 0.048469 0.030000 -0.031775
+v 0.047658 0.030000 -0.049771
+v 0.046305 0.030000 -0.066929
+v 0.044409 0.030000 -0.083249
+v 0.041969 0.030000 -0.098732
+v 0.038983 0.030000 -0.113377
+v 0.035450 0.030000 -0.127184
+v 0.031369 0.030000 -0.140154
+v 0.026739 0.030000 -0.152286
+v 0.021559 0.030000 -0.163580
+v 0.015828 0.030000 -0.174037
+v 0.009543 0.030000 -0.183656
+v 0.002656 0.030000 -0.192551
+v -0.005054 0.030000 -0.200667
+v -0.013585 0.030000 -0.208004
+v -0.022937 0.030000 -0.214563
+v -0.033107 0.030000 -0.220347
+v -0.044095 0.030000 -0.225355
+v -0.055900 0.030000 -0.229590
+v -0.068520 0.030000 -0.233052
+v -0.081954 0.030000 -0.235742
+v -0.096201 0.030000 -0.237663
+v -0.111260 0.030000 -0.238814
+v -0.127130 0.030000 -0.239198
+v -0.143000 0.030000 -0.238808
+v -0.158061 0.030000 -0.237638
+v -0.172312 0.030000 -0.235689
+v -0.185753 0.030000 -0.232963
+v -0.198385 0.030000 -0.229461
+v -0.210208 0.030000 -0.225185
+v -0.221221 0.030000 -0.220134
+v -0.231425 0.030000 -0.214311
+v -0.240819 0.030000 -0.207716
+v -0.249404 0.030000 -0.200351
+v -0.257179 0.030000 -0.192217
+v -0.264144 0.030000 -0.183315
+v -0.270435 0.030000 -0.173618
+v -0.276186 0.030000 -0.163098
+v -0.281394 0.030000 -0.151754
+v -0.286059 0.030000 -0.139586
+v -0.290179 0.030000 -0.126595
+v -0.293754 0.030000 -0.112781
+v -0.296782 0.030000 -0.098143
+v -0.299263 0.030000 -0.082682
+v -0.301194 0.030000 -0.066397
+v -0.302575 0.030000 -0.049288
+v -0.303404 0.030000 -0.031357
+v -0.303681 0.030000 -0.012601
+v -0.303411 0.030000 0.006061
+v -0.302602 0.030000 0.023884
+v -0.301253 0.030000 0.040864
+v -0.299364 0.030000 0.056999
+v -0.296935 0.030000 0.072288
+v -0.293967 0.030000 0.086726
+v -0.290460 0.030000 0.100313
+v -0.286412 0.030000 0.113046
+v -0.281825 0.030000 0.124922
+v -0.276698 0.030000 0.135939
+v -0.271032 0.030000 0.146095
+v -0.264826 0.030000 0.155387
+v -0.257932 0.030000 0.163877
+v -0.250200 0.030000 0.171629
+v -0.241634 0.030000 0.178643
+v -0.232233 0.030000 0.184918
+v -0.221998 0.030000 0.190455
+v -0.210932 0.030000 0.195254
+v -0.199035 0.030000 0.199315
+v -0.186309 0.030000 0.202637
+v -0.172754 0.030000 0.205221
+v -0.158371 0.030000 0.207067
+v -0.143163 0.030000 0.208174
+v -0.127130 0.030000 0.208543
+v -0.122805 0.030000 0.208515
+v -0.118691 0.030000 0.208431
+v -0.114786 0.030000 0.208293
+v -0.111086 0.030000 0.208101
+v -0.107590 0.030000 0.207858
+v -0.104294 0.030000 0.207563
+v -0.101198 0.030000 0.207219
+v -0.098298 0.030000 0.206827
+v -0.095593 0.030000 0.206387
+v -0.093079 0.030000 0.205901
+v -0.090754 0.030000 0.205370
+v -0.088616 0.030000 0.204795
+v -0.032379 0.030000 0.297137
+v 0.032720 0.030000 0.266811
+v 0.027981 0.030000 0.259139
+v 0.022692 0.030000 0.250576
+v 0.017036 0.030000 0.241420
+v 0.011197 0.030000 0.231966
+v 0.005358 0.030000 0.222513
+v -0.000298 0.030000 0.213356
+v -0.005587 0.030000 0.204794
+v -0.010326 0.030000 0.197122
+v -0.014331 0.030000 0.190638
+v -0.017419 0.030000 0.185639
+v -0.019406 0.030000 0.182422
+v -0.020109 0.030000 0.181283
+v 0.291411 0.030000 0.137327
+v 0.286764 0.030000 0.137511
+v 0.281577 0.030000 0.137715
+v 0.276031 0.030000 0.137934
+v 0.270305 0.030000 0.138160
+v 0.264578 0.030000 0.138386
+v 0.259032 0.030000 0.138605
+v 0.253845 0.030000 0.138810
+v 0.249198 0.030000 0.138993
+v 0.245271 0.030000 0.139148
+v 0.242243 0.030000 0.139267
+v 0.240294 0.030000 0.139344
+v 0.239605 0.030000 0.139372
+v 0.235884 0.030000 0.139286
+v 0.232394 0.030000 0.139029
+v 0.229135 0.030000 0.138600
+v 0.226110 0.030000 0.137996
+v 0.223322 0.030000 0.137217
+v 0.220774 0.030000 0.136262
+v 0.218466 0.030000 0.135130
+v 0.216403 0.030000 0.133819
+v 0.214585 0.030000 0.132328
+v 0.213017 0.030000 0.130656
+v 0.211699 0.030000 0.128802
+v 0.210634 0.030000 0.126764
+v 0.209732 0.030000 0.124535
+v 0.208903 0.030000 0.121937
+v 0.208147 0.030000 0.118969
+v 0.207465 0.030000 0.115633
+v 0.206860 0.030000 0.111927
+v 0.206331 0.030000 0.107853
+v 0.205880 0.030000 0.103409
+v 0.205509 0.030000 0.098596
+v 0.205218 0.030000 0.093413
+v 0.205009 0.030000 0.087862
+v 0.204882 0.030000 0.081942
+v 0.204840 0.030000 0.075652
+v 0.204840 0.030000 -0.063713
+v 0.292093 0.030000 -0.063713
+v 0.292093 0.030000 -0.122662
+v 0.204840 0.030000 -0.122662
+v 0.204840 0.030000 -0.214664
+v 0.136333 0.030000 -0.214664
+v 0.136333 0.030000 -0.122662
+v 0.087935 0.030000 -0.122662
+v 0.087935 0.030000 -0.064054
+v 0.136333 0.030000 -0.064054
+v 0.136333 0.030000 -0.050850
+v 0.136333 0.030000 -0.036113
+v 0.136333 0.030000 -0.020353
+v 0.136333 0.030000 -0.004083
+v 0.136333 0.030000 0.012188
+v 0.136333 0.030000 0.027947
+v 0.136333 0.030000 0.042685
+v 0.136333 0.030000 0.055889
+v 0.136333 0.030000 0.067048
+v 0.136333 0.030000 0.075652
+v 0.136333 0.030000 0.081189
+v 0.136333 0.030000 0.083148
+v 0.136475 0.030000 0.094258
+v 0.136899 0.030000 0.104757
+v 0.137605 0.030000 0.114646
+v 0.138592 0.030000 0.123924
+v 0.139858 0.030000 0.132592
+v 0.141403 0.030000 0.140649
+v 0.143224 0.030000 0.148096
+v 0.145321 0.030000 0.154932
+v 0.147692 0.030000 0.161158
+v 0.150337 0.030000 0.166773
+v 0.153254 0.030000 0.171778
+v 0.156442 0.030000 0.176172
+v 0.159999 0.030000 0.180091
+v 0.164025 0.030000 0.183669
+v 0.168520 0.030000 0.186906
+v 0.173483 0.030000 0.189802
+v 0.178915 0.030000 0.192358
+v 0.184816 0.030000 0.194573
+v 0.191185 0.030000 0.196447
+v 0.198023 0.030000 0.197980
+v 0.205330 0.030000 0.199173
+v 0.213105 0.030000 0.200024
+v 0.221349 0.030000 0.200536
+v 0.230061 0.030000 0.200706
+v 0.233945 0.030000 0.200649
+v 0.238099 0.030000 0.200479
+v 0.242523 0.030000 0.200195
+v 0.247217 0.030000 0.199797
+v 0.252180 0.030000 0.199286
+v 0.257413 0.030000 0.198662
+v 0.262916 0.030000 0.197923
+v 0.268689 0.030000 0.197071
+v 0.274732 0.030000 0.196106
+v 0.281044 0.030000 0.195027
+v 0.287626 0.030000 0.193834
+v 0.294479 0.030000 0.192528
+v -0.042504 0.030000 -0.131451
+v -0.039308 0.030000 -0.123910
+v -0.036421 0.030000 -0.115714
+v -0.033843 0.030000 -0.106862
+v -0.031573 0.030000 -0.097352
+v -0.029610 0.030000 -0.087182
+v -0.027952 0.030000 -0.076353
+v -0.026597 0.030000 -0.064862
+v -0.025546 0.030000 -0.052708
+v -0.024797 0.030000 -0.039891
+v -0.024348 0.030000 -0.026409
+v -0.024199 0.030000 -0.012261
+v -0.024348 0.030000 0.001795
+v -0.024794 0.030000 0.015166
+v -0.025536 0.030000 0.027852
+v -0.026572 0.030000 0.039848
+v -0.027902 0.030000 0.051154
+v -0.029525 0.030000 0.061767
+v -0.031438 0.030000 0.071683
+v -0.033641 0.030000 0.080902
+v -0.036133 0.030000 0.089420
+v -0.038913 0.030000 0.097236
+v -0.041979 0.030000 0.104346
+v -0.045331 0.030000 0.110749
+v -0.049179 0.030000 0.116548
+v -0.053569 0.030000 0.121850
+v -0.058501 0.030000 0.126652
+v -0.063975 0.030000 0.130954
+v -0.069995 0.030000 0.134754
+v -0.076559 0.030000 0.138051
+v -0.083671 0.030000 0.140844
+v -0.091330 0.030000 0.143132
+v -0.099539 0.030000 0.144914
+v -0.108298 0.030000 0.146188
+v -0.117608 0.030000 0.146953
+v -0.127471 0.030000 0.147209
+v -0.137341 0.030000 0.146947
+v -0.146670 0.030000 0.146161
+v -0.155456 0.030000 0.144855
+v -0.163700 0.030000 0.143031
+v -0.171399 0.030000 0.140692
+v -0.178553 0.030000 0.137838
+v -0.185160 0.030000 0.134474
+v -0.191219 0.030000 0.130601
+v -0.196729 0.030000 0.126221
+v -0.201689 0.030000 0.121337
+v -0.206097 0.030000 0.115952
+v -0.209952 0.030000 0.110067
+v -0.213382 0.030000 0.103587
+v -0.216513 0.030000 0.096412
+v -0.219346 0.030000 0.088547
+v -0.221881 0.030000 0.079993
+v -0.224118 0.030000 0.070753
+v -0.226057 0.030000 0.060830
+v -0.227697 0.030000 0.050224
+v -0.229039 0.030000 0.038940
+v -0.230083 0.030000 0.026978
+v -0.230828 0.030000 0.014343
+v -0.231276 0.030000 0.001035
+v -0.231425 0.030000 -0.012942
+v -0.231269 0.030000 -0.027005
+v -0.230801 0.030000 -0.040404
+v -0.230024 0.030000 -0.053140
+v -0.228938 0.030000 -0.065215
+v -0.227544 0.030000 -0.076633
+v -0.225844 0.030000 -0.087395
+v -0.223838 0.030000 -0.097504
+v -0.221528 0.030000 -0.106963
+v -0.218915 0.030000 -0.115773
+v -0.216000 0.030000 -0.123937
+v -0.212785 0.030000 -0.131458
+v -0.209271 0.030000 -0.138337
+v -0.205266 0.030000 -0.144620
+v -0.200750 0.030000 -0.150350
+v -0.195723 0.030000 -0.155529
+v -0.190184 0.030000 -0.160157
+v -0.184134 0.030000 -0.164237
+v -0.177573 0.030000 -0.167769
+v -0.170501 0.030000 -0.170754
+v -0.162917 0.030000 -0.173194
+v -0.154823 0.030000 -0.175090
+v -0.146217 0.030000 -0.176442
+v -0.137100 0.030000 -0.177253
+v -0.127471 0.030000 -0.177523
+v -0.117843 0.030000 -0.177253
+v -0.108727 0.030000 -0.176442
+v -0.100125 0.030000 -0.175090
+v -0.092037 0.030000 -0.173194
+v -0.084466 0.030000 -0.170754
+v -0.077411 0.030000 -0.167769
+v -0.070875 0.030000 -0.164237
+v -0.064859 0.030000 -0.160157
+v -0.059363 0.030000 -0.155529
+v -0.054389 0.030000 -0.150350
+v -0.049939 0.030000 -0.144620
+v -0.046012 0.030000 -0.138337
+v 0.500000 -0.030000 -0.271909
+v 0.500000 -0.030000 -0.234087
+v 0.500000 -0.030000 0.229669
+v 0.361282 -0.030000 0.368353
+v -0.369121 -0.030000 0.368353
+v -0.403885 -0.030000 0.368353
+v -0.500000 -0.030000 0.368353
+v -0.500000 -0.030000 0.272263
+v -0.500000 -0.030000 0.234440
+v -0.500000 -0.030000 -0.229316
+v -0.361282 -0.030000 -0.368000
+v 0.369121 -0.030000 -0.368000
+v 0.403886 -0.030000 -0.368000
+v 0.500000 -0.030000 -0.368000
+v -0.014123 -0.030000 0.177038
+v -0.008432 -0.030000 0.172481
+v -0.003036 -0.030000 0.167611
+v 0.002070 -0.030000 0.162429
+v 0.006887 -0.030000 0.156934
+v 0.011418 -0.030000 0.151127
+v 0.015664 -0.030000 0.145008
+v 0.019629 -0.030000 0.138577
+v 0.023315 -0.030000 0.131833
+v 0.026724 -0.030000 0.124776
+v 0.029858 -0.030000 0.117408
+v 0.032720 -0.030000 0.109727
+v 0.035255 -0.030000 0.101769
+v 0.037575 -0.030000 0.093399
+v 0.039680 -0.030000 0.084618
+v 0.041569 -0.030000 0.075425
+v 0.043240 -0.030000 0.065820
+v 0.044692 -0.030000 0.055804
+v 0.045923 -0.030000 0.045375
+v 0.046934 -0.030000 0.034535
+v 0.047722 -0.030000 0.023284
+v 0.048286 -0.030000 0.011620
+v 0.048626 -0.030000 -0.000455
+v 0.048739 -0.030000 -0.012942
+v 0.048469 -0.030000 -0.031775
+v 0.047658 -0.030000 -0.049771
+v 0.046305 -0.030000 -0.066929
+v 0.044409 -0.030000 -0.083249
+v 0.041969 -0.030000 -0.098732
+v 0.038983 -0.030000 -0.113377
+v 0.035450 -0.030000 -0.127184
+v 0.031369 -0.030000 -0.140154
+v 0.026739 -0.030000 -0.152286
+v 0.021559 -0.030000 -0.163580
+v 0.015828 -0.030000 -0.174037
+v 0.009543 -0.030000 -0.183656
+v 0.002656 -0.030000 -0.192551
+v -0.005054 -0.030000 -0.200667
+v -0.013585 -0.030000 -0.208004
+v -0.022937 -0.030000 -0.214563
+v -0.033107 -0.030000 -0.220347
+v -0.044095 -0.030000 -0.225355
+v -0.055900 -0.030000 -0.229590
+v -0.068520 -0.030000 -0.233052
+v -0.081954 -0.030000 -0.235742
+v -0.096201 -0.030000 -0.237663
+v -0.111260 -0.030000 -0.238814
+v -0.127130 -0.030000 -0.239198
+v -0.143000 -0.030000 -0.238808
+v -0.158061 -0.030000 -0.237638
+v -0.172312 -0.030000 -0.235689
+v -0.185753 -0.030000 -0.232963
+v -0.198385 -0.030000 -0.229461
+v -0.210208 -0.030000 -0.225185
+v -0.221221 -0.030000 -0.220134
+v -0.231425 -0.030000 -0.214311
+v -0.240819 -0.030000 -0.207716
+v -0.249404 -0.030000 -0.200351
+v -0.257179 -0.030000 -0.192217
+v -0.264144 -0.030000 -0.183315
+v -0.270435 -0.030000 -0.173618
+v -0.276186 -0.030000 -0.163098
+v -0.281394 -0.030000 -0.151754
+v -0.286059 -0.030000 -0.139586
+v -0.290179 -0.030000 -0.126595
+v -0.293754 -0.030000 -0.112781
+v -0.296782 -0.030000 -0.098143
+v -0.299263 -0.030000 -0.082682
+v -0.301194 -0.030000 -0.066397
+v -0.302575 -0.030000 -0.049288
+v -0.303404 -0.030000 -0.031357
+v -0.303681 -0.030000 -0.012601
+v -0.303411 -0.030000 0.006061
+v -0.302602 -0.030000 0.023884
+v -0.301253 -0.030000 0.040864
+v -0.299364 -0.030000 0.056999
+v -0.296935 -0.030000 0.072288
+v -0.293967 -0.030000 0.086726
+v -0.290460 -0.030000 0.100313
+v -0.286412 -0.030000 0.113046
+v -0.281825 -0.030000 0.124922
+v -0.276698 -0.030000 0.135939
+v -0.271032 -0.030000 0.146095
+v -0.264826 -0.030000 0.155387
+v -0.257932 -0.030000 0.163877
+v -0.250200 -0.030000 0.171629
+v -0.241634 -0.030000 0.178643
+v -0.232233 -0.030000 0.184918
+v -0.221998 -0.030000 0.190455
+v -0.210932 -0.030000 0.195254
+v -0.199035 -0.030000 0.199315
+v -0.186309 -0.030000 0.202637
+v -0.172754 -0.030000 0.205221
+v -0.158371 -0.030000 0.207067
+v -0.143163 -0.030000 0.208174
+v -0.127130 -0.030000 0.208543
+v -0.122805 -0.030000 0.208515
+v -0.118691 -0.030000 0.208431
+v -0.114786 -0.030000 0.208293
+v -0.111086 -0.030000 0.208101
+v -0.107590 -0.030000 0.207858
+v -0.104294 -0.030000 0.207563
+v -0.101198 -0.030000 0.207219
+v -0.098298 -0.030000 0.206827
+v -0.095593 -0.030000 0.206387
+v -0.093079 -0.030000 0.205901
+v -0.090754 -0.030000 0.205370
+v -0.088616 -0.030000 0.204795
+v -0.032379 -0.030000 0.297137
+v 0.032720 -0.030000 0.266811
+v 0.027981 -0.030000 0.259139
+v 0.022692 -0.030000 0.250576
+v 0.017036 -0.030000 0.241420
+v 0.011197 -0.030000 0.231966
+v 0.005358 -0.030000 0.222513
+v -0.000298 -0.030000 0.213356
+v -0.005587 -0.030000 0.204794
+v -0.010326 -0.030000 0.197122
+v -0.014331 -0.030000 0.190638
+v -0.017419 -0.030000 0.185639
+v -0.019406 -0.030000 0.182422
+v -0.020109 -0.030000 0.181283
+v 0.291411 -0.030000 0.137327
+v 0.286764 -0.030000 0.137511
+v 0.281577 -0.030000 0.137715
+v 0.276031 -0.030000 0.137934
+v 0.270305 -0.030000 0.138160
+v 0.264578 -0.030000 0.138386
+v 0.259032 -0.030000 0.138605
+v 0.253845 -0.030000 0.138810
+v 0.249198 -0.030000 0.138993
+v 0.245271 -0.030000 0.139148
+v 0.242243 -0.030000 0.139267
+v 0.240294 -0.030000 0.139344
+v 0.239605 -0.030000 0.139372
+v 0.235884 -0.030000 0.139286
+v 0.232394 -0.030000 0.139029
+v 0.229135 -0.030000 0.138600
+v 0.226110 -0.030000 0.137996
+v 0.223322 -0.030000 0.137217
+v 0.220774 -0.030000 0.136262
+v 0.218466 -0.030000 0.135130
+v 0.216403 -0.030000 0.133819
+v 0.214585 -0.030000 0.132328
+v 0.213017 -0.030000 0.130656
+v 0.211699 -0.030000 0.128802
+v 0.210634 -0.030000 0.126764
+v 0.209732 -0.030000 0.124535
+v 0.208903 -0.030000 0.121937
+v 0.208147 -0.030000 0.118969
+v 0.207465 -0.030000 0.115633
+v 0.206860 -0.030000 0.111927
+v 0.206331 -0.030000 0.107853
+v 0.205880 -0.030000 0.103409
+v 0.205509 -0.030000 0.098596
+v 0.205218 -0.030000 0.093413
+v 0.205009 -0.030000 0.087862
+v 0.204882 -0.030000 0.081942
+v 0.204840 -0.030000 0.075652
+v 0.204840 -0.030000 -0.063713
+v 0.292093 -0.030000 -0.063713
+v 0.292093 -0.030000 -0.122662
+v 0.204840 -0.030000 -0.122662
+v 0.204840 -0.030000 -0.214664
+v 0.136333 -0.030000 -0.214664
+v 0.136333 -0.030000 -0.122662
+v 0.087935 -0.030000 -0.122662
+v 0.087935 -0.030000 -0.064054
+v 0.136333 -0.030000 -0.064054
+v 0.136333 -0.030000 -0.050850
+v 0.136333 -0.030000 -0.036113
+v 0.136333 -0.030000 -0.020353
+v 0.136333 -0.030000 -0.004083
+v 0.136333 -0.030000 0.012188
+v 0.136333 -0.030000 0.027947
+v 0.136333 -0.030000 0.042685
+v 0.136333 -0.030000 0.055889
+v 0.136333 -0.030000 0.067048
+v 0.136333 -0.030000 0.075652
+v 0.136333 -0.030000 0.081189
+v 0.136333 -0.030000 0.083148
+v 0.136475 -0.030000 0.094258
+v 0.136899 -0.030000 0.104757
+v 0.137605 -0.030000 0.114646
+v 0.138592 -0.030000 0.123924
+v 0.139858 -0.030000 0.132592
+v 0.141403 -0.030000 0.140649
+v 0.143224 -0.030000 0.148096
+v 0.145321 -0.030000 0.154932
+v 0.147692 -0.030000 0.161158
+v 0.150337 -0.030000 0.166773
+v 0.153254 -0.030000 0.171778
+v 0.156442 -0.030000 0.176172
+v 0.159999 -0.030000 0.180091
+v 0.164025 -0.030000 0.183669
+v 0.168520 -0.030000 0.186906
+v 0.173483 -0.030000 0.189802
+v 0.178915 -0.030000 0.192358
+v 0.184816 -0.030000 0.194573
+v 0.191185 -0.030000 0.196447
+v 0.198023 -0.030000 0.197980
+v 0.205330 -0.030000 0.199173
+v 0.213105 -0.030000 0.200024
+v 0.221349 -0.030000 0.200536
+v 0.230061 -0.030000 0.200706
+v 0.233945 -0.030000 0.200649
+v 0.238099 -0.030000 0.200479
+v 0.242523 -0.030000 0.200195
+v 0.247217 -0.030000 0.199797
+v 0.252180 -0.030000 0.199286
+v 0.257413 -0.030000 0.198662
+v 0.262916 -0.030000 0.197923
+v 0.268689 -0.030000 0.197071
+v 0.274732 -0.030000 0.196106
+v 0.281044 -0.030000 0.195027
+v 0.287626 -0.030000 0.193834
+v 0.294479 -0.030000 0.192528
+v -0.042504 -0.030000 -0.131451
+v -0.039308 -0.030000 -0.123910
+v -0.036421 -0.030000 -0.115714
+v -0.033843 -0.030000 -0.106862
+v -0.031573 -0.030000 -0.097352
+v -0.029610 -0.030000 -0.087182
+v -0.027952 -0.030000 -0.076353
+v -0.026597 -0.030000 -0.064862
+v -0.025546 -0.030000 -0.052708
+v -0.024797 -0.030000 -0.039891
+v -0.024348 -0.030000 -0.026409
+v -0.024199 -0.030000 -0.012261
+v -0.024348 -0.030000 0.001795
+v -0.024794 -0.030000 0.015166
+v -0.025536 -0.030000 0.027852
+v -0.026572 -0.030000 0.039848
+v -0.027902 -0.030000 0.051154
+v -0.029525 -0.030000 0.061767
+v -0.031438 -0.030000 0.071683
+v -0.033641 -0.030000 0.080902
+v -0.036133 -0.030000 0.089420
+v -0.038913 -0.030000 0.097236
+v -0.041979 -0.030000 0.104346
+v -0.045331 -0.030000 0.110749
+v -0.049179 -0.030000 0.116548
+v -0.053569 -0.030000 0.121850
+v -0.058501 -0.030000 0.126652
+v -0.063975 -0.030000 0.130954
+v -0.069995 -0.030000 0.134754
+v -0.076559 -0.030000 0.138051
+v -0.083671 -0.030000 0.140844
+v -0.091330 -0.030000 0.143132
+v -0.099539 -0.030000 0.144914
+v -0.108298 -0.030000 0.146188
+v -0.117608 -0.030000 0.146953
+v -0.127471 -0.030000 0.147209
+v -0.137341 -0.030000 0.146947
+v -0.146670 -0.030000 0.146161
+v -0.155456 -0.030000 0.144855
+v -0.163700 -0.030000 0.143031
+v -0.171399 -0.030000 0.140692
+v -0.178553 -0.030000 0.137838
+v -0.185160 -0.030000 0.134474
+v -0.191219 -0.030000 0.130601
+v -0.196729 -0.030000 0.126221
+v -0.201689 -0.030000 0.121337
+v -0.206097 -0.030000 0.115952
+v -0.209952 -0.030000 0.110067
+v -0.213382 -0.030000 0.103587
+v -0.216513 -0.030000 0.096412
+v -0.219346 -0.030000 0.088547
+v -0.221881 -0.030000 0.079993
+v -0.224118 -0.030000 0.070753
+v -0.226057 -0.030000 0.060830
+v -0.227697 -0.030000 0.050224
+v -0.229039 -0.030000 0.038940
+v -0.230083 -0.030000 0.026978
+v -0.230828 -0.030000 0.014343
+v -0.231276 -0.030000 0.001035
+v -0.231425 -0.030000 -0.012942
+v -0.231269 -0.030000 -0.027005
+v -0.230801 -0.030000 -0.040404
+v -0.230024 -0.030000 -0.053140
+v -0.228938 -0.030000 -0.065215
+v -0.227544 -0.030000 -0.076633
+v -0.225844 -0.030000 -0.087395
+v -0.223838 -0.030000 -0.097504
+v -0.221528 -0.030000 -0.106963
+v -0.218915 -0.030000 -0.115773
+v -0.216000 -0.030000 -0.123937
+v -0.212785 -0.030000 -0.131458
+v -0.209271 -0.030000 -0.138337
+v -0.205266 -0.030000 -0.144620
+v -0.200750 -0.030000 -0.150350
+v -0.195723 -0.030000 -0.155529
+v -0.190184 -0.030000 -0.160157
+v -0.184134 -0.030000 -0.164237
+v -0.177573 -0.030000 -0.167769
+v -0.170501 -0.030000 -0.170754
+v -0.162917 -0.030000 -0.173194
+v -0.154823 -0.030000 -0.175090
+v -0.146217 -0.030000 -0.176442
+v -0.137100 -0.030000 -0.177253
+v -0.127471 -0.030000 -0.177523
+v -0.117843 -0.030000 -0.177253
+v -0.108727 -0.030000 -0.176442
+v -0.100125 -0.030000 -0.175090
+v -0.092037 -0.030000 -0.173194
+v -0.084466 -0.030000 -0.170754
+v -0.077411 -0.030000 -0.167769
+v -0.070875 -0.030000 -0.164237
+v -0.064859 -0.030000 -0.160157
+v -0.059363 -0.030000 -0.155529
+v -0.054389 -0.030000 -0.150350
+v -0.049939 -0.030000 -0.144620
+v -0.046012 -0.030000 -0.138337
+v 0.500000 -0.030000 -0.271909
+v 0.500000 0.030000 -0.271909
+v 0.500000 -0.030000 -0.234087
+v 0.500000 0.030000 -0.234087
+v 0.500000 -0.030000 0.229669
+v 0.500000 0.030000 0.229669
+v 0.361282 -0.030000 0.368353
+v 0.361282 0.030000 0.368353
+v -0.369121 -0.030000 0.368353
+v -0.369121 0.030000 0.368353
+v -0.403885 -0.030000 0.368353
+v -0.403885 0.030000 0.368353
+v -0.500000 -0.030000 0.368353
+v -0.500000 0.030000 0.368353
+v -0.500000 -0.030000 0.272263
+v -0.500000 0.030000 0.272263
+v -0.500000 -0.030000 0.234440
+v -0.500000 0.030000 0.234440
+v -0.500000 -0.030000 -0.229316
+v -0.500000 0.030000 -0.229316
+v -0.361282 -0.030000 -0.368000
+v -0.361282 0.030000 -0.368000
+v 0.369121 -0.030000 -0.368000
+v 0.369121 0.030000 -0.368000
+v 0.403886 -0.030000 -0.368000
+v 0.403886 0.030000 -0.368000
+v 0.500000 -0.030000 -0.368000
+v 0.500000 0.030000 -0.368000
+v -0.014123 -0.030000 0.177038
+v -0.014123 0.030000 0.177038
+v -0.008432 -0.030000 0.172481
+v -0.008432 0.030000 0.172481
+v -0.003036 -0.030000 0.167611
+v -0.003036 0.030000 0.167611
+v 0.002070 -0.030000 0.162429
+v 0.002070 0.030000 0.162429
+v 0.006887 -0.030000 0.156934
+v 0.006887 0.030000 0.156934
+v 0.011418 -0.030000 0.151127
+v 0.011418 0.030000 0.151127
+v 0.015664 -0.030000 0.145008
+v 0.015664 0.030000 0.145008
+v 0.019629 -0.030000 0.138577
+v 0.019629 0.030000 0.138577
+v 0.023315 -0.030000 0.131833
+v 0.023315 0.030000 0.131833
+v 0.026724 -0.030000 0.124776
+v 0.026724 0.030000 0.124776
+v 0.029858 -0.030000 0.117408
+v 0.029858 0.030000 0.117408
+v 0.032720 -0.030000 0.109727
+v 0.032720 0.030000 0.109727
+v 0.035255 -0.030000 0.101769
+v 0.035255 0.030000 0.101769
+v 0.037575 -0.030000 0.093399
+v 0.037575 0.030000 0.093399
+v 0.039680 -0.030000 0.084618
+v 0.039680 0.030000 0.084618
+v 0.041569 -0.030000 0.075425
+v 0.041569 0.030000 0.075425
+v 0.043240 -0.030000 0.065820
+v 0.043240 0.030000 0.065820
+v 0.044692 -0.030000 0.055804
+v 0.044692 0.030000 0.055804
+v 0.045923 -0.030000 0.045375
+v 0.045923 0.030000 0.045375
+v 0.046934 -0.030000 0.034535
+v 0.046934 0.030000 0.034535
+v 0.047722 -0.030000 0.023284
+v 0.047722 0.030000 0.023284
+v 0.048286 -0.030000 0.011620
+v 0.048286 0.030000 0.011620
+v 0.048626 -0.030000 -0.000455
+v 0.048626 0.030000 -0.000455
+v 0.048739 -0.030000 -0.012942
+v 0.048739 0.030000 -0.012942
+v 0.048469 -0.030000 -0.031775
+v 0.048469 0.030000 -0.031775
+v 0.047658 -0.030000 -0.049771
+v 0.047658 0.030000 -0.049771
+v 0.046305 -0.030000 -0.066929
+v 0.046305 0.030000 -0.066929
+v 0.044409 -0.030000 -0.083249
+v 0.044409 0.030000 -0.083249
+v 0.041969 -0.030000 -0.098732
+v 0.041969 0.030000 -0.098732
+v 0.038983 -0.030000 -0.113377
+v 0.038983 0.030000 -0.113377
+v 0.035450 -0.030000 -0.127184
+v 0.035450 0.030000 -0.127184
+v 0.031369 -0.030000 -0.140154
+v 0.031369 0.030000 -0.140154
+v 0.026739 -0.030000 -0.152286
+v 0.026739 0.030000 -0.152286
+v 0.021559 -0.030000 -0.163580
+v 0.021559 0.030000 -0.163580
+v 0.015828 -0.030000 -0.174037
+v 0.015828 0.030000 -0.174037
+v 0.009543 -0.030000 -0.183656
+v 0.009543 0.030000 -0.183656
+v 0.002656 -0.030000 -0.192551
+v 0.002656 0.030000 -0.192551
+v -0.005054 -0.030000 -0.200667
+v -0.005054 0.030000 -0.200667
+v -0.013585 -0.030000 -0.208004
+v -0.013585 0.030000 -0.208004
+v -0.022937 -0.030000 -0.214563
+v -0.022937 0.030000 -0.214563
+v -0.033107 -0.030000 -0.220347
+v -0.033107 0.030000 -0.220347
+v -0.044095 -0.030000 -0.225355
+v -0.044095 0.030000 -0.225355
+v -0.055900 -0.030000 -0.229590
+v -0.055900 0.030000 -0.229590
+v -0.068520 -0.030000 -0.233052
+v -0.068520 0.030000 -0.233052
+v -0.081954 -0.030000 -0.235742
+v -0.081954 0.030000 -0.235742
+v -0.096201 -0.030000 -0.237663
+v -0.096201 0.030000 -0.237663
+v -0.111260 -0.030000 -0.238814
+v -0.111260 0.030000 -0.238814
+v -0.127130 -0.030000 -0.239198
+v -0.127130 0.030000 -0.239198
+v -0.143000 -0.030000 -0.238808
+v -0.143000 0.030000 -0.238808
+v -0.158061 -0.030000 -0.237638
+v -0.158061 0.030000 -0.237638
+v -0.172312 -0.030000 -0.235689
+v -0.172312 0.030000 -0.235689
+v -0.185753 -0.030000 -0.232963
+v -0.185753 0.030000 -0.232963
+v -0.198385 -0.030000 -0.229461
+v -0.198385 0.030000 -0.229461
+v -0.210208 -0.030000 -0.225185
+v -0.210208 0.030000 -0.225185
+v -0.221221 -0.030000 -0.220134
+v -0.221221 0.030000 -0.220134
+v -0.231425 -0.030000 -0.214311
+v -0.231425 0.030000 -0.214311
+v -0.240819 -0.030000 -0.207716
+v -0.240819 0.030000 -0.207716
+v -0.249404 -0.030000 -0.200351
+v -0.249404 0.030000 -0.200351
+v -0.257179 -0.030000 -0.192217
+v -0.257179 0.030000 -0.192217
+v -0.264144 -0.030000 -0.183315
+v -0.264144 0.030000 -0.183315
+v -0.270435 -0.030000 -0.173618
+v -0.270435 0.030000 -0.173618
+v -0.276186 -0.030000 -0.163098
+v -0.276186 0.030000 -0.163098
+v -0.281394 -0.030000 -0.151754
+v -0.281394 0.030000 -0.151754
+v -0.286059 -0.030000 -0.139586
+v -0.286059 0.030000 -0.139586
+v -0.290179 -0.030000 -0.126595
+v -0.290179 0.030000 -0.126595
+v -0.293754 -0.030000 -0.112781
+v -0.293754 0.030000 -0.112781
+v -0.296782 -0.030000 -0.098143
+v -0.296782 0.030000 -0.098143
+v -0.299263 -0.030000 -0.082682
+v -0.299263 0.030000 -0.082682
+v -0.301194 -0.030000 -0.066397
+v -0.301194 0.030000 -0.066397
+v -0.302575 -0.030000 -0.049288
+v -0.302575 0.030000 -0.049288
+v -0.303404 -0.030000 -0.031357
+v -0.303404 0.030000 -0.031357
+v -0.303681 -0.030000 -0.012601
+v -0.303681 0.030000 -0.012601
+v -0.303411 -0.030000 0.006061
+v -0.303411 0.030000 0.006061
+v -0.302602 -0.030000 0.023884
+v -0.302602 0.030000 0.023884
+v -0.301253 -0.030000 0.040864
+v -0.301253 0.030000 0.040864
+v -0.299364 -0.030000 0.056999
+v -0.299364 0.030000 0.056999
+v -0.296935 -0.030000 0.072288
+v -0.296935 0.030000 0.072288
+v -0.293967 -0.030000 0.086726
+v -0.293967 0.030000 0.086726
+v -0.290460 -0.030000 0.100313
+v -0.290460 0.030000 0.100313
+v -0.286412 -0.030000 0.113046
+v -0.286412 0.030000 0.113046
+v -0.281825 -0.030000 0.124922
+v -0.281825 0.030000 0.124922
+v -0.276698 -0.030000 0.135939
+v -0.276698 0.030000 0.135939
+v -0.271032 -0.030000 0.146095
+v -0.271032 0.030000 0.146095
+v -0.264826 -0.030000 0.155387
+v -0.264826 0.030000 0.155387
+v -0.257932 -0.030000 0.163877
+v -0.257932 0.030000 0.163877
+v -0.250200 -0.030000 0.171629
+v -0.250200 0.030000 0.171629
+v -0.241634 -0.030000 0.178643
+v -0.241634 0.030000 0.178643
+v -0.232233 -0.030000 0.184918
+v -0.232233 0.030000 0.184918
+v -0.221998 -0.030000 0.190455
+v -0.221998 0.030000 0.190455
+v -0.210932 -0.030000 0.195254
+v -0.210932 0.030000 0.195254
+v -0.199035 -0.030000 0.199315
+v -0.199035 0.030000 0.199315
+v -0.186309 -0.030000 0.202637
+v -0.186309 0.030000 0.202637
+v -0.172754 -0.030000 0.205221
+v -0.172754 0.030000 0.205221
+v -0.158371 -0.030000 0.207067
+v -0.158371 0.030000 0.207067
+v -0.143163 -0.030000 0.208174
+v -0.143163 0.030000 0.208174
+v -0.127130 -0.030000 0.208543
+v -0.127130 0.030000 0.208543
+v -0.122805 -0.030000 0.208515
+v -0.122805 0.030000 0.208515
+v -0.118691 -0.030000 0.208431
+v -0.118691 0.030000 0.208431
+v -0.114786 -0.030000 0.208293
+v -0.114786 0.030000 0.208293
+v -0.111086 -0.030000 0.208101
+v -0.111086 0.030000 0.208101
+v -0.107590 -0.030000 0.207858
+v -0.107590 0.030000 0.207858
+v -0.104294 -0.030000 0.207563
+v -0.104294 0.030000 0.207563
+v -0.101198 -0.030000 0.207219
+v -0.101198 0.030000 0.207219
+v -0.098298 -0.030000 0.206827
+v -0.098298 0.030000 0.206827
+v -0.095593 -0.030000 0.206387
+v -0.095593 0.030000 0.206387
+v -0.093079 -0.030000 0.205901
+v -0.093079 0.030000 0.205901
+v -0.090754 -0.030000 0.205370
+v -0.090754 0.030000 0.205370
+v -0.088616 -0.030000 0.204795
+v -0.088616 0.030000 0.204795
+v -0.032379 -0.030000 0.297137
+v -0.032379 0.030000 0.297137
+v 0.032720 -0.030000 0.266811
+v 0.032720 0.030000 0.266811
+v 0.027981 -0.030000 0.259139
+v 0.027981 0.030000 0.259139
+v 0.022692 -0.030000 0.250576
+v 0.022692 0.030000 0.250576
+v 0.017036 -0.030000 0.241420
+v 0.017036 0.030000 0.241420
+v 0.011197 -0.030000 0.231966
+v 0.011197 0.030000 0.231966
+v 0.005358 -0.030000 0.222513
+v 0.005358 0.030000 0.222513
+v -0.000298 -0.030000 0.213356
+v -0.000298 0.030000 0.213356
+v -0.005587 -0.030000 0.204794
+v -0.005587 0.030000 0.204794
+v -0.010326 -0.030000 0.197122
+v -0.010326 0.030000 0.197122
+v -0.014331 -0.030000 0.190638
+v -0.014331 0.030000 0.190638
+v -0.017419 -0.030000 0.185639
+v -0.017419 0.030000 0.185639
+v -0.019406 -0.030000 0.182422
+v -0.019406 0.030000 0.182422
+v -0.020109 -0.030000 0.181283
+v -0.020109 0.030000 0.181283
+v 0.291411 -0.030000 0.137327
+v 0.291411 0.030000 0.137327
+v 0.286764 -0.030000 0.137511
+v 0.286764 0.030000 0.137511
+v 0.281577 -0.030000 0.137715
+v 0.281577 0.030000 0.137715
+v 0.276031 -0.030000 0.137934
+v 0.276031 0.030000 0.137934
+v 0.270305 -0.030000 0.138160
+v 0.270305 0.030000 0.138160
+v 0.264578 -0.030000 0.138386
+v 0.264578 0.030000 0.138386
+v 0.259032 -0.030000 0.138605
+v 0.259032 0.030000 0.138605
+v 0.253845 -0.030000 0.138810
+v 0.253845 0.030000 0.138810
+v 0.249198 -0.030000 0.138993
+v 0.249198 0.030000 0.138993
+v 0.245271 -0.030000 0.139148
+v 0.245271 0.030000 0.139148
+v 0.242243 -0.030000 0.139267
+v 0.242243 0.030000 0.139267
+v 0.240294 -0.030000 0.139344
+v 0.240294 0.030000 0.139344
+v 0.239605 -0.030000 0.139372
+v 0.239605 0.030000 0.139372
+v 0.235884 -0.030000 0.139286
+v 0.235884 0.030000 0.139286
+v 0.232394 -0.030000 0.139029
+v 0.232394 0.030000 0.139029
+v 0.229135 -0.030000 0.138600
+v 0.229135 0.030000 0.138600
+v 0.226110 -0.030000 0.137996
+v 0.226110 0.030000 0.137996
+v 0.223322 -0.030000 0.137217
+v 0.223322 0.030000 0.137217
+v 0.220774 -0.030000 0.136262
+v 0.220774 0.030000 0.136262
+v 0.218466 -0.030000 0.135130
+v 0.218466 0.030000 0.135130
+v 0.216403 -0.030000 0.133819
+v 0.216403 0.030000 0.133819
+v 0.214585 -0.030000 0.132328
+v 0.214585 0.030000 0.132328
+v 0.213017 -0.030000 0.130656
+v 0.213017 0.030000 0.130656
+v 0.211699 -0.030000 0.128802
+v 0.211699 0.030000 0.128802
+v 0.210634 -0.030000 0.126764
+v 0.210634 0.030000 0.126764
+v 0.209732 -0.030000 0.124535
+v 0.209732 0.030000 0.124535
+v 0.208903 -0.030000 0.121937
+v 0.208903 0.030000 0.121937
+v 0.208147 -0.030000 0.118969
+v 0.208147 0.030000 0.118969
+v 0.207465 -0.030000 0.115633
+v 0.207465 0.030000 0.115633
+v 0.206860 -0.030000 0.111927
+v 0.206860 0.030000 0.111927
+v 0.206331 -0.030000 0.107853
+v 0.206331 0.030000 0.107853
+v 0.205880 -0.030000 0.103409
+v 0.205880 0.030000 0.103409
+v 0.205509 -0.030000 0.098596
+v 0.205509 0.030000 0.098596
+v 0.205218 -0.030000 0.093413
+v 0.205218 0.030000 0.093413
+v 0.205009 -0.030000 0.087862
+v 0.205009 0.030000 0.087862
+v 0.204882 -0.030000 0.081942
+v 0.204882 0.030000 0.081942
+v 0.204840 -0.030000 0.075652
+v 0.204840 0.030000 0.075652
+v 0.204840 -0.030000 -0.063713
+v 0.204840 0.030000 -0.063713
+v 0.292093 -0.030000 -0.063713
+v 0.292093 0.030000 -0.063713
+v 0.292093 -0.030000 -0.122662
+v 0.292093 0.030000 -0.122662
+v 0.204840 -0.030000 -0.122662
+v 0.204840 0.030000 -0.122662
+v 0.204840 -0.030000 -0.214664
+v 0.204840 0.030000 -0.214664
+v 0.136333 -0.030000 -0.214664
+v 0.136333 0.030000 -0.214664
+v 0.136333 -0.030000 -0.122662
+v 0.136333 0.030000 -0.122662
+v 0.087935 -0.030000 -0.122662
+v 0.087935 0.030000 -0.122662
+v 0.087935 -0.030000 -0.064054
+v 0.087935 0.030000 -0.064054
+v 0.136333 -0.030000 -0.064054
+v 0.136333 0.030000 -0.064054
+v 0.136333 -0.030000 -0.050850
+v 0.136333 0.030000 -0.050850
+v 0.136333 -0.030000 -0.036113
+v 0.136333 0.030000 -0.036113
+v 0.136333 -0.030000 -0.020353
+v 0.136333 0.030000 -0.020353
+v 0.136333 -0.030000 -0.004083
+v 0.136333 0.030000 -0.004083
+v 0.136333 -0.030000 0.012188
+v 0.136333 0.030000 0.012188
+v 0.136333 -0.030000 0.027947
+v 0.136333 0.030000 0.027947
+v 0.136333 -0.030000 0.042685
+v 0.136333 0.030000 0.042685
+v 0.136333 -0.030000 0.055889
+v 0.136333 0.030000 0.055889
+v 0.136333 -0.030000 0.067048
+v 0.136333 0.030000 0.067048
+v 0.136333 -0.030000 0.075652
+v 0.136333 0.030000 0.075652
+v 0.136333 -0.030000 0.081189
+v 0.136333 0.030000 0.081189
+v 0.136333 -0.030000 0.083148
+v 0.136333 0.030000 0.083148
+v 0.136475 -0.030000 0.094258
+v 0.136475 0.030000 0.094258
+v 0.136899 -0.030000 0.104757
+v 0.136899 0.030000 0.104757
+v 0.137605 -0.030000 0.114646
+v 0.137605 0.030000 0.114646
+v 0.138592 -0.030000 0.123924
+v 0.138592 0.030000 0.123924
+v 0.139858 -0.030000 0.132592
+v 0.139858 0.030000 0.132592
+v 0.141403 -0.030000 0.140649
+v 0.141403 0.030000 0.140649
+v 0.143224 -0.030000 0.148096
+v 0.143224 0.030000 0.148096
+v 0.145321 -0.030000 0.154932
+v 0.145321 0.030000 0.154932
+v 0.147692 -0.030000 0.161158
+v 0.147692 0.030000 0.161158
+v 0.150337 -0.030000 0.166773
+v 0.150337 0.030000 0.166773
+v 0.153254 -0.030000 0.171778
+v 0.153254 0.030000 0.171778
+v 0.156442 -0.030000 0.176172
+v 0.156442 0.030000 0.176172
+v 0.159999 -0.030000 0.180091
+v 0.159999 0.030000 0.180091
+v 0.164025 -0.030000 0.183669
+v 0.164025 0.030000 0.183669
+v 0.168520 -0.030000 0.186906
+v 0.168520 0.030000 0.186906
+v 0.173483 -0.030000 0.189802
+v 0.173483 0.030000 0.189802
+v 0.178915 -0.030000 0.192358
+v 0.178915 0.030000 0.192358
+v 0.184816 -0.030000 0.194573
+v 0.184816 0.030000 0.194573
+v 0.191185 -0.030000 0.196447
+v 0.191185 0.030000 0.196447
+v 0.198023 -0.030000 0.197980
+v 0.198023 0.030000 0.197980
+v 0.205330 -0.030000 0.199173
+v 0.205330 0.030000 0.199173
+v 0.213105 -0.030000 0.200024
+v 0.213105 0.030000 0.200024
+v 0.221349 -0.030000 0.200536
+v 0.221349 0.030000 0.200536
+v 0.230061 -0.030000 0.200706
+v 0.230061 0.030000 0.200706
+v 0.233945 -0.030000 0.200649
+v 0.233945 0.030000 0.200649
+v 0.238099 -0.030000 0.200479
+v 0.238099 0.030000 0.200479
+v 0.242523 -0.030000 0.200195
+v 0.242523 0.030000 0.200195
+v 0.247217 -0.030000 0.199797
+v 0.247217 0.030000 0.199797
+v 0.252180 -0.030000 0.199286
+v 0.252180 0.030000 0.199286
+v 0.257413 -0.030000 0.198662
+v 0.257413 0.030000 0.198662
+v 0.262916 -0.030000 0.197923
+v 0.262916 0.030000 0.197923
+v 0.268689 -0.030000 0.197071
+v 0.268689 0.030000 0.197071
+v 0.274732 -0.030000 0.196106
+v 0.274732 0.030000 0.196106
+v 0.281044 -0.030000 0.195027
+v 0.281044 0.030000 0.195027
+v 0.287626 -0.030000 0.193834
+v 0.287626 0.030000 0.193834
+v 0.294479 -0.030000 0.192528
+v 0.294479 0.030000 0.192528
+v -0.042504 -0.030000 -0.131451
+v -0.042504 0.030000 -0.131451
+v -0.039308 -0.030000 -0.123910
+v -0.039308 0.030000 -0.123910
+v -0.036421 -0.030000 -0.115714
+v -0.036421 0.030000 -0.115714
+v -0.033843 -0.030000 -0.106862
+v -0.033843 0.030000 -0.106862
+v -0.031573 -0.030000 -0.097352
+v -0.031573 0.030000 -0.097352
+v -0.029610 -0.030000 -0.087182
+v -0.029610 0.030000 -0.087182
+v -0.027952 -0.030000 -0.076353
+v -0.027952 0.030000 -0.076353
+v -0.026597 -0.030000 -0.064862
+v -0.026597 0.030000 -0.064862
+v -0.025546 -0.030000 -0.052708
+v -0.025546 0.030000 -0.052708
+v -0.024797 -0.030000 -0.039891
+v -0.024797 0.030000 -0.039891
+v -0.024348 -0.030000 -0.026409
+v -0.024348 0.030000 -0.026409
+v -0.024199 -0.030000 -0.012261
+v -0.024199 0.030000 -0.012261
+v -0.024348 -0.030000 0.001795
+v -0.024348 0.030000 0.001795
+v -0.024794 -0.030000 0.015166
+v -0.024794 0.030000 0.015166
+v -0.025536 -0.030000 0.027852
+v -0.025536 0.030000 0.027852
+v -0.026572 -0.030000 0.039848
+v -0.026572 0.030000 0.039848
+v -0.027902 -0.030000 0.051154
+v -0.027902 0.030000 0.051154
+v -0.029525 -0.030000 0.061767
+v -0.029525 0.030000 0.061767
+v -0.031438 -0.030000 0.071683
+v -0.031438 0.030000 0.071683
+v -0.033641 -0.030000 0.080902
+v -0.033641 0.030000 0.080902
+v -0.036133 -0.030000 0.089420
+v -0.036133 0.030000 0.089420
+v -0.038913 -0.030000 0.097236
+v -0.038913 0.030000 0.097236
+v -0.041979 -0.030000 0.104346
+v -0.041979 0.030000 0.104346
+v -0.045331 -0.030000 0.110749
+v -0.045331 0.030000 0.110749
+v -0.049179 -0.030000 0.116548
+v -0.049179 0.030000 0.116548
+v -0.053569 -0.030000 0.121850
+v -0.053569 0.030000 0.121850
+v -0.058501 -0.030000 0.126652
+v -0.058501 0.030000 0.126652
+v -0.063975 -0.030000 0.130954
+v -0.063975 0.030000 0.130954
+v -0.069995 -0.030000 0.134754
+v -0.069995 0.030000 0.134754
+v -0.076559 -0.030000 0.138051
+v -0.076559 0.030000 0.138051
+v -0.083671 -0.030000 0.140844
+v -0.083671 0.030000 0.140844
+v -0.091330 -0.030000 0.143132
+v -0.091330 0.030000 0.143132
+v -0.099539 -0.030000 0.144914
+v -0.099539 0.030000 0.144914
+v -0.108298 -0.030000 0.146188
+v -0.108298 0.030000 0.146188
+v -0.117608 -0.030000 0.146953
+v -0.117608 0.030000 0.146953
+v -0.127471 -0.030000 0.147209
+v -0.127471 0.030000 0.147209
+v -0.137341 -0.030000 0.146947
+v -0.137341 0.030000 0.146947
+v -0.146670 -0.030000 0.146161
+v -0.146670 0.030000 0.146161
+v -0.155456 -0.030000 0.144855
+v -0.155456 0.030000 0.144855
+v -0.163700 -0.030000 0.143031
+v -0.163700 0.030000 0.143031
+v -0.171399 -0.030000 0.140692
+v -0.171399 0.030000 0.140692
+v -0.178553 -0.030000 0.137838
+v -0.178553 0.030000 0.137838
+v -0.185160 -0.030000 0.134474
+v -0.185160 0.030000 0.134474
+v -0.191219 -0.030000 0.130601
+v -0.191219 0.030000 0.130601
+v -0.196729 -0.030000 0.126221
+v -0.196729 0.030000 0.126221
+v -0.201689 -0.030000 0.121337
+v -0.201689 0.030000 0.121337
+v -0.206097 -0.030000 0.115952
+v -0.206097 0.030000 0.115952
+v -0.209952 -0.030000 0.110067
+v -0.209952 0.030000 0.110067
+v -0.213382 -0.030000 0.103587
+v -0.213382 0.030000 0.103587
+v -0.216513 -0.030000 0.096412
+v -0.216513 0.030000 0.096412
+v -0.219346 -0.030000 0.088547
+v -0.219346 0.030000 0.088547
+v -0.221881 -0.030000 0.079993
+v -0.221881 0.030000 0.079993
+v -0.224118 -0.030000 0.070753
+v -0.224118 0.030000 0.070753
+v -0.226057 -0.030000 0.060830
+v -0.226057 0.030000 0.060830
+v -0.227697 -0.030000 0.050224
+v -0.227697 0.030000 0.050224
+v -0.229039 -0.030000 0.038940
+v -0.229039 0.030000 0.038940
+v -0.230083 -0.030000 0.026978
+v -0.230083 0.030000 0.026978
+v -0.230828 -0.030000 0.014343
+v -0.230828 0.030000 0.014343
+v -0.231276 -0.030000 0.001035
+v -0.231276 0.030000 0.001035
+v -0.231425 -0.030000 -0.012942
+v -0.231425 0.030000 -0.012942
+v -0.231269 -0.030000 -0.027005
+v -0.231269 0.030000 -0.027005
+v -0.230801 -0.030000 -0.040404
+v -0.230801 0.030000 -0.040404
+v -0.230024 -0.030000 -0.053140
+v -0.230024 0.030000 -0.053140
+v -0.228938 -0.030000 -0.065215
+v -0.228938 0.030000 -0.065215
+v -0.227544 -0.030000 -0.076633
+v -0.227544 0.030000 -0.076633
+v -0.225844 -0.030000 -0.087395
+v -0.225844 0.030000 -0.087395
+v -0.223838 -0.030000 -0.097504
+v -0.223838 0.030000 -0.097504
+v -0.221528 -0.030000 -0.106963
+v -0.221528 0.030000 -0.106963
+v -0.218915 -0.030000 -0.115773
+v -0.218915 0.030000 -0.115773
+v -0.216000 -0.030000 -0.123937
+v -0.216000 0.030000 -0.123937
+v -0.212785 -0.030000 -0.131458
+v -0.212785 0.030000 -0.131458
+v -0.209271 -0.030000 -0.138337
+v -0.209271 0.030000 -0.138337
+v -0.205266 -0.030000 -0.144620
+v -0.205266 0.030000 -0.144620
+v -0.200750 -0.030000 -0.150350
+v -0.200750 0.030000 -0.150350
+v -0.195723 -0.030000 -0.155529
+v -0.195723 0.030000 -0.155529
+v -0.190184 -0.030000 -0.160157
+v -0.190184 0.030000 -0.160157
+v -0.184134 -0.030000 -0.164237
+v -0.184134 0.030000 -0.164237
+v -0.177573 -0.030000 -0.167769
+v -0.177573 0.030000 -0.167769
+v -0.170501 -0.030000 -0.170754
+v -0.170501 0.030000 -0.170754
+v -0.162917 -0.030000 -0.173194
+v -0.162917 0.030000 -0.173194
+v -0.154823 -0.030000 -0.175090
+v -0.154823 0.030000 -0.175090
+v -0.146217 -0.030000 -0.176442
+v -0.146217 0.030000 -0.176442
+v -0.137100 -0.030000 -0.177253
+v -0.137100 0.030000 -0.177253
+v -0.127471 -0.030000 -0.177523
+v -0.127471 0.030000 -0.177523
+v -0.117843 -0.030000 -0.177253
+v -0.117843 0.030000 -0.177253
+v -0.108727 -0.030000 -0.176442
+v -0.108727 0.030000 -0.176442
+v -0.100125 -0.030000 -0.175090
+v -0.100125 0.030000 -0.175090
+v -0.092037 -0.030000 -0.173194
+v -0.092037 0.030000 -0.173194
+v -0.084466 -0.030000 -0.170754
+v -0.084466 0.030000 -0.170754
+v -0.077411 -0.030000 -0.167769
+v -0.077411 0.030000 -0.167769
+v -0.070875 -0.030000 -0.164237
+v -0.070875 0.030000 -0.164237
+v -0.064859 -0.030000 -0.160157
+v -0.064859 0.030000 -0.160157
+v -0.059363 -0.030000 -0.155529
+v -0.059363 0.030000 -0.155529
+v -0.054389 -0.030000 -0.150350
+v -0.054389 0.030000 -0.150350
+v -0.049939 -0.030000 -0.144620
+v -0.049939 0.030000 -0.144620
+v -0.046012 -0.030000 -0.138337
+v -0.046012 0.030000 -0.138337
+vn 0.0000 1.0000 0.0000
+vn 0.0000 0.0000 1.0000
+vn 0.0000 0.0000 -1.0000
+vn 0.0000 -1.0000 0.0000
+vn 0.0000 -1.0000 -0.0001
+vn 0.0000 -1.0000 0.0001
+vn 1.0000 0.0000 0.0000
+vn 0.9238 0.0000 0.3827
+vn 0.3826 0.0000 0.9239
+vn -0.7071 0.0000 0.7071
+vn -1.0000 0.0000 0.0000
+vn -0.9238 0.0000 -0.3827
+vn -0.3826 0.0000 -0.9239
+vn 0.7071 0.0000 -0.7071
+vn -0.6478 0.0000 -0.7618
+vn -0.6020 0.0000 -0.7985
+vn -0.6914 0.0000 -0.7224
+vn -0.7324 0.0000 -0.6808
+vn -0.7705 0.0000 -0.6374
+vn -0.8053 0.0000 -0.5929
+vn -0.8367 0.0000 -0.5477
+vn -0.8647 0.0000 -0.5023
+vn -0.8367 0.0000 -0.5476
+vn -0.8892 0.0000 -0.4574
+vn -0.9106 0.0000 -0.4133
+vn -0.9289 0.0000 -0.3704
+vn -0.9452 0.0000 -0.3264
+vn -0.9584 0.0000 -0.2854
+vn -0.9682 0.0000 -0.2502
+vn -0.9761 0.0000 -0.2172
+vn -0.9825 0.0000 -0.1863
+vn -0.9875 0.0000 -0.1574
+vn -0.9915 0.0000 -0.1304
+vn -0.9944 0.0000 -0.1050
+vn -0.9967 0.0000 -0.0813
+vn -0.9982 0.0000 -0.0591
+vn -0.9993 0.0000 -0.0382
+vn -0.9998 0.0000 -0.0186
+vn -1.0000 0.0000 0.0026
+vn -0.9995 0.0000 0.0297
+vn -0.9981 0.0000 0.0618
+vn -0.9953 0.0000 0.0970
+vn -0.9908 0.0000 0.1356
+vn -0.9840 0.0000 0.1778
+vn -0.9746 0.0000 0.2239
+vn -0.9617 0.0000 0.2741
+vn -0.9445 0.0000 0.3285
+vn -0.9221 0.0000 0.3869
+vn -0.8935 0.0000 0.4490
+vn -0.8577 0.0000 0.5142
+vn -0.8146 0.0000 0.5800
+vn -0.7588 0.0000 0.6513
+vn -0.6894 0.0000 0.7244
+vn -0.6139 0.0000 0.7894
+vn -0.5349 0.0000 0.8449
+vn -0.4550 0.0000 0.8905
+vn -0.3765 0.0000 0.9264
+vn -0.3013 0.0000 0.9535
+vn -0.2306 0.0000 0.9730
+vn -0.1650 0.0000 0.9863
+vn -0.1050 0.0000 0.9945
+vn -0.0502 0.0000 0.9987
+vn 0.0002 0.0000 1.0000
+vn 0.0510 0.0000 0.9987
+vn 0.1065 0.0000 0.9943
+vn 0.1672 0.0000 0.9859
+vn 0.2331 0.0000 0.9724
+vn 0.3039 0.0000 0.9527
+vn 0.3788 0.0000 0.9254
+vn 0.4567 0.0000 0.8896
+vn 0.5357 0.0000 0.8444
+vn 0.6135 0.0000 0.7896
+vn 0.6878 0.0000 0.7259
+vn 0.7561 0.0000 0.6544
+vn 0.8140 0.0000 0.5808
+vn 0.8588 0.0000 0.5123
+vn 0.8937 0.0000 0.4487
+vn 0.9217 0.0000 0.3878
+vn 0.9438 0.0000 0.3303
+vn 0.9610 0.0000 0.2765
+vn 0.9740 0.0000 0.2266
+vn 0.9836 0.0000 0.1805
+vn 0.9904 0.0000 0.1381
+vn 0.9951 0.0000 0.0991
+vn 0.9980 0.0000 0.0633
+vn 0.9995 0.0000 0.0305
+vn 1.0000 0.0000 0.0001
+vn 0.9995 0.0000 -0.0299
+vn 0.9980 0.0000 -0.0623
+vn 0.9952 0.0000 -0.0978
+vn 0.9906 0.0000 -0.1366
+vn 0.9838 0.0000 -0.1791
+vn 0.9742 0.0000 -0.2257
+vn 0.9610 0.0000 -0.2766
+vn 0.9434 0.0000 -0.3318
+vn 0.9203 0.0000 -0.3913
+vn 0.8905 0.0000 -0.4548
+vn 0.8531 0.0000 -0.5217
+vn 0.8048 0.0000 -0.5935
+vn 0.7431 0.0000 -0.6691
+vn 0.6716 0.0000 -0.7409
+vn 0.5950 0.0000 -0.8037
+vn 0.5161 0.0000 -0.8565
+vn 0.4372 0.0000 -0.8993
+vn 0.3607 0.0000 -0.9326
+vn 0.2880 0.0000 -0.9576
+vn 0.2200 0.0000 -0.9755
+vn 0.1573 0.0000 -0.9875
+vn 0.1000 0.0000 -0.9950
+vn 0.0478 0.0000 -0.9988
+vn 0.0082 0.0000 -0.9999
+vn -0.0134 0.0000 -0.9999
+vn -0.0279 0.0000 -0.9996
+vn -0.0435 0.0000 -0.9990
+vn -0.0606 0.0000 -0.9981
+vn -0.0792 0.0000 -0.9968
+vn -0.0997 0.0000 -0.9950
+vn -0.1223 0.0000 -0.9925
+vn -0.1473 0.0000 -0.9891
+vn -0.1752 0.0000 -0.9845
+vn -0.2063 0.0000 -0.9785
+vn -0.1751 0.0000 -0.9845
+vn -0.2412 0.0000 -0.9705
+vn 0.3714 0.0000 -0.9284
+vn 0.2897 0.0000 -0.9571
+vn -0.9580 0.0000 -0.2867
+vn -0.8508 0.0000 0.5255
+vn -0.9800 0.0000 -0.1990
+vn 0.0394 0.0000 0.9992
+vn -0.6727 0.0000 0.7399
+vn 0.0395 0.0000 0.9992
+vn 0.0083 0.0000 0.9999
+vn -0.0482 0.0000 0.9988
+vn 0.0082 0.0000 0.9999
+vn -0.1021 0.0000 0.9948
+vn -0.1633 0.0000 0.9866
+vn -0.2325 0.0000 0.9726
+vn -0.3102 0.0000 0.9507
+vn -0.3962 0.0000 0.9181
+vn -0.4892 0.0000 0.8722
+vn -0.5863 0.0000 0.8101
+vn -0.6832 0.0000 0.7302
+vn -0.7739 0.0000 0.6333
+vn -0.8527 0.0000 0.5224
+vn -0.9077 0.0000 0.4195
+vn -0.9405 0.0000 0.3398
+vn -0.9612 0.0000 0.2756
+vn -0.9747 0.0000 0.2235
+vn -0.9835 0.0000 0.1807
+vn -0.9894 0.0000 0.1450
+vn -0.9934 0.0000 0.1148
+vn -0.9960 0.0000 0.0889
+vn -0.9978 0.0000 0.0665
+vn -0.9989 0.0000 0.0468
+vn -0.9995 0.0000 0.0295
+vn -0.9999 0.0000 0.0140
+vn -1.0000 0.0000 0.0034
+vn -0.7071 0.0000 -0.7071
+vn 0.7071 0.0000 0.7071
+vn 1.0000 0.0000 -0.0064
+vn 0.9996 0.0000 -0.0266
+vn 0.9984 0.0000 -0.0558
+vn 0.9961 0.0000 -0.0885
+vn 0.9921 0.0000 -0.1252
+vn 0.9861 0.0000 -0.1664
+vn 0.9771 0.0000 -0.2129
+vn 0.9641 0.0000 -0.2655
+vn 0.9458 0.0000 -0.3248
+vn 0.8852 0.0000 -0.4653
+vn 0.8377 0.0000 -0.5461
+vn 0.7761 0.0000 -0.6306
+vn 0.7033 0.0000 -0.7108
+vn 0.6251 0.0000 -0.7805
+vn 0.5448 0.0000 -0.8385
+vn 0.4653 0.0000 -0.8851
+vn 0.3889 0.0000 -0.9213
+vn 0.3170 0.0000 -0.9484
+vn 0.2506 0.0000 -0.9680
+vn 0.3171 0.0000 -0.9484
+vn 0.1900 0.0000 -0.9817
+vn 0.1350 0.0000 -0.9908
+vn 0.0854 0.0000 -0.9963
+vn 0.0407 0.0000 -0.9991
+vn 0.0024 0.0000 -1.0000
+vn -0.0278 0.0000 -0.9996
+vn -0.0525 0.0000 -0.9986
+vn -0.0742 0.0000 -0.9972
+vn -0.0934 0.0000 -0.9956
+vn -0.1105 0.0000 -0.9939
+vn -0.1257 0.0000 -0.9920
+vn -0.1395 0.0000 -0.9902
+vn -0.1519 0.0000 -0.9884
+vn -0.1631 0.0000 -0.9866
+vn -0.1734 0.0000 -0.9848
+vn -0.1827 0.0000 -0.9832
+vn -0.7879 0.0000 -0.6158
+vn 0.9324 0.0000 -0.3614
+vn 0.9064 0.0000 -0.4223
+vn 0.9520 0.0000 -0.3060
+vn 0.9667 0.0000 -0.2559
+vn 0.9775 0.0000 -0.2109
+vn 0.9854 0.0000 -0.1705
+vn 0.9909 0.0000 -0.1342
+vn 0.9948 0.0000 -0.1016
+vn 0.9974 0.0000 -0.0723
+vn 0.9989 0.0000 -0.0458
+vn 0.9998 0.0000 -0.0219
+vn 0.9998 0.0000 0.0219
+vn 0.9989 0.0000 0.0458
+vn 0.9974 0.0000 0.0722
+vn 0.9948 0.0000 0.1014
+vn 0.9910 0.0000 0.1340
+vn 0.9854 0.0000 0.1703
+vn 0.9775 0.0000 0.2110
+vn 0.9665 0.0000 0.2567
+vn 0.9514 0.0000 0.3081
+vn 0.9307 0.0000 0.3657
+vn 0.9027 0.0000 0.4301
+vn 0.8607 0.0000 0.5090
+vn 0.8028 0.0000 0.5962
+vn 0.7350 0.0000 0.6781
+vn 0.6587 0.0000 0.7524
+vn 0.5766 0.0000 0.8170
+vn 0.4919 0.0000 0.8706
+vn 0.4076 0.0000 0.9131
+vn 0.3262 0.0000 0.9453
+vn 0.2493 0.0000 0.9684
+vn 0.1781 0.0000 0.9840
+vn 0.1130 0.0000 0.9936
+vn 0.0539 0.0000 0.9985
+vn -0.0003 0.0000 1.0000
+vn -0.0552 0.0000 0.9984
+vn -0.1155 0.0000 0.9933
+vn -0.1816 0.0000 0.9834
+vn -0.2536 0.0000 0.9673
+vn -0.1816 0.0000 0.9833
+vn -0.3309 0.0000 0.9436
+vn -0.4125 0.0000 0.9109
+vn -0.4968 0.0000 0.8679
+vn -0.5812 0.0000 0.8137
+vn -0.6629 0.0000 0.7487
+vn -0.7388 0.0000 0.6739
+vn -0.8063 0.0000 0.5915
+vn -0.8611 0.0000 0.5084
+vn -0.9008 0.0000 0.4342
+vn -0.9291 0.0000 0.3696
+vn -0.9502 0.0000 0.3116
+vn -0.9656 0.0000 0.2598
+vn -0.9769 0.0000 0.2135
+vn -0.9850 0.0000 0.1723
+vn -0.9908 0.0000 0.1355
+vn -0.9947 0.0000 0.1025
+vn -0.9973 0.0000 0.0729
+vn -0.9989 0.0000 0.0462
+vn -0.9997 0.0000 0.0221
+vn -1.0000 0.0000 -0.0002
+vn -0.9997 0.0000 -0.0229
+vn -0.9988 0.0000 -0.0479
+vn -0.9972 0.0000 -0.0753
+vn -0.9944 0.0000 -0.1054
+vn -0.9903 0.0000 -0.1386
+vn -0.9845 0.0000 -0.1754
+vn -0.9764 0.0000 -0.2159
+vn -0.9654 0.0000 -0.2608
+vn -0.9506 0.0000 -0.3104
+vn -0.9311 0.0000 -0.3648
+vn -0.9055 0.0000 -0.4243
+vn -0.8679 0.0000 -0.4968
+vn -0.8153 0.0000 -0.5790
+vn -0.7525 0.0000 -0.6586
+vn -0.6803 0.0000 -0.7329
+vn -0.6010 0.0000 -0.7992
+vn -0.5172 0.0000 -0.8559
+vn -0.4319 0.0000 -0.9019
+vn -0.3479 0.0000 -0.9375
+vn -0.2673 0.0000 -0.9636
+vn -0.1917 0.0000 -0.9814
+vn -0.1220 0.0000 -0.9925
+vn -0.0583 0.0000 -0.9983
+vn 0.0583 0.0000 -0.9983
+vn 0.1220 0.0000 -0.9925
+vn 0.1919 0.0000 -0.9814
+vn 0.2677 0.0000 -0.9635
+vn 0.3486 0.0000 -0.9373
+vn 0.4330 0.0000 -0.9014
+vn 0.5190 0.0000 -0.8548
+vn 0.6035 0.0000 -0.7973
+vn 0.6836 0.0000 -0.7298
+vn 0.7565 0.0000 -0.6539
+vn 0.8199 0.0000 -0.5724
+vn 0.8704 0.0000 -0.4924
+s off
+f 10//1 12//1 11//1
+f 10//1 13//1 12//1
+f 10//1 14//1 13//1
+f 10//1 1//1 14//1
+f 10//1 63//1 1//1
+f 63//1 62//1 1//1
+f 62//1 2//1 1//1
+f 61//1 2//1 62//1
+f 60//1 2//1 61//1
+f 10//1 64//1 63//1
+f 59//1 2//1 60//1
+f 10//1 65//1 64//1
+f 58//1 2//1 59//1
+f 10//1 66//1 65//1
+f 58//1 178//1 2//1
+f 178//1 176//1 2//1
+f 176//1 3//1 2//1
+f 57//1 178//1 58//1
+f 10//1 67//1 66//1
+f 56//1 178//1 57//1
+f 10//1 68//1 67//1
+f 9//1 75//1 10//1
+f 75//1 74//1 10//1
+f 74//1 73//1 10//1
+f 73//1 72//1 10//1
+f 72//1 71//1 10//1
+f 71//1 70//1 10//1
+f 70//1 69//1 10//1
+f 69//1 68//1 10//1
+f 55//1 178//1 56//1
+f 54//1 179//1 55//1
+f 179//1 178//1 55//1
+f 54//1 180//1 179//1
+f 177//1 176//1 178//1
+f 53//1 180//1 54//1
+f 52//1 180//1 53//1
+f 51//1 180//1 52//1
+f 50//1 180//1 51//1
+f 49//1 180//1 50//1
+f 314//1 316//1 315//1
+f 313//1 316//1 314//1
+f 313//1 317//1 316//1
+f 313//1 318//1 317//1
+f 312//1 318//1 313//1
+f 312//1 319//1 318//1
+f 311//1 319//1 312//1
+f 48//1 180//1 49//1
+f 9//1 76//1 75//1
+f 311//1 320//1 319//1
+f 310//1 320//1 311//1
+f 310//1 321//1 320//1
+f 309//1 321//1 310//1
+f 309//1 322//1 321//1
+f 308//1 322//1 309//1
+f 308//1 323//1 322//1
+f 307//1 323//1 308//1
+f 47//1 180//1 48//1
+f 9//1 77//1 76//1
+f 307//1 324//1 323//1
+f 306//1 324//1 307//1
+f 306//1 325//1 324//1
+f 305//1 325//1 306//1
+f 46//1 180//1 47//1
+f 9//1 78//1 77//1
+f 305//1 326//1 325//1
+f 304//1 326//1 305//1
+f 304//1 327//1 326//1
+f 303//1 327//1 304//1
+f 45//1 180//1 46//1
+f 9//1 79//1 78//1
+f 302//1 327//1 303//1
+f 302//1 232//1 327//1
+f 301//1 232//1 302//1
+f 301//1 233//1 232//1
+f 44//1 181//1 45//1
+f 181//1 180//1 45//1
+f 9//1 80//1 79//1
+f 300//1 233//1 301//1
+f 300//1 234//1 233//1
+f 44//1 182//1 181//1
+f 175//1 3//1 176//1
+f 299//1 234//1 300//1
+f 299//1 235//1 234//1
+f 43//1 182//1 44//1
+f 9//1 81//1 80//1
+f 298//1 235//1 299//1
+f 298//1 236//1 235//1
+f 42//1 182//1 43//1
+f 9//1 82//1 81//1
+f 297//1 236//1 298//1
+f 297//1 237//1 236//1
+f 296//1 237//1 297//1
+f 296//1 238//1 237//1
+f 41//1 182//1 42//1
+f 9//1 83//1 82//1
+f 295//1 238//1 296//1
+f 295//1 239//1 238//1
+f 40//1 182//1 41//1
+f 9//1 84//1 83//1
+f 294//1 239//1 295//1
+f 294//1 240//1 239//1
+f 40//1 183//1 182//1
+f 40//1 184//1 183//1
+f 173//1 175//1 174//1
+f 173//1 3//1 175//1
+f 293//1 240//1 294//1
+f 293//1 241//1 240//1
+f 40//1 185//1 184//1
+f 39//1 185//1 40//1
+f 9//1 85//1 84//1
+f 292//1 241//1 293//1
+f 292//1 242//1 241//1
+f 39//1 186//1 185//1
+f 38//1 186//1 39//1
+f 9//1 86//1 85//1
+f 291//1 242//1 292//1
+f 291//1 243//1 242//1
+f 38//1 187//1 186//1
+f 290//1 243//1 291//1
+f 37//1 187//1 38//1
+f 9//1 87//1 86//1
+f 290//1 244//1 243//1
+f 37//1 188//1 187//1
+f 36//1 188//1 37//1
+f 289//1 244//1 290//1
+f 289//1 245//1 244//1
+f 9//1 88//1 87//1
+f 35//1 188//1 36//1
+f 35//1 189//1 188//1
+f 288//1 245//1 289//1
+f 288//1 246//1 245//1
+f 34//1 189//1 35//1
+f 9//1 89//1 88//1
+f 287//1 246//1 288//1
+f 287//1 247//1 246//1
+f 34//1 190//1 189//1
+f 33//1 190//1 34//1
+f 286//1 247//1 287//1
+f 286//1 248//1 247//1
+f 9//1 90//1 89//1
+f 33//1 191//1 190//1
+f 32//1 191//1 33//1
+f 285//1 248//1 286//1
+f 285//1 249//1 248//1
+f 31//1 191//1 32//1
+f 31//1 192//1 191//1
+f 9//1 91//1 90//1
+f 284//1 249//1 285//1
+f 284//1 250//1 249//1
+f 30//1 192//1 31//1
+f 30//1 193//1 192//1
+f 283//1 250//1 284//1
+f 283//1 251//1 250//1
+f 9//1 92//1 91//1
+f 29//1 193//1 30//1
+f 29//1 194//1 193//1
+f 172//1 3//1 173//1
+f 282//1 251//1 283//1
+f 282//1 252//1 251//1
+f 29//1 195//1 194//1
+f 171//1 3//1 172//1
+f 29//1 196//1 195//1
+f 28//1 196//1 29//1
+f 9//1 93//1 92//1
+f 170//1 3//1 171//1
+f 281//1 252//1 282//1
+f 281//1 253//1 252//1
+f 27//1 196//1 28//1
+f 169//1 3//1 170//1
+f 27//1 197//1 196//1
+f 280//1 253//1 281//1
+f 280//1 254//1 253//1
+f 168//1 137//1 169//1
+f 137//1 3//1 169//1
+f 9//1 94//1 93//1
+f 26//1 197//1 27//1
+f 167//1 137//1 168//1
+f 279//1 254//1 280//1
+f 279//1 255//1 254//1
+f 26//1 198//1 197//1
+f 166//1 137//1 167//1
+f 25//1 198//1 26//1
+f 278//1 255//1 279//1
+f 278//1 256//1 255//1
+f 165//1 137//1 166//1
+f 9//1 95//1 94//1
+f 25//1 199//1 198//1
+f 164//1 137//1 165//1
+f 277//1 256//1 278//1
+f 277//1 257//1 256//1
+f 24//1 199//1 25//1
+f 163//1 137//1 164//1
+f 276//1 257//1 277//1
+f 276//1 258//1 257//1
+f 162//1 137//1 163//1
+f 24//1 200//1 199//1
+f 161//1 137//1 162//1
+f 23//1 200//1 24//1
+f 9//1 96//1 95//1
+f 275//1 258//1 276//1
+f 275//1 259//1 258//1
+f 160//1 137//1 161//1
+f 159//1 137//1 160//1
+f 274//1 259//1 275//1
+f 158//1 137//1 159//1
+f 274//1 260//1 259//1
+f 22//1 200//1 23//1
+f 157//1 137//1 158//1
+f 22//1 201//1 200//1
+f 156//1 137//1 157//1
+f 273//1 260//1 274//1
+f 273//1 261//1 260//1
+f 155//1 137//1 156//1
+f 9//1 97//1 96//1
+f 154//1 137//1 155//1
+f 153//1 137//1 154//1
+f 153//1 138//1 137//1
+f 231//1 3//1 137//1
+f 153//1 139//1 138//1
+f 153//1 140//1 139//1
+f 272//1 261//1 273//1
+f 153//1 141//1 140//1
+f 152//1 141//1 153//1
+f 272//1 262//1 261//1
+f 152//1 142//1 141//1
+f 152//1 143//1 142//1
+f 21//1 201//1 22//1
+f 151//1 143//1 152//1
+f 151//1 144//1 143//1
+f 151//1 145//1 144//1
+f 151//1 146//1 145//1
+f 150//1 146//1 151//1
+f 150//1 147//1 146//1
+f 150//1 148//1 147//1
+f 149//1 148//1 150//1
+f 21//1 202//1 201//1
+f 271//1 262//1 272//1
+f 271//1 263//1 262//1
+f 270//1 263//1 271//1
+f 270//1 264//1 263//1
+f 269//1 264//1 270//1
+f 269//1 265//1 264//1
+f 20//1 202//1 21//1
+f 9//1 98//1 97//1
+f 268//1 265//1 269//1
+f 268//1 266//1 265//1
+f 267//1 266//1 268//1
+f 20//1 203//1 202//1
+f 19//1 203//1 20//1
+f 19//1 204//1 203//1
+f 9//1 99//1 98//1
+f 18//1 204//1 19//1
+f 18//1 205//1 204//1
+f 17//1 205//1 18//1
+f 9//1 100//1 99//1
+f 17//1 206//1 205//1
+f 16//1 206//1 17//1
+f 9//1 101//1 100//1
+f 16//1 207//1 206//1
+f 15//1 207//1 16//1
+f 15//1 208//1 207//1
+f 136//1 208//1 15//1
+f 9//1 102//1 101//1
+f 136//1 209//1 208//1
+f 135//1 209//1 136//1
+f 134//1 209//1 135//1
+f 134//1 210//1 209//1
+f 9//1 103//1 102//1
+f 133//1 210//1 134//1
+f 133//1 211//1 210//1
+f 133//1 212//1 211//1
+f 9//1 104//1 103//1
+f 132//1 212//1 133//1
+f 132//1 213//1 212//1
+f 230//1 3//1 231//1
+f 229//1 3//1 230//1
+f 132//1 214//1 213//1
+f 228//1 3//1 229//1
+f 9//1 105//1 104//1
+f 227//1 3//1 228//1
+f 132//1 215//1 214//1
+f 226//1 3//1 227//1
+f 131//1 215//1 132//1
+f 225//1 3//1 226//1
+f 131//1 216//1 215//1
+f 224//1 3//1 225//1
+f 131//1 217//1 216//1
+f 223//1 3//1 224//1
+f 9//1 106//1 105//1
+f 222//1 3//1 223//1
+f 131//1 218//1 217//1
+f 221//1 3//1 222//1
+f 220//1 3//1 221//1
+f 131//1 219//1 218//1
+f 219//1 3//1 220//1
+f 131//1 3//1 219//1
+f 9//1 107//1 106//1
+f 130//1 3//1 131//1
+f 121//1 123//1 122//1
+f 9//1 108//1 107//1
+f 120//1 123//1 121//1
+f 119//1 123//1 120//1
+f 118//1 123//1 119//1
+f 117//1 123//1 118//1
+f 9//1 109//1 108//1
+f 116//1 123//1 117//1
+f 115//1 123//1 116//1
+f 114//1 123//1 115//1
+f 113//1 123//1 114//1
+f 9//1 110//1 109//1
+f 112//1 123//1 113//1
+f 111//1 123//1 112//1
+f 110//1 123//1 111//1
+f 9//1 123//1 110//1
+f 129//1 3//1 130//1
+f 128//1 3//1 129//1
+f 128//1 4//1 3//1
+f 127//1 4//1 128//1
+f 8//1 123//1 9//1
+f 126//1 4//1 127//1
+f 125//1 4//1 126//1
+f 124//1 4//1 125//1
+f 123//1 4//1 124//1
+f 7//1 123//1 8//1
+f 7//1 4//1 123//1
+f 6//2 4//2 7//2
+f 5//3 4//3 6//3
+f 339//4 337//4 338//4
+f 340//4 337//4 339//4
+f 341//4 337//4 340//4
+f 328//4 337//4 341//4
+f 390//4 337//4 328//4
+f 389//4 390//4 328//4
+f 329//4 389//4 328//4
+f 329//4 388//4 389//4
+f 329//4 387//4 388//4
+f 391//4 337//4 390//4
+f 329//4 386//4 387//4
+f 392//4 337//4 391//4
+f 329//4 385//4 386//4
+f 393//4 337//4 392//4
+f 505//4 385//4 329//4
+f 503//4 505//4 329//4
+f 330//4 503//4 329//4
+f 505//4 384//4 385//4
+f 394//4 337//4 393//4
+f 505//4 383//4 384//4
+f 395//4 337//4 394//4
+f 402//4 336//4 337//4
+f 401//4 402//4 337//4
+f 400//4 401//4 337//4
+f 399//4 400//4 337//4
+f 398//4 399//4 337//4
+f 397//4 398//4 337//4
+f 396//4 397//4 337//4
+f 395//4 396//4 337//4
+f 505//4 382//4 383//4
+f 506//4 381//4 382//4
+f 505//4 506//4 382//4
+f 507//4 381//4 506//4
+f 503//4 504//4 505//4
+f 507//4 380//4 381//4
+f 507//4 379//4 380//4
+f 507//4 378//4 379//4
+f 507//4 377//4 378//4
+f 507//4 376//4 377//4
+f 643//4 641//4 642//4
+f 643//4 640//4 641//4
+f 644//4 640//4 643//4
+f 645//4 640//4 644//4
+f 645//4 639//4 640//4
+f 646//4 639//4 645//4
+f 646//4 638//4 639//4
+f 507//4 375//4 376//4
+f 403//4 336//4 402//4
+f 647//4 638//4 646//4
+f 647//4 637//4 638//4
+f 648//4 637//4 647//4
+f 648//4 636//4 637//4
+f 649//4 636//4 648//4
+f 649//4 635//4 636//4
+f 650//4 635//4 649//4
+f 650//4 634//4 635//4
+f 507//4 374//4 375//4
+f 404//4 336//4 403//4
+f 651//4 634//4 650//4
+f 651//4 633//4 634//4
+f 652//4 633//4 651//4
+f 652//4 632//4 633//4
+f 507//4 373//4 374//4
+f 405//4 336//4 404//4
+f 653//4 632//4 652//4
+f 653//4 631//4 632//4
+f 654//4 631//4 653//4
+f 654//4 630//4 631//4
+f 507//4 372//4 373//4
+f 406//4 336//4 405//4
+f 654//4 629//4 630//4
+f 559//4 629//4 654//4
+f 559//4 628//4 629//4
+f 560//4 628//4 559//4
+f 508//4 371//4 372//4
+f 507//4 508//4 372//4
+f 407//4 336//4 406//4
+f 560//4 627//4 628//4
+f 561//4 627//4 560//4
+f 509//4 371//4 508//4
+f 330//4 502//4 503//4
+f 561//4 626//4 627//4
+f 562//4 626//4 561//4
+f 509//4 370//4 371//4
+f 408//4 336//4 407//4
+f 562//4 625//4 626//4
+f 563//4 625//4 562//4
+f 509//4 369//4 370//4
+f 409//4 336//4 408//4
+f 563//4 624//4 625//4
+f 564//4 624//4 563//4
+f 564//4 623//4 624//4
+f 565//4 623//4 564//4
+f 509//4 368//4 369//4
+f 410//4 336//4 409//4
+f 565//4 622//4 623//4
+f 566//4 622//4 565//4
+f 509//4 367//4 368//4
+f 411//4 336//4 410//4
+f 566//4 621//4 622//4
+f 567//4 621//4 566//4
+f 510//4 367//4 509//4
+f 511//4 367//4 510//4
+f 502//4 500//4 501//4
+f 330//4 500//4 502//4
+f 567//4 620//4 621//4
+f 568//4 620//4 567//4
+f 512//4 367//4 511//4
+f 512//4 366//4 367//4
+f 412//4 336//4 411//4
+f 568//4 619//4 620//4
+f 569//4 619//4 568//4
+f 513//4 366//4 512//4
+f 513//4 365//4 366//4
+f 413//4 336//4 412//4
+f 569//4 618//4 619//4
+f 570//4 618//4 569//4
+f 514//4 365//4 513//4
+f 570//4 617//4 618//4
+f 514//4 364//4 365//4
+f 414//4 336//4 413//4
+f 571//4 617//4 570//4
+f 515//4 364//4 514//4
+f 515//4 363//4 364//4
+f 571//4 616//4 617//4
+f 572//4 616//4 571//4
+f 415//4 336//4 414//4
+f 515//4 362//4 363//4
+f 516//4 362//4 515//4
+f 572//4 615//4 616//4
+f 573//4 615//4 572//4
+f 516//4 361//4 362//4
+f 416//4 336//4 415//4
+f 573//4 614//4 615//4
+f 574//4 614//4 573//4
+f 517//4 361//4 516//4
+f 517//4 360//4 361//4
+f 574//4 613//4 614//4
+f 575//4 613//4 574//4
+f 417//4 336//4 416//4
+f 518//4 360//4 517//4
+f 518//4 359//4 360//4
+f 575//4 612//4 613//4
+f 576//4 612//4 575//4
+f 518//4 358//4 359//4
+f 519//4 358//4 518//4
+f 418//4 336//4 417//4
+f 576//4 611//4 612//4
+f 577//4 611//4 576//4
+f 519//4 357//4 358//4
+f 520//4 357//4 519//4
+f 577//4 610//4 611//4
+f 578//4 610//4 577//4
+f 419//4 336//4 418//4
+f 520//4 356//4 357//4
+f 521//4 356//4 520//4
+f 330//4 499//4 500//4
+f 578//4 609//4 610//4
+f 579//4 609//4 578//4
+f 522//4 356//4 521//4
+f 330//4 498//4 499//4
+f 523//4 356//4 522//4
+f 523//4 355//4 356//4
+f 420//4 336//4 419//4
+f 330//4 497//4 498//4
+f 579//4 608//4 609//4
+f 580//4 608//4 579//4
+f 523//4 354//4 355//4
+f 330//4 496//4 497//4
+f 524//4 354//4 523//4
+f 580//4 607//4 608//4
+f 581//4 607//4 580//4
+f 464//4 495//4 496//4
+f 330//4 464//4 496//4
+f 421//4 336//4 420//4
+f 524//4 353//4 354//4
+f 464//4 494//4 495//4
+f 581//4 606//4 607//4
+f 582//4 606//4 581//4
+f 525//4 353//4 524//4
+f 464//4 493//4 494//4
+f 525//4 352//4 353//4
+f 582//4 605//4 606//4
+f 583//4 605//4 582//4
+f 464//4 492//4 493//4
+f 422//4 336//4 421//4
+f 526//4 352//4 525//4
+f 464//4 491//4 492//4
+f 583//4 604//4 605//4
+f 584//4 604//4 583//4
+f 526//4 351//4 352//4
+f 464//4 490//4 491//4
+f 584//4 603//4 604//4
+f 585//4 603//4 584//4
+f 464//4 489//4 490//4
+f 527//4 351//4 526//4
+f 464//4 488//4 489//4
+f 527//4 350//4 351//4
+f 423//4 336//4 422//4
+f 585//4 602//4 603//4
+f 586//4 602//4 585//4
+f 464//4 487//4 488//4
+f 464//4 486//4 487//4
+f 586//4 601//4 602//4
+f 464//4 485//4 486//4
+f 587//4 601//4 586//4
+f 527//4 349//4 350//4
+f 464//4 484//4 485//4
+f 528//4 349//4 527//4
+f 464//4 483//4 484//4
+f 587//4 600//4 601//4
+f 588//4 600//4 587//4
+f 464//4 482//4 483//4
+f 424//4 336//4 423//4
+f 464//4 481//4 482//4
+f 464//4 480//4 481//4
+f 465//4 480//4 464//4
+f 330//4 558//4 464//4
+f 466//4 480//4 465//4
+f 467//4 480//4 466//4
+f 588//4 599//4 600//4
+f 468//4 480//4 467//4
+f 468//4 479//4 480//4
+f 589//4 599//4 588//4
+f 469//4 479//4 468//4
+f 470//4 479//4 469//4
+f 528//4 348//4 349//4
+f 470//4 478//4 479//4
+f 471//4 478//4 470//4
+f 472//4 478//4 471//4
+f 473//4 478//4 472//4
+f 473//4 477//4 478//4
+f 474//4 477//4 473//4
+f 475//5 477//5 474//5
+f 475//6 476//6 477//6
+f 529//4 348//4 528//4
+f 589//4 598//4 599//4
+f 590//4 598//4 589//4
+f 590//4 597//4 598//4
+f 591//4 597//4 590//4
+f 591//4 596//4 597//4
+f 592//4 596//4 591//4
+f 529//4 347//4 348//4
+f 425//4 336//4 424//4
+f 592//4 595//4 596//4
+f 593//4 595//4 592//4
+f 593//4 594//4 595//4
+f 530//4 347//4 529//4
+f 530//4 346//4 347//4
+f 531//4 346//4 530//4
+f 426//4 336//4 425//4
+f 531//4 345//4 346//4
+f 532//4 345//4 531//4
+f 532//4 344//4 345//4
+f 427//4 336//4 426//4
+f 533//4 344//4 532//4
+f 533//4 343//4 344//4
+f 428//4 336//4 427//4
+f 534//4 343//4 533//4
+f 534//4 342//4 343//4
+f 535//4 342//4 534//4
+f 535//4 463//4 342//4
+f 429//4 336//4 428//4
+f 536//4 463//4 535//4
+f 536//4 462//4 463//4
+f 536//4 461//4 462//4
+f 537//4 461//4 536//4
+f 430//4 336//4 429//4
+f 537//4 460//4 461//4
+f 538//4 460//4 537//4
+f 539//4 460//4 538//4
+f 431//4 336//4 430//4
+f 539//4 459//4 460//4
+f 540//4 459//4 539//4
+f 330//4 557//4 558//4
+f 330//4 556//4 557//4
+f 541//4 459//4 540//4
+f 330//4 555//4 556//4
+f 432//4 336//4 431//4
+f 330//4 554//4 555//4
+f 542//4 459//4 541//4
+f 330//4 553//4 554//4
+f 542//4 458//4 459//4
+f 330//4 552//4 553//4
+f 543//4 458//4 542//4
+f 330//4 551//4 552//4
+f 544//4 458//4 543//4
+f 330//4 550//4 551//4
+f 433//4 336//4 432//4
+f 330//4 549//4 550//4
+f 545//4 458//4 544//4
+f 330//4 548//4 549//4
+f 330//4 547//4 548//4
+f 546//4 458//4 545//4
+f 330//4 546//4 547//4
+f 330//4 458//4 546//4
+f 434//4 336//4 433//4
+f 330//4 457//4 458//4
+f 450//4 448//4 449//4
+f 435//4 336//4 434//4
+f 450//4 447//4 448//4
+f 450//4 446//4 447//4
+f 450//4 445//4 446//4
+f 450//4 444//4 445//4
+f 436//4 336//4 435//4
+f 450//4 443//4 444//4
+f 450//4 442//4 443//4
+f 450//4 441//4 442//4
+f 450//4 440//4 441//4
+f 437//4 336//4 436//4
+f 450//4 439//4 440//4
+f 450//4 438//4 439//4
+f 450//4 437//4 438//4
+f 450//4 336//4 437//4
+f 330//4 456//4 457//4
+f 330//4 455//4 456//4
+f 331//4 455//4 330//4
+f 331//4 454//4 455//4
+f 450//4 335//4 336//4
+f 331//4 453//4 454//4
+f 331//4 452//4 453//4
+f 331//4 451//4 452//4
+f 331//4 450//4 451//4
+f 450//4 334//4 335//4
+f 331//4 334//4 450//4
+f 331//2 333//2 334//2
+f 331//3 332//3 333//3
+s 1
+f 658//7 655//7 656//7
+f 660//8 657//7 658//7
+f 662//9 659//8 660//8
+f 664//2 661//9 662//9
+f 666//2 663//2 664//2
+f 668//10 665//2 666//2
+f 670//11 667//10 668//10
+f 672//11 669//11 670//11
+f 674//12 671//11 672//11
+f 676//13 673//12 674//12
+f 678//3 675//13 676//13
+f 680//3 677//3 678//3
+f 682//14 679//3 680//3
+f 656//7 681//14 682//14
+f 686//15 683//16 684//16
+f 688//17 685//15 686//15
+f 690//18 687//17 688//17
+f 692//19 689//18 690//18
+f 694//20 691//19 692//19
+f 696//21 693//20 694//20
+f 698//22 695//23 696//21
+f 700//24 697//22 698//22
+f 702//25 699//24 700//24
+f 704//26 701//25 702//25
+f 706//27 703//26 704//26
+f 708//28 705//27 706//27
+f 710//29 707//28 708//28
+f 712//30 709//29 710//29
+f 714//31 711//30 712//30
+f 716//32 713//31 714//31
+f 718//33 715//32 716//32
+f 720//34 717//33 718//33
+f 722//35 719//34 720//34
+f 724//36 721//35 722//35
+f 726//37 723//36 724//36
+f 728//38 725//37 726//37
+f 730//39 727//38 728//38
+f 732//40 729//39 730//39
+f 734//41 731//40 732//40
+f 736//42 733//41 734//41
+f 738//43 735//42 736//42
+f 740//44 737//43 738//43
+f 742//45 739//44 740//44
+f 744//46 741//45 742//45
+f 746//47 743//46 744//46
+f 748//48 745//47 746//47
+f 750//49 747//48 748//48
+f 752//50 749//49 750//49
+f 754//51 751//50 752//50
+f 756//52 753//51 754//51
+f 758//53 755//52 756//52
+f 760//54 757//53 758//53
+f 762//55 759//54 760//54
+f 764//56 761//55 762//55
+f 766//57 763//56 764//56
+f 768//58 765//57 766//57
+f 770//59 767//58 768//58
+f 772//60 769//59 770//59
+f 774//61 771//60 772//60
+f 776//62 773//61 774//61
+f 778//63 775//62 776//62
+f 780//64 777//63 778//63
+f 782//65 779//64 780//64
+f 784//66 781//65 782//65
+f 786//67 783//66 784//66
+f 788//68 785//67 786//67
+f 790//69 787//68 788//68
+f 792//70 789//69 790//69
+f 794//71 791//70 792//70
+f 796//72 793//71 794//71
+f 798//73 795//72 796//72
+f 800//74 797//73 798//73
+f 802//75 799//74 800//74
+f 804//76 801//75 802//75
+f 806//77 803//76 804//76
+f 808//78 805//77 806//77
+f 810//79 807//78 808//78
+f 812//80 809//79 810//79
+f 814//81 811//80 812//80
+f 816//82 813//81 814//81
+f 818//83 815//82 816//82
+f 820//84 817//83 818//83
+f 822//85 819//84 820//84
+f 824//86 821//85 822//85
+f 826//87 823//86 824//86
+f 828//88 825//87 826//87
+f 830//89 827//88 828//88
+f 832//90 829//89 830//89
+f 834//91 831//90 832//90
+f 836//92 833//91 834//91
+f 838//93 835//92 836//92
+f 840//94 837//93 838//93
+f 842//95 839//94 840//94
+f 844//96 841//95 842//95
+f 846//97 843//96 844//96
+f 848//98 845//97 846//97
+f 850//99 847//98 848//98
+f 852//100 849//99 850//99
+f 854//101 851//100 852//100
+f 856//102 853//101 854//101
+f 858//103 855//102 856//102
+f 860//104 857//103 858//103
+f 862//105 859//104 860//104
+f 864//106 861//105 862//105
+f 866//107 863//106 864//106
+f 868//108 865//107 866//107
+f 870//109 867//108 868//108
+f 872//110 869//109 870//109
+f 874//111 871//110 872//110
+f 876//112 873//111 874//111
+f 878//113 875//112 876//112
+f 880//114 877//113 878//113
+f 882//115 879//114 880//114
+f 884//116 881//115 882//115
+f 886//117 883//116 884//116
+f 888//118 885//117 886//117
+f 890//119 887//118 888//118
+f 892//120 889//119 890//119
+f 894//121 891//122 892//120
+f 896//123 893//121 894//121
+f 898//124 895//123 896//123
+f 900//125 897//124 898//124
+f 902//126 899//125 900//125
+f 904//127 901//126 902//126
+f 906//127 903//127 904//127
+f 908//127 905//127 906//127
+f 910//127 907//127 908//127
+f 912//127 909//127 910//127
+f 914//127 911//127 912//127
+f 916//127 913//127 914//127
+f 918//127 915//127 916//127
+f 920//127 917//127 918//127
+f 922//127 919//127 920//127
+f 924//127 921//127 922//127
+f 926//128 923//127 924//127
+f 684//16 925//128 926//128
+f 930//129 927//130 928//130
+f 932//129 929//129 930//129
+f 934//129 931//129 932//129
+f 936//129 933//129 934//129
+f 938//129 935//129 936//129
+f 940//129 937//129 938//129
+f 942//129 939//129 940//129
+f 944//129 941//129 942//129
+f 946//129 943//129 944//129
+f 948//129 945//129 946//129
+f 950//131 947//129 948//129
+f 952//132 949//129 950//131
+f 954//133 951//134 952//132
+f 956//135 953//133 954//133
+f 958//136 955//135 956//135
+f 960//137 957//136 958//136
+f 962//138 959//137 960//137
+f 964//139 961//138 962//138
+f 966//140 963//139 964//139
+f 968//141 965//140 966//140
+f 970//142 967//141 968//141
+f 972//143 969//142 970//142
+f 974//144 971//143 972//143
+f 976//145 973//144 974//144
+f 978//146 975//145 976//145
+f 980//147 977//146 978//146
+f 982//148 979//147 980//147
+f 984//149 981//148 982//148
+f 986//150 983//149 984//149
+f 988//151 985//150 986//150
+f 990//152 987//151 988//151
+f 992//153 989//152 990//152
+f 994//154 991//153 992//153
+f 996//155 993//154 994//154
+f 998//156 995//155 996//155
+f 1000//157 997//156 998//156
+f 1002//158 999//157 1000//157
+f 1004//158 1001//158 1002//158
+f 1006//10 1003//158 1004//158
+f 1008//10 1005//10 1006//10
+f 1010//10 1007//10 1008//10
+f 1012//159 1009//10 1010//10
+f 1014//159 1011//159 1012//159
+f 1016//159 1013//159 1014//159
+f 1018//14 1015//159 1016//159
+f 1020//14 1017//14 1018//14
+f 1022//7 1019//14 1020//14
+f 1024//7 1021//7 1022//7
+f 1026//7 1023//7 1024//7
+f 1028//7 1025//7 1026//7
+f 1030//7 1027//7 1028//7
+f 1032//7 1029//7 1030//7
+f 1034//7 1031//7 1032//7
+f 1036//7 1033//7 1034//7
+f 1038//7 1035//7 1036//7
+f 1040//7 1037//7 1038//7
+f 1042//7 1039//7 1040//7
+f 1044//160 1041//7 1042//7
+f 1046//161 1043//160 1044//160
+f 1048//162 1045//161 1046//161
+f 1050//163 1047//162 1048//162
+f 1052//164 1049//163 1050//163
+f 1054//165 1051//164 1052//164
+f 1056//166 1053//165 1054//165
+f 1058//167 1055//166 1056//166
+f 1060//168 1057//167 1058//167
+f 1062//96 1059//168 1060//168
+f 1064//169 1061//96 1062//96
+f 1066//170 1063//169 1064//169
+f 1068//171 1065//170 1066//170
+f 1070//172 1067//171 1068//171
+f 1072//173 1069//172 1070//172
+f 1074//174 1071//173 1072//173
+f 1076//175 1073//174 1074//174
+f 1078//176 1075//175 1076//175
+f 1080//177 1077//176 1078//176
+f 1082//178 1079//179 1080//177
+f 1084//180 1081//178 1082//178
+f 1086//181 1083//180 1084//180
+f 1088//182 1085//181 1086//181
+f 1090//183 1087//182 1088//182
+f 1092//184 1089//183 1090//183
+f 1094//185 1091//184 1092//184
+f 1096//186 1093//185 1094//185
+f 1098//187 1095//186 1096//186
+f 1100//188 1097//187 1098//187
+f 1102//189 1099//188 1100//188
+f 1104//190 1101//189 1102//189
+f 1106//191 1103//190 1104//190
+f 1108//192 1105//191 1106//191
+f 1110//193 1107//192 1108//192
+f 1112//194 1109//193 1110//193
+f 1114//195 1111//194 1112//194
+f 1116//196 1113//195 1114//195
+f 928//130 1115//196 1116//196
+f 1120//197 1117//198 1118//198
+f 1122//199 1119//197 1120//197
+f 1124//200 1121//199 1122//199
+f 1126//201 1123//200 1124//200
+f 1128//202 1125//201 1126//201
+f 1130//203 1127//202 1128//202
+f 1132//204 1129//203 1130//203
+f 1134//205 1131//204 1132//204
+f 1136//206 1133//205 1134//205
+f 1138//207 1135//206 1136//206
+f 1140//7 1137//207 1138//207
+f 1142//208 1139//7 1140//7
+f 1144//209 1141//208 1142//208
+f 1146//210 1143//209 1144//209
+f 1148//211 1145//210 1146//210
+f 1150//212 1147//211 1148//211
+f 1152//213 1149//212 1150//212
+f 1154//214 1151//213 1152//213
+f 1156//215 1153//214 1154//214
+f 1158//216 1155//215 1156//215
+f 1160//217 1157//216 1158//216
+f 1162//218 1159//217 1160//217
+f 1164//219 1161//218 1162//218
+f 1166//220 1163//219 1164//219
+f 1168//221 1165//220 1166//220
+f 1170//222 1167//221 1168//221
+f 1172//223 1169//222 1170//222
+f 1174//224 1171//223 1172//223
+f 1176//225 1173//224 1174//224
+f 1178//226 1175//225 1176//225
+f 1180//227 1177//226 1178//226
+f 1182//228 1179//227 1180//227
+f 1184//229 1181//228 1182//228
+f 1186//230 1183//229 1184//229
+f 1188//231 1185//230 1186//230
+f 1190//232 1187//231 1188//231
+f 1192//233 1189//232 1190//232
+f 1194//234 1191//233 1192//233
+f 1196//235 1193//236 1194//234
+f 1198//237 1195//235 1196//235
+f 1200//238 1197//237 1198//237
+f 1202//239 1199//238 1200//238
+f 1204//240 1201//239 1202//239
+f 1206//241 1203//240 1204//240
+f 1208//242 1205//241 1206//241
+f 1210//243 1207//242 1208//242
+f 1212//244 1209//243 1210//243
+f 1214//245 1211//244 1212//244
+f 1216//246 1213//245 1214//245
+f 1218//247 1215//246 1216//246
+f 1220//248 1217//247 1218//247
+f 1222//249 1219//248 1220//248
+f 1224//250 1221//249 1222//249
+f 1226//251 1223//250 1224//250
+f 1228//252 1225//251 1226//251
+f 1230//253 1227//252 1228//252
+f 1232//254 1229//253 1230//253
+f 1234//255 1231//254 1232//254
+f 1236//256 1233//255 1234//255
+f 1238//257 1235//256 1236//256
+f 1240//258 1237//257 1238//257
+f 1242//259 1239//258 1240//258
+f 1244//260 1241//259 1242//259
+f 1246//261 1243//260 1244//260
+f 1248//262 1245//261 1246//261
+f 1250//263 1247//262 1248//262
+f 1252//264 1249//263 1250//263
+f 1254//265 1251//264 1252//264
+f 1256//266 1253//265 1254//265
+f 1258//267 1255//266 1256//266
+f 1260//268 1257//267 1258//267
+f 1262//269 1259//268 1260//268
+f 1264//270 1261//269 1262//269
+f 1266//271 1263//270 1264//270
+f 1268//272 1265//271 1266//271
+f 1270//273 1267//272 1268//272
+f 1272//274 1269//273 1270//273
+f 1274//275 1271//274 1272//274
+f 1276//276 1273//275 1274//275
+f 1278//277 1275//276 1276//276
+f 1280//278 1277//277 1278//277
+f 1282//279 1279//278 1280//278
+f 1284//3 1281//279 1282//279
+f 1286//280 1283//3 1284//3
+f 1288//281 1285//280 1286//280
+f 1290//282 1287//281 1288//281
+f 1292//283 1289//282 1290//282
+f 1294//284 1291//283 1292//283
+f 1296//285 1293//284 1294//284
+f 1298//286 1295//285 1296//285
+f 1300//287 1297//286 1298//286
+f 1302//288 1299//287 1300//287
+f 1304//289 1301//288 1302//288
+f 1306//290 1303//289 1304//289
+f 1308//291 1305//290 1306//290
+f 1118//198 1307//291 1308//291
+f 658//7 657//7 655//7
+f 660//8 659//8 657//7
+f 662//9 661//9 659//8
+f 664//2 663//2 661//9
+f 666//2 665//2 663//2
+f 668//10 667//10 665//2
+f 670//11 669//11 667//10
+f 672//11 671//11 669//11
+f 674//12 673//12 671//11
+f 676//13 675//13 673//12
+f 678//3 677//3 675//13
+f 680//3 679//3 677//3
+f 682//14 681//14 679//3
+f 656//7 655//7 681//14
+f 686//15 685//15 683//16
+f 688//17 687//17 685//15
+f 690//18 689//18 687//17
+f 692//19 691//19 689//18
+f 694//20 693//20 691//19
+f 696//21 695//23 693//20
+f 698//22 697//22 695//23
+f 700//24 699//24 697//22
+f 702//25 701//25 699//24
+f 704//26 703//26 701//25
+f 706//27 705//27 703//26
+f 708//28 707//28 705//27
+f 710//29 709//29 707//28
+f 712//30 711//30 709//29
+f 714//31 713//31 711//30
+f 716//32 715//32 713//31
+f 718//33 717//33 715//32
+f 720//34 719//34 717//33
+f 722//35 721//35 719//34
+f 724//36 723//36 721//35
+f 726//37 725//37 723//36
+f 728//38 727//38 725//37
+f 730//39 729//39 727//38
+f 732//40 731//40 729//39
+f 734//41 733//41 731//40
+f 736//42 735//42 733//41
+f 738//43 737//43 735//42
+f 740//44 739//44 737//43
+f 742//45 741//45 739//44
+f 744//46 743//46 741//45
+f 746//47 745//47 743//46
+f 748//48 747//48 745//47
+f 750//49 749//49 747//48
+f 752//50 751//50 749//49
+f 754//51 753//51 751//50
+f 756//52 755//52 753//51
+f 758//53 757//53 755//52
+f 760//54 759//54 757//53
+f 762//55 761//55 759//54
+f 764//56 763//56 761//55
+f 766//57 765//57 763//56
+f 768//58 767//58 765//57
+f 770//59 769//59 767//58
+f 772//60 771//60 769//59
+f 774//61 773//61 771//60
+f 776//62 775//62 773//61
+f 778//63 777//63 775//62
+f 780//64 779//64 777//63
+f 782//65 781//65 779//64
+f 784//66 783//66 781//65
+f 786//67 785//67 783//66
+f 788//68 787//68 785//67
+f 790//69 789//69 787//68
+f 792//70 791//70 789//69
+f 794//71 793//71 791//70
+f 796//72 795//72 793//71
+f 798//73 797//73 795//72
+f 800//74 799//74 797//73
+f 802//75 801//75 799//74
+f 804//76 803//76 801//75
+f 806//77 805//77 803//76
+f 808//78 807//78 805//77
+f 810//79 809//79 807//78
+f 812//80 811//80 809//79
+f 814//81 813//81 811//80
+f 816//82 815//82 813//81
+f 818//83 817//83 815//82
+f 820//84 819//84 817//83
+f 822//85 821//85 819//84
+f 824//86 823//86 821//85
+f 826//87 825//87 823//86
+f 828//88 827//88 825//87
+f 830//89 829//89 827//88
+f 832//90 831//90 829//89
+f 834//91 833//91 831//90
+f 836//92 835//92 833//91
+f 838//93 837//93 835//92
+f 840//94 839//94 837//93
+f 842//95 841//95 839//94
+f 844//96 843//96 841//95
+f 846//97 845//97 843//96
+f 848//98 847//98 845//97
+f 850//99 849//99 847//98
+f 852//100 851//100 849//99
+f 854//101 853//101 851//100
+f 856//102 855//102 853//101
+f 858//103 857//103 855//102
+f 860//104 859//104 857//103
+f 862//105 861//105 859//104
+f 864//106 863//106 861//105
+f 866//107 865//107 863//106
+f 868//108 867//108 865//107
+f 870//109 869//109 867//108
+f 872//110 871//110 869//109
+f 874//111 873//111 871//110
+f 876//112 875//112 873//111
+f 878//113 877//113 875//112
+f 880//114 879//114 877//113
+f 882//115 881//115 879//114
+f 884//116 883//116 881//115
+f 886//117 885//117 883//116
+f 888//118 887//118 885//117
+f 890//119 889//119 887//118
+f 892//120 891//122 889//119
+f 894//121 893//121 891//122
+f 896//123 895//123 893//121
+f 898//124 897//124 895//123
+f 900//125 899//125 897//124
+f 902//126 901//126 899//125
+f 904//127 903//127 901//126
+f 906//127 905//127 903//127
+f 908//127 907//127 905//127
+f 910//127 909//127 907//127
+f 912//127 911//127 909//127
+f 914//127 913//127 911//127
+f 916//127 915//127 913//127
+f 918//127 917//127 915//127
+f 920//127 919//127 917//127
+f 922//127 921//127 919//127
+f 924//127 923//127 921//127
+f 926//128 925//128 923//127
+f 684//16 683//16 925//128
+f 930//129 929//129 927//130
+f 932//129 931//129 929//129
+f 934//129 933//129 931//129
+f 936//129 935//129 933//129
+f 938//129 937//129 935//129
+f 940//129 939//129 937//129
+f 942//129 941//129 939//129
+f 944//129 943//129 941//129
+f 946//129 945//129 943//129
+f 948//129 947//129 945//129
+f 950//131 949//129 947//129
+f 952//132 951//134 949//129
+f 954//133 953//133 951//134
+f 956//135 955//135 953//133
+f 958//136 957//136 955//135
+f 960//137 959//137 957//136
+f 962//138 961//138 959//137
+f 964//139 963//139 961//138
+f 966//140 965//140 963//139
+f 968//141 967//141 965//140
+f 970//142 969//142 967//141
+f 972//143 971//143 969//142
+f 974//144 973//144 971//143
+f 976//145 975//145 973//144
+f 978//146 977//146 975//145
+f 980//147 979//147 977//146
+f 982//148 981//148 979//147
+f 984//149 983//149 981//148
+f 986//150 985//150 983//149
+f 988//151 987//151 985//150
+f 990//152 989//152 987//151
+f 992//153 991//153 989//152
+f 994//154 993//154 991//153
+f 996//155 995//155 993//154
+f 998//156 997//156 995//155
+f 1000//157 999//157 997//156
+f 1002//158 1001//158 999//157
+f 1004//158 1003//158 1001//158
+f 1006//10 1005//10 1003//158
+f 1008//10 1007//10 1005//10
+f 1010//10 1009//10 1007//10
+f 1012//159 1011//159 1009//10
+f 1014//159 1013//159 1011//159
+f 1016//159 1015//159 1013//159
+f 1018//14 1017//14 1015//159
+f 1020//14 1019//14 1017//14
+f 1022//7 1021//7 1019//14
+f 1024//7 1023//7 1021//7
+f 1026//7 1025//7 1023//7
+f 1028//7 1027//7 1025//7
+f 1030//7 1029//7 1027//7
+f 1032//7 1031//7 1029//7
+f 1034//7 1033//7 1031//7
+f 1036//7 1035//7 1033//7
+f 1038//7 1037//7 1035//7
+f 1040//7 1039//7 1037//7
+f 1042//7 1041//7 1039//7
+f 1044//160 1043//160 1041//7
+f 1046//161 1045//161 1043//160
+f 1048//162 1047//162 1045//161
+f 1050//163 1049//163 1047//162
+f 1052//164 1051//164 1049//163
+f 1054//165 1053//165 1051//164
+f 1056//166 1055//166 1053//165
+f 1058//167 1057//167 1055//166
+f 1060//168 1059//168 1057//167
+f 1062//96 1061//96 1059//168
+f 1064//169 1063//169 1061//96
+f 1066//170 1065//170 1063//169
+f 1068//171 1067//171 1065//170
+f 1070//172 1069//172 1067//171
+f 1072//173 1071//173 1069//172
+f 1074//174 1073//174 1071//173
+f 1076//175 1075//175 1073//174
+f 1078//176 1077//176 1075//175
+f 1080//177 1079//179 1077//176
+f 1082//178 1081//178 1079//179
+f 1084//180 1083//180 1081//178
+f 1086//181 1085//181 1083//180
+f 1088//182 1087//182 1085//181
+f 1090//183 1089//183 1087//182
+f 1092//184 1091//184 1089//183
+f 1094//185 1093//185 1091//184
+f 1096//186 1095//186 1093//185
+f 1098//187 1097//187 1095//186
+f 1100//188 1099//188 1097//187
+f 1102//189 1101//189 1099//188
+f 1104//190 1103//190 1101//189
+f 1106//191 1105//191 1103//190
+f 1108//192 1107//192 1105//191
+f 1110//193 1109//193 1107//192
+f 1112//194 1111//194 1109//193
+f 1114//195 1113//195 1111//194
+f 1116//196 1115//196 1113//195
+f 928//130 927//130 1115//196
+f 1120//197 1119//197 1117//198
+f 1122//199 1121//199 1119//197
+f 1124//200 1123//200 1121//199
+f 1126//201 1125//201 1123//200
+f 1128//202 1127//202 1125//201
+f 1130//203 1129//203 1127//202
+f 1132//204 1131//204 1129//203
+f 1134//205 1133//205 1131//204
+f 1136//206 1135//206 1133//205
+f 1138//207 1137//207 1135//206
+f 1140//7 1139//7 1137//207
+f 1142//208 1141//208 1139//7
+f 1144//209 1143//209 1141//208
+f 1146//210 1145//210 1143//209
+f 1148//211 1147//211 1145//210
+f 1150//212 1149//212 1147//211
+f 1152//213 1151//213 1149//212
+f 1154//214 1153//214 1151//213
+f 1156//215 1155//215 1153//214
+f 1158//216 1157//216 1155//215
+f 1160//217 1159//217 1157//216
+f 1162//218 1161//218 1159//217
+f 1164//219 1163//219 1161//218
+f 1166//220 1165//220 1163//219
+f 1168//221 1167//221 1165//220
+f 1170//222 1169//222 1167//221
+f 1172//223 1171//223 1169//222
+f 1174//224 1173//224 1171//223
+f 1176//225 1175//225 1173//224
+f 1178//226 1177//226 1175//225
+f 1180//227 1179//227 1177//226
+f 1182//228 1181//228 1179//227
+f 1184//229 1183//229 1181//228
+f 1186//230 1185//230 1183//229
+f 1188//231 1187//231 1185//230
+f 1190//232 1189//232 1187//231
+f 1192//233 1191//233 1189//232
+f 1194//234 1193//236 1191//233
+f 1196//235 1195//235 1193//236
+f 1198//237 1197//237 1195//235
+f 1200//238 1199//238 1197//237
+f 1202//239 1201//239 1199//238
+f 1204//240 1203//240 1201//239
+f 1206//241 1205//241 1203//240
+f 1208//242 1207//242 1205//241
+f 1210//243 1209//243 1207//242
+f 1212//244 1211//244 1209//243
+f 1214//245 1213//245 1211//244
+f 1216//246 1215//246 1213//245
+f 1218//247 1217//247 1215//246
+f 1220//248 1219//248 1217//247
+f 1222//249 1221//249 1219//248
+f 1224//250 1223//250 1221//249
+f 1226//251 1225//251 1223//250
+f 1228//252 1227//252 1225//251
+f 1230//253 1229//253 1227//252
+f 1232//254 1231//254 1229//253
+f 1234//255 1233//255 1231//254
+f 1236//256 1235//256 1233//255
+f 1238//257 1237//257 1235//256
+f 1240//258 1239//258 1237//257
+f 1242//259 1241//259 1239//258
+f 1244//260 1243//260 1241//259
+f 1246//261 1245//261 1243//260
+f 1248//262 1247//262 1245//261
+f 1250//263 1249//263 1247//262
+f 1252//264 1251//264 1249//263
+f 1254//265 1253//265 1251//264
+f 1256//266 1255//266 1253//265
+f 1258//267 1257//267 1255//266
+f 1260//268 1259//268 1257//267
+f 1262//269 1261//269 1259//268
+f 1264//270 1263//270 1261//269
+f 1266//271 1265//271 1263//270
+f 1268//272 1267//272 1265//271
+f 1270//273 1269//273 1267//272
+f 1272//274 1271//274 1269//273
+f 1274//275 1273//275 1271//274
+f 1276//276 1275//276 1273//275
+f 1278//277 1277//277 1275//276
+f 1280//278 1279//278 1277//277
+f 1282//279 1281//279 1279//278
+f 1284//3 1283//3 1281//279
+f 1286//280 1285//280 1283//3
+f 1288//281 1287//281 1285//280
+f 1290//282 1289//282 1287//281
+f 1292//283 1291//283 1289//282
+f 1294//284 1293//284 1291//283
+f 1296//285 1295//285 1293//284
+f 1298//286 1297//286 1295//285
+f 1300//287 1299//287 1297//286
+f 1302//288 1301//288 1299//287
+f 1304//289 1303//289 1301//288
+f 1306//290 1305//290 1303//289
+f 1308//291 1307//291 1305//290
+f 1118//198 1117//198 1307//291
diff --git a/examples/vulkan/shared/trianglerenderer.cpp b/examples/vulkan/shared/trianglerenderer.cpp
new file mode 100644
index 0000000000..f346f90c89
--- /dev/null
+++ b/examples/vulkan/shared/trianglerenderer.cpp
@@ -0,0 +1,513 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "trianglerenderer.h"
+#include <QVulkanFunctions>
+#include <QFile>
+
+// Note that the vertex data and the projection matrix assume OpenGL. With
+// Vulkan Y is negated in clip space and the near/far plane is at 0/1 instead
+// of -1/1. These will be corrected for by an extra transformation when
+// calculating the modelview-projection matrix.
+static float vertexData[] = {
+ 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
+ -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f
+};
+
+static const int UNIFORM_DATA_SIZE = 16 * sizeof(float);
+
+static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)
+{
+ return (v + byteAlign - 1) & ~(byteAlign - 1);
+}
+
+TriangleRenderer::TriangleRenderer(QVulkanWindow *w, bool msaa)
+ : m_window(w)
+{
+ if (msaa) {
+ const QVector<int> counts = w->supportedSampleCounts();
+ qDebug() << "Supported sample counts:" << counts;
+ for (int s = 16; s >= 4; s /= 2) {
+ if (counts.contains(s)) {
+ qDebug("Requesting sample count %d", s);
+ m_window->setSampleCount(s);
+ break;
+ }
+ }
+ }
+}
+
+VkShaderModule TriangleRenderer::createShader(const QString &name)
+{
+ QFile file(name);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning("Failed to read shader %s", qPrintable(name));
+ return VK_NULL_HANDLE;
+ }
+ QByteArray blob = file.readAll();
+ file.close();
+
+ VkShaderModuleCreateInfo shaderInfo;
+ memset(&shaderInfo, 0, sizeof(shaderInfo));
+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shaderInfo.codeSize = blob.size();
+ shaderInfo.pCode = reinterpret_cast<const uint32_t *>(blob.constData());
+ VkShaderModule shaderModule;
+ VkResult err = m_devFuncs->vkCreateShaderModule(m_window->device(), &shaderInfo, nullptr, &shaderModule);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create shader module: %d", err);
+ return VK_NULL_HANDLE;
+ }
+
+ return shaderModule;
+}
+
+void TriangleRenderer::initResources()
+{
+ qDebug("initResources");
+
+ VkDevice dev = m_window->device();
+ m_devFuncs = m_window->vulkanInstance()->deviceFunctions(dev);
+
+ // Prepare the vertex and uniform data. The vertex data will never
+ // change so one buffer is sufficient regardless of the value of
+ // QVulkanWindow::CONCURRENT_FRAME_COUNT. Uniform data is changing per
+ // frame however so active frames have to have a dedicated copy.
+
+ // Use just one memory allocation and one buffer. We will then specify the
+ // appropriate offsets for uniform buffers in the VkDescriptorBufferInfo.
+ // Have to watch out for
+ // VkPhysicalDeviceLimits::minUniformBufferOffsetAlignment, though.
+
+ // The uniform buffer is not strictly required in this example, we could
+ // have used push constants as well since our single matrix (64 bytes) fits
+ // into the spec mandated minimum limit of 128 bytes. However, once that
+ // limit is not sufficient, the per-frame buffers, as shown below, will
+ // become necessary.
+
+ const int concurrentFrameCount = m_window->concurrentFrameCount();
+ const VkPhysicalDeviceLimits *pdevLimits = &m_window->physicalDeviceProperties()->limits;
+ const VkDeviceSize uniAlign = pdevLimits->minUniformBufferOffsetAlignment;
+ qDebug("uniform buffer offset alignment is %u", (uint) uniAlign);
+ VkBufferCreateInfo bufInfo;
+ memset(&bufInfo, 0, sizeof(bufInfo));
+ bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ // Our internal layout is vertex, uniform, uniform, ... with each uniform buffer start offset aligned to uniAlign.
+ const VkDeviceSize vertexAllocSize = aligned(sizeof(vertexData), uniAlign);
+ const VkDeviceSize uniformAllocSize = aligned(UNIFORM_DATA_SIZE, uniAlign);
+ bufInfo.size = vertexAllocSize + concurrentFrameCount * uniformAllocSize;
+ bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+
+ VkResult err = m_devFuncs->vkCreateBuffer(dev, &bufInfo, nullptr, &m_buf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create buffer: %d", err);
+
+ VkMemoryRequirements memReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(dev, m_buf, &memReq);
+
+ VkMemoryAllocateInfo memAllocInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ nullptr,
+ memReq.size,
+ m_window->hostVisibleMemoryIndex()
+ };
+
+ err = m_devFuncs->vkAllocateMemory(dev, &memAllocInfo, nullptr, &m_bufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate memory: %d", err);
+
+ err = m_devFuncs->vkBindBufferMemory(dev, m_buf, m_bufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind buffer memory: %d", err);
+
+ quint8 *p;
+ err = m_devFuncs->vkMapMemory(dev, m_bufMem, 0, memReq.size, 0, reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS)
+ qFatal("Failed to map memory: %d", err);
+ memcpy(p, vertexData, sizeof(vertexData));
+ QMatrix4x4 ident;
+ memset(m_uniformBufInfo, 0, sizeof(m_uniformBufInfo));
+ for (int i = 0; i < concurrentFrameCount; ++i) {
+ const VkDeviceSize offset = vertexAllocSize + i * uniformAllocSize;
+ memcpy(p + offset, ident.constData(), 16 * sizeof(float));
+ m_uniformBufInfo[i].buffer = m_buf;
+ m_uniformBufInfo[i].offset = offset;
+ m_uniformBufInfo[i].range = uniformAllocSize;
+ }
+ m_devFuncs->vkUnmapMemory(dev, m_bufMem);
+
+ VkVertexInputBindingDescription vertexBindingDesc = {
+ 0, // binding
+ 5 * sizeof(float),
+ VK_VERTEX_INPUT_RATE_VERTEX
+ };
+ VkVertexInputAttributeDescription vertexAttrDesc[] = {
+ { // position
+ 0, // location
+ 0, // binding
+ VK_FORMAT_R32G32_SFLOAT,
+ 0
+ },
+ { // color
+ 1,
+ 0,
+ VK_FORMAT_R32G32B32_SFLOAT,
+ 2 * sizeof(float)
+ }
+ };
+
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo;
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.pNext = nullptr;
+ vertexInputInfo.flags = 0;
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDesc;
+ vertexInputInfo.vertexAttributeDescriptionCount = 2;
+ vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc;
+
+ // Set up descriptor set and its layout.
+ VkDescriptorPoolSize descPoolSizes = { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uint32_t(concurrentFrameCount) };
+ VkDescriptorPoolCreateInfo descPoolInfo;
+ memset(&descPoolInfo, 0, sizeof(descPoolInfo));
+ descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ descPoolInfo.maxSets = concurrentFrameCount;
+ descPoolInfo.poolSizeCount = 1;
+ descPoolInfo.pPoolSizes = &descPoolSizes;
+ err = m_devFuncs->vkCreateDescriptorPool(dev, &descPoolInfo, nullptr, &m_descPool);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor pool: %d", err);
+
+ VkDescriptorSetLayoutBinding layoutBinding = {
+ 0, // binding
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ 1,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ nullptr
+ };
+ VkDescriptorSetLayoutCreateInfo descLayoutInfo = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ nullptr,
+ 0,
+ 1,
+ &layoutBinding
+ };
+ err = m_devFuncs->vkCreateDescriptorSetLayout(dev, &descLayoutInfo, nullptr, &m_descSetLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor set layout: %d", err);
+
+ for (int i = 0; i < concurrentFrameCount; ++i) {
+ VkDescriptorSetAllocateInfo descSetAllocInfo = {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ nullptr,
+ m_descPool,
+ 1,
+ &m_descSetLayout
+ };
+ err = m_devFuncs->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_descSet[i]);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate descriptor set: %d", err);
+
+ VkWriteDescriptorSet descWrite;
+ memset(&descWrite, 0, sizeof(descWrite));
+ descWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descWrite.dstSet = m_descSet[i];
+ descWrite.descriptorCount = 1;
+ descWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descWrite.pBufferInfo = &m_uniformBufInfo[i];
+ m_devFuncs->vkUpdateDescriptorSets(dev, 1, &descWrite, 0, nullptr);
+ }
+
+ // Pipeline cache
+ VkPipelineCacheCreateInfo pipelineCacheInfo;
+ memset(&pipelineCacheInfo, 0, sizeof(pipelineCacheInfo));
+ pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+ err = m_devFuncs->vkCreatePipelineCache(dev, &pipelineCacheInfo, nullptr, &m_pipelineCache);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline cache: %d", err);
+
+ // Pipeline layout
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo;
+ memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo));
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &m_descSetLayout;
+ err = m_devFuncs->vkCreatePipelineLayout(dev, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline layout: %d", err);
+
+ // Shaders
+ VkShaderModule vertShaderModule = createShader(QStringLiteral(":/color_vert.spv"));
+ VkShaderModule fragShaderModule = createShader(QStringLiteral(":/color_frag.spv"));
+
+ // Graphics pipeline
+ VkGraphicsPipelineCreateInfo pipelineInfo;
+ memset(&pipelineInfo, 0, sizeof(pipelineInfo));
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+
+ VkPipelineShaderStageCreateInfo shaderStages[2] = {
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ vertShaderModule,
+ "main",
+ nullptr
+ },
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ nullptr,
+ 0,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fragShaderModule,
+ "main",
+ nullptr
+ }
+ };
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+
+ VkPipelineInputAssemblyStateCreateInfo ia;
+ memset(&ia, 0, sizeof(ia));
+ ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ pipelineInfo.pInputAssemblyState = &ia;
+
+ // The viewport and scissor will be set dynamically via vkCmdSetViewport/Scissor.
+ // This way the pipeline does not need to be touched when resizing the window.
+ VkPipelineViewportStateCreateInfo vp;
+ memset(&vp, 0, sizeof(vp));
+ vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vp.viewportCount = 1;
+ vp.scissorCount = 1;
+ pipelineInfo.pViewportState = &vp;
+
+ VkPipelineRasterizationStateCreateInfo rs;
+ memset(&rs, 0, sizeof(rs));
+ rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rs.polygonMode = VK_POLYGON_MODE_FILL;
+ rs.cullMode = VK_CULL_MODE_NONE; // we want the back face as well
+ rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ rs.lineWidth = 1.0f;
+ pipelineInfo.pRasterizationState = &rs;
+
+ VkPipelineMultisampleStateCreateInfo ms;
+ memset(&ms, 0, sizeof(ms));
+ ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ // Enable multisampling.
+ ms.rasterizationSamples = m_window->sampleCountFlagBits();
+ pipelineInfo.pMultisampleState = &ms;
+
+ VkPipelineDepthStencilStateCreateInfo ds;
+ memset(&ds, 0, sizeof(ds));
+ ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ ds.depthTestEnable = VK_TRUE;
+ ds.depthWriteEnable = VK_TRUE;
+ ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
+ pipelineInfo.pDepthStencilState = &ds;
+
+ VkPipelineColorBlendStateCreateInfo cb;
+ memset(&cb, 0, sizeof(cb));
+ cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ // no blend, write out all of rgba
+ VkPipelineColorBlendAttachmentState att;
+ memset(&att, 0, sizeof(att));
+ att.colorWriteMask = 0xF;
+ cb.attachmentCount = 1;
+ cb.pAttachments = &att;
+ pipelineInfo.pColorBlendState = &cb;
+
+ VkDynamicState dynEnable[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+ VkPipelineDynamicStateCreateInfo dyn;
+ memset(&dyn, 0, sizeof(dyn));
+ dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dyn.dynamicStateCount = sizeof(dynEnable) / sizeof(VkDynamicState);
+ dyn.pDynamicStates = dynEnable;
+ pipelineInfo.pDynamicState = &dyn;
+
+ pipelineInfo.layout = m_pipelineLayout;
+ pipelineInfo.renderPass = m_window->defaultRenderPass();
+
+ err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create graphics pipeline: %d", err);
+
+ if (vertShaderModule)
+ m_devFuncs->vkDestroyShaderModule(dev, vertShaderModule, nullptr);
+ if (fragShaderModule)
+ m_devFuncs->vkDestroyShaderModule(dev, fragShaderModule, nullptr);
+}
+
+void TriangleRenderer::initSwapChainResources()
+{
+ qDebug("initSwapChainResources");
+
+ // Projection matrix
+ m_proj = m_window->clipCorrectionMatrix(); // adjust for Vulkan-OpenGL clip space differences
+ const QSize sz = m_window->swapChainImageSize();
+ m_proj.perspective(45.0f, sz.width() / (float) sz.height(), 0.01f, 100.0f);
+ m_proj.translate(0, 0, -4);
+}
+
+void TriangleRenderer::releaseSwapChainResources()
+{
+ qDebug("releaseSwapChainResources");
+}
+
+void TriangleRenderer::releaseResources()
+{
+ qDebug("releaseResources");
+
+ VkDevice dev = m_window->device();
+
+ if (m_pipeline) {
+ m_devFuncs->vkDestroyPipeline(dev, m_pipeline, nullptr);
+ m_pipeline = VK_NULL_HANDLE;
+ }
+
+ if (m_pipelineLayout) {
+ m_devFuncs->vkDestroyPipelineLayout(dev, m_pipelineLayout, nullptr);
+ m_pipelineLayout = VK_NULL_HANDLE;
+ }
+
+ if (m_pipelineCache) {
+ m_devFuncs->vkDestroyPipelineCache(dev, m_pipelineCache, nullptr);
+ m_pipelineCache = VK_NULL_HANDLE;
+ }
+
+ if (m_descSetLayout) {
+ m_devFuncs->vkDestroyDescriptorSetLayout(dev, m_descSetLayout, nullptr);
+ m_descSetLayout = VK_NULL_HANDLE;
+ }
+
+ if (m_descPool) {
+ m_devFuncs->vkDestroyDescriptorPool(dev, m_descPool, nullptr);
+ m_descPool = VK_NULL_HANDLE;
+ }
+
+ if (m_buf) {
+ m_devFuncs->vkDestroyBuffer(dev, m_buf, nullptr);
+ m_buf = VK_NULL_HANDLE;
+ }
+
+ if (m_bufMem) {
+ m_devFuncs->vkFreeMemory(dev, m_bufMem, nullptr);
+ m_bufMem = VK_NULL_HANDLE;
+ }
+}
+
+void TriangleRenderer::startNextFrame()
+{
+ VkDevice dev = m_window->device();
+ VkCommandBuffer cb = m_window->currentCommandBuffer();
+ const QSize sz = m_window->swapChainImageSize();
+
+ VkClearColorValue clearColor = { 0, 0, 0, 1 };
+ VkClearDepthStencilValue clearDS = { 1, 0 };
+ VkClearValue clearValues[3];
+ memset(clearValues, 0, sizeof(clearValues));
+ clearValues[0].color = clearValues[2].color = clearColor;
+ clearValues[1].depthStencil = clearDS;
+
+ VkRenderPassBeginInfo rpBeginInfo;
+ memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
+ rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ rpBeginInfo.renderPass = m_window->defaultRenderPass();
+ rpBeginInfo.framebuffer = m_window->currentFramebuffer();
+ rpBeginInfo.renderArea.extent.width = sz.width();
+ rpBeginInfo.renderArea.extent.height = sz.height();
+ rpBeginInfo.clearValueCount = m_window->sampleCountFlagBits() > VK_SAMPLE_COUNT_1_BIT ? 3 : 2;
+ rpBeginInfo.pClearValues = clearValues;
+ VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
+ m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ quint8 *p;
+ VkResult err = m_devFuncs->vkMapMemory(dev, m_bufMem, m_uniformBufInfo[m_window->currentFrame()].offset,
+ UNIFORM_DATA_SIZE, 0, reinterpret_cast<void **>(&p));
+ if (err != VK_SUCCESS)
+ qFatal("Failed to map memory: %d", err);
+ QMatrix4x4 m = m_proj;
+ m.rotate(m_rotation, 0, 1, 0);
+ memcpy(p, m.constData(), 16 * sizeof(float));
+ m_devFuncs->vkUnmapMemory(dev, m_bufMem);
+
+ // Not exactly a real animation system, just advance on every frame for now.
+ m_rotation += 1.0f;
+
+ m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
+ m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1,
+ &m_descSet[m_window->currentFrame()], 0, nullptr);
+ VkDeviceSize vbOffset = 0;
+ m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_buf, &vbOffset);
+
+ VkViewport viewport;
+ viewport.x = viewport.y = 0;
+ viewport.width = sz.width();
+ viewport.height = sz.height();
+ viewport.minDepth = 0;
+ viewport.maxDepth = 1;
+ m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport);
+
+ VkRect2D scissor;
+ scissor.offset.x = scissor.offset.y = 0;
+ scissor.extent.width = viewport.width;
+ scissor.extent.height = viewport.height;
+ m_devFuncs->vkCmdSetScissor(cb, 0, 1, &scissor);
+
+ m_devFuncs->vkCmdDraw(cb, 3, 1, 0, 0);
+
+ m_devFuncs->vkCmdEndRenderPass(cmdBuf);
+
+ m_window->frameReady();
+ m_window->requestUpdate(); // render continuously, throttled by the presentation rate
+}
diff --git a/examples/vulkan/shared/trianglerenderer.h b/examples/vulkan/shared/trianglerenderer.h
new file mode 100644
index 0000000000..9a33291a95
--- /dev/null
+++ b/examples/vulkan/shared/trianglerenderer.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QVulkanWindow>
+
+class TriangleRenderer : public QVulkanWindowRenderer
+{
+public:
+ TriangleRenderer(QVulkanWindow *w, bool msaa = false);
+
+ void initResources() override;
+ void initSwapChainResources() override;
+ void releaseSwapChainResources() override;
+ void releaseResources() override;
+
+ void startNextFrame() override;
+
+protected:
+ VkShaderModule createShader(const QString &name);
+
+ QVulkanWindow *m_window;
+ QVulkanDeviceFunctions *m_devFuncs;
+
+ VkDeviceMemory m_bufMem = VK_NULL_HANDLE;
+ VkBuffer m_buf = VK_NULL_HANDLE;
+ VkDescriptorBufferInfo m_uniformBufInfo[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT];
+
+ VkDescriptorPool m_descPool = VK_NULL_HANDLE;
+ VkDescriptorSetLayout m_descSetLayout = VK_NULL_HANDLE;
+ VkDescriptorSet m_descSet[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT];
+
+ VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
+ VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
+ VkPipeline m_pipeline = VK_NULL_HANDLE;
+
+ QMatrix4x4 m_proj;
+ float m_rotation = 0.0f;
+};
diff --git a/examples/vulkan/vulkan.pro b/examples/vulkan/vulkan.pro
new file mode 100644
index 0000000000..920762cb9e
--- /dev/null
+++ b/examples/vulkan/vulkan.pro
@@ -0,0 +1,10 @@
+TEMPLATE = subdirs
+
+SUBDIRS = hellovulkanwindow \
+ hellovulkantriangle \
+ hellovulkantexture
+
+qtHaveModule(widgets) {
+ SUBDIRS += hellovulkanwidget
+ qtHaveModule(concurrent): SUBDIRS += hellovulkancubes
+}
diff --git a/examples/widgets/animation/animatedtiles/main.cpp b/examples/widgets/animation/animatedtiles/main.cpp
index 0511fe8162..89b5b67f8a 100644
--- a/examples/widgets/animation/animatedtiles/main.cpp
+++ b/examples/widgets/animation/animatedtiles/main.cpp
@@ -50,6 +50,7 @@
#include <QtWidgets>
#include <QtCore/qmath.h>
+#include <QtCore/qrandom.h>
#include <QtCore/qstate.h>
class Pixmap : public QObject, public QGraphicsPixmapItem
@@ -202,8 +203,8 @@ int main(int argc, char **argv)
// Random
randomState->assignProperty(item, "pos",
- QPointF(-250 + qrand() % 500,
- -250 + qrand() % 500));
+ QPointF(-250 + QRandomGenerator::global()->bounded(500),
+ -250 + QRandomGenerator::global()->bounded(500)));
// Tiled
tiledState->assignProperty(item, "pos",
diff --git a/examples/widgets/animation/animation.pro b/examples/widgets/animation/animation.pro
index a13f8bb65a..19b79caf15 100644
--- a/examples/widgets/animation/animation.pro
+++ b/examples/widgets/animation/animation.pro
@@ -2,7 +2,6 @@ TEMPLATE = \
subdirs
SUBDIRS += \
animatedtiles \
- appchooser \
easing \
moveblocks \
states \
diff --git a/examples/widgets/animation/appchooser/accessories-dictionary.png b/examples/widgets/animation/appchooser/accessories-dictionary.png
deleted file mode 100644
index e9bd55d918..0000000000
--- a/examples/widgets/animation/appchooser/accessories-dictionary.png
+++ /dev/null
Binary files differ
diff --git a/examples/widgets/animation/appchooser/akregator.png b/examples/widgets/animation/appchooser/akregator.png
deleted file mode 100644
index a086f45ab6..0000000000
--- a/examples/widgets/animation/appchooser/akregator.png
+++ /dev/null
Binary files differ
diff --git a/examples/widgets/animation/appchooser/appchooser.pro b/examples/widgets/animation/appchooser/appchooser.pro
deleted file mode 100644
index 674e623b2d..0000000000
--- a/examples/widgets/animation/appchooser/appchooser.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-QT += widgets
-
-SOURCES = main.cpp
-RESOURCES = appchooser.qrc
-
-# install
-target.path = $$[QT_INSTALL_EXAMPLES]/widgets/animation/appchooser
-INSTALLS += target
diff --git a/examples/widgets/animation/appchooser/appchooser.qrc b/examples/widgets/animation/appchooser/appchooser.qrc
deleted file mode 100644
index 28a3e1c4c1..0000000000
--- a/examples/widgets/animation/appchooser/appchooser.qrc
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>accessories-dictionary.png</file>
- <file>akregator.png</file>
- <file>digikam.png</file>
- <file>k3b.png</file>
-</qresource>
-</RCC>
diff --git a/examples/widgets/animation/appchooser/digikam.png b/examples/widgets/animation/appchooser/digikam.png
deleted file mode 100644
index 9de9fb2f80..0000000000
--- a/examples/widgets/animation/appchooser/digikam.png
+++ /dev/null
Binary files differ
diff --git a/examples/widgets/animation/appchooser/k3b.png b/examples/widgets/animation/appchooser/k3b.png
deleted file mode 100644
index bbcafcfba1..0000000000
--- a/examples/widgets/animation/appchooser/k3b.png
+++ /dev/null
Binary files differ
diff --git a/examples/widgets/animation/appchooser/main.cpp b/examples/widgets/animation/appchooser/main.cpp
deleted file mode 100644
index 71c869f6a2..0000000000
--- a/examples/widgets/animation/appchooser/main.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore>
-#include <QtWidgets>
-
-
-class Pixmap : public QGraphicsWidget
-{
- Q_OBJECT
-
-public:
- Pixmap(const QPixmap &pix, QGraphicsItem *parent = 0)
- : QGraphicsWidget(parent), orig(pix), p(pix)
- {
- }
-
- void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
- {
- painter->drawPixmap(QPointF(), p);
- }
-
- void mousePressEvent(QGraphicsSceneMouseEvent *) override
- {
- emit clicked();
- }
-
- void setGeometry(const QRectF &rect) override
- {
- QGraphicsWidget::setGeometry(rect);
-
- if (rect.size().width() > orig.size().width())
- p = orig.scaled(rect.size().toSize());
- else
- p = orig;
- }
-
-Q_SIGNALS:
- void clicked();
-
-private:
- QPixmap orig;
- QPixmap p;
-};
-
-class GraphicsView : public QGraphicsView
-{
- Q_OBJECT
-public:
- GraphicsView(QGraphicsScene *scene, QWidget *parent = 0) : QGraphicsView(scene, parent)
- {
- }
-
- void resizeEvent(QResizeEvent *) override
- {
- fitInView(sceneRect(), Qt::KeepAspectRatio);
- }
-};
-
-
-void createStates(const QObjectList &objects,
- const QRect &selectedRect, QState *parent)
-{
- for (int i = 0; i < objects.size(); ++i) {
- QState *state = new QState(parent);
- state->assignProperty(objects.at(i), "geometry", selectedRect);
- parent->addTransition(objects.at(i), SIGNAL(clicked()), state);
- }
-}
-
-void createAnimations(const QObjectList &objects, QStateMachine *machine)
-{
- for (int i=0; i<objects.size(); ++i)
- machine->addDefaultAnimation(new QPropertyAnimation(objects.at(i), "geometry"));
-}
-
-int main(int argc, char **argv)
-{
- Q_INIT_RESOURCE(appchooser);
-
- QApplication app(argc, argv);
-
- Pixmap *p1 = new Pixmap(QPixmap(":/digikam.png"));
- Pixmap *p2 = new Pixmap(QPixmap(":/akregator.png"));
- Pixmap *p3 = new Pixmap(QPixmap(":/accessories-dictionary.png"));
- Pixmap *p4 = new Pixmap(QPixmap(":/k3b.png"));
-
- p1->setObjectName("p1");
- p2->setObjectName("p2");
- p3->setObjectName("p3");
- p4->setObjectName("p4");
-
- p1->setGeometry(QRectF( 0.0, 0.0, 64.0, 64.0));
- p2->setGeometry(QRectF(236.0, 0.0, 64.0, 64.0));
- p3->setGeometry(QRectF(236.0, 236.0, 64.0, 64.0));
- p4->setGeometry(QRectF( 0.0, 236.0, 64.0, 64.0));
-
- QGraphicsScene scene(0, 0, 300, 300);
- scene.setBackgroundBrush(Qt::white);
- scene.addItem(p1);
- scene.addItem(p2);
- scene.addItem(p3);
- scene.addItem(p4);
-
- GraphicsView window(&scene);
- window.setFrameStyle(0);
- window.setAlignment(Qt::AlignLeft | Qt::AlignTop);
- window.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- window.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-
- QStateMachine machine;
- machine.setGlobalRestorePolicy(QState::RestoreProperties);
-
- QState *group = new QState(&machine);
- group->setObjectName("group");
-
- QRect selectedRect(86, 86, 128, 128);
-
- QState *idleState = new QState(group);
- group->setInitialState(idleState);
-
- QObjectList objects;
- objects << p1 << p2 << p3 << p4;
- createStates(objects, selectedRect, group);
- createAnimations(objects, &machine);
-
- machine.setInitialState(group);
- machine.start();
-
- window.resize(300, 300);
- window.show();
-
- return app.exec();
-}
-
-#include "main.moc"
diff --git a/examples/widgets/animation/moveblocks/main.cpp b/examples/widgets/animation/moveblocks/main.cpp
index a9b95808a5..6d17696108 100644
--- a/examples/widgets/animation/moveblocks/main.cpp
+++ b/examples/widgets/animation/moveblocks/main.cpp
@@ -125,7 +125,7 @@ public:
void onEntry(QEvent *) override
{
int n;
- while ((n = (qrand() % m_stateCount + 1)) == m_lastIndex)
+ while ((n = QRandomGenerator::global()->bounded(m_stateCount) + 1) == m_lastIndex)
{ }
m_lastIndex = n;
machine()->postEvent(new StateSwitchEvent(n));
@@ -323,8 +323,6 @@ int main(int argc, char **argv)
window.resize(300, 300);
window.show();
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
-
return app.exec();
}
diff --git a/examples/widgets/animation/stickman/lifecycle.cpp b/examples/widgets/animation/stickman/lifecycle.cpp
index 253af22b2d..dbe9a299b4 100644
--- a/examples/widgets/animation/stickman/lifecycle.cpp
+++ b/examples/widgets/animation/stickman/lifecycle.cpp
@@ -91,13 +91,12 @@ public:
: QEventTransition(this, QEvent::Timer)
{
setTargetState(target);
- qsrand((uint)QDateTime::currentSecsSinceEpoch());
startTimer(1000);
}
bool eventTest(QEvent *e) override
{
- return QEventTransition::eventTest(e) && ((qrand() % 50) == 0);
+ return QEventTransition::eventTest(e) && QRandomGenerator::global()->bounded(50) == 0;
}
};
//! [4]
diff --git a/examples/widgets/animation/stickman/stickman.cpp b/examples/widgets/animation/stickman/stickman.cpp
index 7a4629c4d2..b7a2d87ada 100644
--- a/examples/widgets/animation/stickman/stickman.cpp
+++ b/examples/widgets/animation/stickman/stickman.cpp
@@ -53,13 +53,7 @@
#include <QPainter>
#include <QTimer>
-
-#define _USE_MATH_DEFINES
-#include <math.h>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
+#include <qmath.h>
static const qreal Coords[NodeCount * 2] = {
0.0, -150.0, // head, #0
@@ -300,7 +294,7 @@ void StickMan::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidge
QPointF dist = node2->pos() - node1->pos();
qreal sinAngle = dist.x() / sqrt(pow(dist.x(), 2) + pow(dist.y(), 2));
- qreal angle = asin(sinAngle) * 180.0 / M_PI;
+ qreal angle = qRadiansToDegrees(asin(sinAngle));
QPointF headPos = node1->pos();
painter->translate(headPos);
diff --git a/examples/widgets/animation/sub-attaq/main.cpp b/examples/widgets/animation/sub-attaq/main.cpp
index f65ca7be18..9b28d8c40f 100644
--- a/examples/widgets/animation/sub-attaq/main.cpp
+++ b/examples/widgets/animation/sub-attaq/main.cpp
@@ -57,8 +57,6 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
Q_INIT_RESOURCE(subattaq);
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
-
MainWindow w;
w.show();
diff --git a/examples/widgets/animation/sub-attaq/states.cpp b/examples/widgets/animation/sub-attaq/states.cpp
index 21cff048e7..e19704db7b 100644
--- a/examples/widgets/animation/sub-attaq/states.cpp
+++ b/examples/widgets/animation/sub-attaq/states.cpp
@@ -64,6 +64,7 @@
#include <QtCore/QStateMachine>
#include <QtWidgets/QKeyEventTransition>
#include <QtCore/QFinalState>
+#include <QtCore/QRandomGenerator>
PlayState::PlayState(GraphicsScene *scene, QState *parent)
: QState(parent),
@@ -193,12 +194,12 @@ void LevelState::initializeLevel()
for (int j = 0; j < subContent.second; ++j ) {
SubMarine *sub = new SubMarine(submarineDesc.type, submarineDesc.name, submarineDesc.points);
scene->addItem(sub);
- int random = (qrand() % 15 + 1);
+ int random = QRandomGenerator::global()->bounded(15) + 1;
qreal x = random == 13 || random == 5 ? 0 : scene->width() - sub->size().width();
- qreal y = scene->height() -(qrand() % 150 + 1) - sub->size().height();
+ qreal y = scene->height() -(QRandomGenerator::global()->bounded(150) + 1) - sub->size().height();
sub->setPos(x,y);
sub->setCurrentDirection(x == 0 ? SubMarine::Right : SubMarine::Left);
- sub->setCurrentSpeed(qrand() % 3 + 1);
+ sub->setCurrentSpeed(QRandomGenerator::global()->bounded(3) + 1);
}
}
}
diff --git a/examples/widgets/animation/sub-attaq/submarine_p.h b/examples/widgets/animation/sub-attaq/submarine_p.h
index b8d5532962..698b4b494f 100644
--- a/examples/widgets/animation/sub-attaq/submarine_p.h
+++ b/examples/widgets/animation/sub-attaq/submarine_p.h
@@ -69,6 +69,7 @@
//Qt
#include <QtCore/QPropertyAnimation>
+#include <QtCore/QRandomGenerator>
#include <QtWidgets/QGraphicsScene>
//This state is describing when the boat is moving right
@@ -88,8 +89,8 @@ public:
protected slots:
void onAnimationMovementValueChanged(const QVariant &)
{
- if (qrand() % 200 + 1 == 3)
- submarine->launchTorpedo(qrand() % 3 + 1);
+ if (QRandomGenerator::global()->bounded(200) + 1 == 3)
+ submarine->launchTorpedo(QRandomGenerator::global()->bounded(3) + 1);
}
protected:
diff --git a/examples/widgets/dialogs/dialogs.pro b/examples/widgets/dialogs/dialogs.pro
index 82e814dcb0..a29903938e 100644
--- a/examples/widgets/dialogs/dialogs.pro
+++ b/examples/widgets/dialogs/dialogs.pro
@@ -14,4 +14,3 @@ SUBDIRS = classwizard \
!qtConfig(wizard) {
SUBDIRS -= trivialwizard licensewizard classwizard
}
-wince: SUBDIRS += sipdialog
diff --git a/examples/widgets/doc/images/addressbook-editdialog.png b/examples/widgets/doc/images/addressbook-editdialog.png
index fd41ee63f7..7434aa44ef 100644
--- a/examples/widgets/doc/images/addressbook-editdialog.png
+++ b/examples/widgets/doc/images/addressbook-editdialog.png
Binary files differ
diff --git a/examples/widgets/doc/images/addressbook-example.png b/examples/widgets/doc/images/addressbook-example.png
index b743c166da..eebe97a718 100644
--- a/examples/widgets/doc/images/addressbook-example.png
+++ b/examples/widgets/doc/images/addressbook-example.png
Binary files differ
diff --git a/examples/widgets/doc/images/addressbook-newaddresstab.png b/examples/widgets/doc/images/addressbook-newaddresstab.png
index ff215a4b20..6b60ee08e9 100644
--- a/examples/widgets/doc/images/addressbook-newaddresstab.png
+++ b/examples/widgets/doc/images/addressbook-newaddresstab.png
Binary files differ
diff --git a/examples/widgets/doc/images/graphicssimpleanchorlayout-example.png b/examples/widgets/doc/images/graphicssimpleanchorlayout-example.png
index 543670e05c..e4bed44edf 100644
--- a/examples/widgets/doc/images/graphicssimpleanchorlayout-example.png
+++ b/examples/widgets/doc/images/graphicssimpleanchorlayout-example.png
Binary files differ
diff --git a/examples/widgets/doc/images/itemviews-editabletreemodel.png b/examples/widgets/doc/images/itemviews-editabletreemodel.png
index a151ea857f..ff6cf637a1 100644
--- a/examples/widgets/doc/images/itemviews-editabletreemodel.png
+++ b/examples/widgets/doc/images/itemviews-editabletreemodel.png
Binary files differ
diff --git a/examples/widgets/doc/images/stylesheet-pagefold.png b/examples/widgets/doc/images/stylesheet-pagefold.png
index 5ccb4edbc9..d1358f326b 100644
--- a/examples/widgets/doc/images/stylesheet-pagefold.png
+++ b/examples/widgets/doc/images/stylesheet-pagefold.png
Binary files differ
diff --git a/examples/widgets/doc/src/addressbook.qdoc b/examples/widgets/doc/src/addressbook.qdoc
index b9bcae21aa..1fa0bfa9d4 100644
--- a/examples/widgets/doc/src/addressbook.qdoc
+++ b/examples/widgets/doc/src/addressbook.qdoc
@@ -60,8 +60,8 @@
the address book.
\c TableModel is a subclass of QAbstractTableModel that provides
- the standard model/view API to access data. It also holds a
- QList of \l{QPair}s corresponding to the contacts added.
+ the standard model/view API to access data. It holds a list of
+ added contacts.
However, this data is not all visible in a single tab. Instead,
QTableView is used to provide 9 different views of the same
data, according to the alphabet groups.
@@ -80,7 +80,7 @@
\section1 TableModel Class Definition
The \c TableModel class provides standard API to access data in
- its QList of \l{QPair}s by subclassing QAbstractTableModel. The
+ its list of contacts by subclassing QAbstractTableModel. The
basic functions that must be implemented in order to do so are:
\c rowCount(), \c columnCount(), \c data(), \c headerData().
For TableModel to be editable, it has to provide implementations
@@ -90,15 +90,14 @@
\snippet itemviews/addressbook/tablemodel.h 0
Two constructors are used, a default constructor which uses
- \c TableModel's own \c {QList<QPair<QString, QString>>} and one
- that takes \c {QList<QPair<QString, QString>} as an argument,
- for convenience.
+ \c TableModel's own \c {QList<Contact>} and one that takes
+ \c {QList<Contact>} as an argument, for convenience.
\section1 TableModel Class Implementation
We implement the two constructors as defined in the header file.
- The second constructor initializes the list of pairs in the
+ The second constructor initializes the list of contacts in the
model, with the parameter value.
\snippet itemviews/addressbook/tablemodel.cpp 0
@@ -117,7 +116,7 @@
The \c data() function returns either a \b Name or
\b {Address}, based on the contents of the model index
supplied. The row number stored in the model index is used to
- reference an item in the list of pairs. Selection is handled
+ reference an item in the list of contacts. Selection is handled
by the QItemSelectionModel, which will be explained with
\c AddressWidget.
@@ -164,12 +163,11 @@
use the editing features of the QTableView object, we enable
them here so that we can reuse the model in other programs.
- The last function in \c {TableModel}, \c getList() returns the
- QList<QPair<QString, QString>> object that holds all the
- contacts in the address book. We use this function later to
- obtain the list of contacts to check for existing entries, write
- the contacts to a file and read them back. Further explanation is
- given with \c AddressWidget.
+ The last function in \c {TableModel}, \c getContacts() returns the
+ QList<Contact> object that holds all the contacts in the address
+ book. We use this function later to obtain the list of contacts to
+ check for existing entries, write the contacts to a file and read
+ them back. Further explanation is given with \c AddressWidget.
\snippet itemviews/addressbook/tablemodel.cpp 8
@@ -222,11 +220,12 @@
The QItemSelectionModel class provides a
\l{QItemSelectionModel::selectionChanged()}{selectionChanged}
signal that is connected to \c{AddressWidget}'s
- \c selectionChanged() signal. This signal to signal connection
- is necessary to enable the \uicontrol{Edit Entry...} and
- \uicontrol{Remove Entry} actions in \c MainWindow's Tools menu. This
- connection is further explained in \c MainWindow's
- implementation.
+ \c selectionChanged() signal. We also connect
+ QTabWidget::currentChanged() signal to the lambda expression which
+ emits \c{AddressWidget}'s \c selectionChanged() as well. These
+ connections are necessary to enable the \uicontrol{Edit Entry...} and
+ \uicontrol{Remove Entry} actions in \c MainWindow's Tools menu.
+ It is further explained in \c MainWindow's implementation.
Each table view in the address book is added as a tab to the
QTabWidget with the relevant label, obtained from the QStringList
@@ -250,7 +249,7 @@
Basic validation is done in the second \c addEntry() function to
prevent duplicate entries in the address book. As mentioned with
\c TableModel, this is part of the reason why we require the
- getter method \c getList().
+ getter method \c getContacts().
\snippet itemviews/addressbook/addresswidget.cpp 3
@@ -292,7 +291,7 @@
The \c writeToFile() function is used to save a file containing
all the contacts in the address book. The file is saved in a
- custom \c{.dat} format. The contents of the QList of \l{QPair}s
+ custom \c{.dat} format. The contents of the list of contacts
are written to \c file using QDataStream. If the file cannot be
opened, a QMessageBox is displayed with the related error message.
@@ -301,7 +300,7 @@
The \c readFromFile() function loads a file containing all the
contacts in the address book, previously saved using
\c writeToFile(). QDataStream is used to read the contents of a
- \c{.dat} file into a list of pairs and each of these is added
+ \c{.dat} file into a list of contacts and each of these is added
using \c addEntry().
\snippet itemviews/addressbook/addresswidget.cpp 7
diff --git a/examples/widgets/doc/src/basiclayouts.qdoc b/examples/widgets/doc/src/basiclayouts.qdoc
index 01bcaa8c1a..e9d7cea21b 100644
--- a/examples/widgets/doc/src/basiclayouts.qdoc
+++ b/examples/widgets/doc/src/basiclayouts.qdoc
@@ -67,11 +67,11 @@
In the constructor, we first use the \c createMenu() function to
create and populate a menu bar and the \c createHorizontalGroupBox()
function to create a group box containing four buttons with a
- horizontal layout. Next we use the \c createGridGroupBox() function
+ horizontal layout. Next, we use the \c createGridGroupBox() function
to create a group box containing several line edits and a small text
editor which are displayed in a grid layout. Finally, we use the
\c createFormGroupBox() function to create a group box with
- three labels and three input fields: a line edit, a combo box and
+ three labels and three input fields: a line edit, a combo box, and
a spin box.
\snippet layouts/basiclayouts/dialog.cpp 1
@@ -111,7 +111,7 @@
\snippet layouts/basiclayouts/dialog.cpp 4
We use the QBoxLayout::addWidget() function to add the widgets to
- the end of layout. Each widget will get at least its minimum size
+ the end of the layout. Each widget will get at least its minimum size
and at most its maximum size. It is possible to specify a stretch
factor in the \l {QBoxLayout::addWidget()}{addWidget()} function,
and any excess space is shared according to these stretch
diff --git a/examples/widgets/doc/src/calendarwidget.qdoc b/examples/widgets/doc/src/calendarwidget.qdoc
index eaf8f547da..c04fab1fc7 100644
--- a/examples/widgets/doc/src/calendarwidget.qdoc
+++ b/examples/widgets/doc/src/calendarwidget.qdoc
@@ -110,8 +110,8 @@
size hints of its contents widgets.
To ensure that the window isn't automatically resized every time
- we change a property of the QCalendarWidget (e.g., hiding the
- navigation bar, trhe vertical header, or the grid), we set the
+ we change a property of the QCalendarWidget (for example, hiding the
+ navigation bar, the vertical header, or the grid), we set the
minimum height of row 0 and the minimum width of column 0 to the
initial size of the QCalendarWidget.
@@ -126,8 +126,8 @@
the formatting specified by the user.
The \c createGeneralOptionsGroupBox() function is somewhat large
- and several widgets are set up the same way; we look at parts of
- its implementation here and skip the rest:
+ and several widgets are set up in the same way. We will look at
+ parts of its implementation here and skip the rest:
\snippet widgets/calendarwidget/window.cpp 10
\dots
@@ -146,7 +146,7 @@
\snippet widgets/calendarwidget/window.cpp 11
\dots
- After creating the widgets, we connect the signals and slots. We
+ After having created the widgets, we connect the signals and slots. We
connect the comboboxes to private slots of \c Window or to
public slots provided by QComboBox.
diff --git a/examples/widgets/doc/src/collidingmice-example.qdoc b/examples/widgets/doc/src/collidingmice-example.qdoc
index 02417ba521..535057bb6a 100644
--- a/examples/widgets/doc/src/collidingmice-example.qdoc
+++ b/examples/widgets/doc/src/collidingmice-example.qdoc
@@ -80,8 +80,7 @@
\snippet graphicsview/collidingmice/mouse.cpp 0
To calculate the various components of the mouse's color, we use
- the global qrand() function which is a thread-safe version of the
- standard C++ rand() function.
+ \l QRandomGenerator.
Then we call the \l {QGraphicsItem::setRotation()}{setRotation()} function
inherited from QGraphicsItem. Items live in their own local
@@ -178,12 +177,7 @@
\snippet graphicsview/collidingmice/main.cpp 0
- First, we create an application object and call the global
- qsrand() function to specify the seed used to generate a new
- random number sequence of pseudo random integers with the
- previously mentioned qrand() function.
-
- Then it is time to create the scene:
+ First, we create an application object and create the scene:
\snippet graphicsview/collidingmice/main.cpp 1
diff --git a/examples/widgets/doc/src/customsortfiltermodel.qdoc b/examples/widgets/doc/src/customsortfiltermodel.qdoc
index 0eb6560e10..6eab846e89 100644
--- a/examples/widgets/doc/src/customsortfiltermodel.qdoc
+++ b/examples/widgets/doc/src/customsortfiltermodel.qdoc
@@ -75,7 +75,7 @@
QSortFilterProxyModel's default implementations of functions are
written so that they call the equivalent functions in the relevant
source model. This simple proxying mechanism may need to be
- overridden for source models with more complex behavior; in this
+ overridden for source models with more complex behavior. In this
example we derive from the QSortFilterProxyModel class to ensure
that our filter can recognize a valid range of dates, and to
control the sorting behavior.
@@ -170,7 +170,7 @@
We implement two private slots, \c textFilterChanged() and \c
dateFilterChanged(), to respond to the user changing the filter
- pattern, case sensitivity or any of the dates. In addition, we
+ pattern, case sensitivity, or any of the dates. In addition, we
implement a public \c setSourceModel() convenience function to set
up the model/ view relation.
@@ -197,7 +197,7 @@
\snippet itemviews/customsortfiltermodel/window.cpp 1
The QTreeView class provides a default model/view implementation
- of a tree view; our view implements a tree representation of items
+ of a tree view. Our view implements a tree representation of items
in the application's source model.
\snippet itemviews/customsortfiltermodel/window.cpp 2
diff --git a/examples/widgets/doc/src/dragdroprobot.qdoc b/examples/widgets/doc/src/dragdroprobot.qdoc
index ac221ec5f9..f74b898e1b 100644
--- a/examples/widgets/doc/src/dragdroprobot.qdoc
+++ b/examples/widgets/doc/src/dragdroprobot.qdoc
@@ -257,7 +257,7 @@
\snippet graphicsview/dragdroprobot/coloritem.cpp 0
\c ColorItem's constructor assigns an opaque random color to its color
- member by making use of qrand(). For improved usability, it assigns a
+ member by making use of \l QRandomGenerator. For improved usability, it assigns a
tooltip that provides a useful hint to the user, and it also sets a
suitable cursor. This ensures that the cursor will chance to
Qt::OpenHandCursor when the mouse pointer hovers over the item.
diff --git a/examples/widgets/doc/src/elasticnodes.qdoc b/examples/widgets/doc/src/elasticnodes.qdoc
index 09ac891b24..65e1195121 100644
--- a/examples/widgets/doc/src/elasticnodes.qdoc
+++ b/examples/widgets/doc/src/elasticnodes.qdoc
@@ -424,9 +424,8 @@
\section1 The main() Function
In contrast to the complexity of the rest of this example, the \c main()
- function is very simple: We create a QApplication instance, seed the
- randomizer using qsrand(), and then create and show an instance of \c
- GraphWidget. Because all nodes in the grid are moved initially, the \c
- GraphWidget timer will start immediately after control has returned to the
- event loop.
+ function is very simple: We create a QApplication instance, then create and
+ show an instance of \c GraphWidget. Because all nodes in the grid are moved
+ initially, the \c GraphWidget timer will start immediately after control
+ has returned to the event loop.
*/
diff --git a/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc b/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc
index 866dac442b..fd0427fdc0 100644
--- a/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc
+++ b/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc
@@ -35,4 +35,50 @@
QGraphicsAnchorLayout class.
\image graphicssimpleanchorlayout-example.png
+
+ The example starts by creating a QGraphicsScene (\c scene), 3 widgets
+ (\c a, \c b, and \c c), and a QGraphicsAnchorlayout (\c layout).
+
+ \quotefromfile graphicsview/simpleanchorlayout/main.cpp
+ \skipto QGraphicsScene
+ \printuntil QGraphicsAnchorLayout
+
+ First it anchors the top left corner of item \c a to the top left
+ corner of \c layout. This can be done in two steps:
+
+ \skipto layout->addAnchor(a
+ \printto adding
+
+ Or in one step:
+
+ \skipuntil [adding a corner anchor]
+ \printline layout->addCornerAnchors(a, Qt::T
+
+ Then the right anchor of \c a is anchored to the left anchor of
+ \c b, and the top of item \c b is anchored to the bottom of \c a.
+
+ \skipuntil [adding anchors]
+ \printto adding anchors
+
+ Place a third widget \c c under widget \c b:
+
+ \skipuntil third widget
+ \printline AnchorBottom
+
+ Items \c b and \c c are anchored to each other horizontally:
+
+ \skipto Qt::Horizontal
+ \printline Qt::Horizontal
+
+ Item c is anchored to the bottom right point of \c layout
+
+ \skipuntil corner of the layout
+ \printline Qt::BottomRightCorner
+
+ Finally, QGraphicsWidget \c w is displayed in QGraphicsView \c view.
+
+ \skipto QGraphicsWidget
+ \printuntil app.exec()
+
+ \sa {Anchor Layout Example}
*/
diff --git a/examples/widgets/doc/src/painterpaths.qdoc b/examples/widgets/doc/src/painterpaths.qdoc
index 2cc5ff410a..bd821ac1bf 100644
--- a/examples/widgets/doc/src/painterpaths.qdoc
+++ b/examples/widgets/doc/src/painterpaths.qdoc
@@ -98,14 +98,9 @@
\section1 Window Class Implementation
- In the implementation of the \c Window class we first declare the
- constant \c Pi with six significant figures:
-
- \snippet painting/painterpaths/window.cpp 0
-
- In the constructor, we then define the various painter paths and
- create corresponding \c RenderArea widgets which will render the
- graphical shapes:
+ In the \c Window constructor, we define the various painter paths
+ and create corresponding \c RenderArea widgets which will render
+ the graphical shapes:
\snippet painting/painterpaths/window.cpp 1
diff --git a/examples/widgets/doc/src/stardelegate.qdoc b/examples/widgets/doc/src/stardelegate.qdoc
index dcc7080456..44d17662ca 100644
--- a/examples/widgets/doc/src/stardelegate.qdoc
+++ b/examples/widgets/doc/src/stardelegate.qdoc
@@ -37,7 +37,7 @@
When displaying data in a QListView, QTableView, or QTreeView,
the individual items are drawn by a
\l{Delegate Classes}{delegate}. Also, when the user starts
- editing an item (e.g., by double-clicking the item), the delegate
+ editing an item (for example, by double-clicking the item), the delegate
provides an editor widget that is placed on top of the item while
editing takes place.
@@ -96,9 +96,9 @@
QItemDelegate paint it for us. This ensures that the \c
StarDelegate can handle the most common data types.
- In the case where the item is a \c StarRating, we draw the
- background if the item is selected, and we draw the item using \c
- StarRating::paint(), which we will review later.
+ If the item is a \c StarRating, we draw the background if the
+ item is selected, and we draw the item using \c StarRating::paint(),
+ which we will review later.
\c{StartRating}s can be stored in a QVariant thanks to the
Q_DECLARE_METATYPE() macro appearing in \c starrating.h. More on
@@ -133,8 +133,8 @@
We simply call \c setStarRating() on the editor.
The \l{QAbstractItemDelegate::}{setModelData()} function is
- called when editing is finished, to commit data from the editor
- to the model:
+ called to commit data from the editor to the model when editing
+ is finished:
\snippet itemviews/stardelegate/stardelegate.cpp 4
@@ -210,7 +210,7 @@
current rating, and \c myMaxStarCount stores the highest possible
rating (typically 5).
- The Q_DECLARE_METATYPE() macro makes the type \c StarRating known
+ The \c Q_DECLARE_METATYPE() macro makes the type \c StarRating known
to QVariant, making it possible to store \c StarRating values in
QVariant.
@@ -283,7 +283,7 @@
\list
\li It is possible to open editors programmatically by calling
QAbstractItemView::edit(), instead of relying on edit
- triggers. This could be use to support other edit triggers
+ triggers. This could be used to support other edit triggers
than those offered by the QAbstractItemView::EditTrigger enum.
For example, in the Star Delegate example, hovering over an
item with the mouse might make sense as a way to pop up an
diff --git a/examples/widgets/doc/src/stylesheet.qdoc b/examples/widgets/doc/src/stylesheet.qdoc
index 0016836f0d..a86b697059 100644
--- a/examples/widgets/doc/src/stylesheet.qdoc
+++ b/examples/widgets/doc/src/stylesheet.qdoc
@@ -33,5 +33,56 @@
\borderedimage stylesheet-pagefold.png
\caption Screen Shot of the Pagefold style sheet
+
+ The Style Sheet example shows how widgets can be styled using Qt Style Sheets.
+ You can open the style editor by selecting \uicontrol File > \uicontrol Edit Style Sheet,
+ to select an existing style sheet or design your own style and load it.
+
+ The Style Sheet example consists of 2 classes:
+ \list
+ \li \c MainWindow
+ \li \c StyleSheetEditor
+ \endlist
+
+
+ \section1 MainWindow Class
+
+ \c MainWindow inherits QWidget, and is the application's main window defined in
+ \c mainwindow.ui. The style of \c MainWindow can be modified with \l StyleSheetEditor.
+
+
+ \section1 StyleSheetEditor Class
+
+ \c StyleSheetEditor enables you to open an editor where you can load an existing style sheet.
+ It is also possible to define a new stylesheet and load it. Its layout is defined in
+ \c stylesheeteditor.ui.
+
+ \quotefromfile widgets/stylesheet/stylesheeteditor.cpp
+ \skipto on_styleCombo_activated
+ \printline on_styleCombo_activated
+
+ Sets the specified \a styleName and grays the \c applyButton.
+
+ \skipto on_styleSheetCombo_activated
+ \printline on_styleSheetCombo_activated
+
+ Loads the stylesheet from \c styleSheetName.
+
+ \skipto on_styleTextEdit_textChanged()
+ \printline on_styleTextEdit_textChanged()
+
+ Enables the \c applyButton when the text in the buffer has changed.
+
+ \skipto on_applyButton_clicked()
+ \printline on_applyButton_clicked()
+
+ Sets the stylesheet properties in \l qApp and disables the \c applyButton.
+
+ \skipto loadStyleSheet(const QString &sheetName)
+ \printline loadStyleSheet(const QString &sheetName)
+
+ Loads the specified \a sheetName, and sets its properties in
+ \l qApp.
+
*/
diff --git a/examples/widgets/doc/src/tablet.qdoc b/examples/widgets/doc/src/tablet.qdoc
index 88fdefa68f..2b11020c07 100644
--- a/examples/widgets/doc/src/tablet.qdoc
+++ b/examples/widgets/doc/src/tablet.qdoc
@@ -206,8 +206,7 @@
\snippet widgets/tablet/tabletcanvas.cpp 0
- In the constructor we initialize our class variables. We need
- to draw the background of our pixmap, as the default is gray.
+ In the constructor we initialize most of our class variables.
Here is the implementation of \c saveImage():
@@ -247,7 +246,15 @@
\snippet widgets/tablet/tabletcanvas.cpp 4
- We simply draw the pixmap to the top left of the widget.
+ The first time Qt calls paintEvent(), m_pixmap is default-constructed, so
+ QPixmap::isNull() returns \c true. Now that we know which screen we will be
+ rendering to, we can create a pixmap with the appropriate resolution.
+ The size of the pixmap with which we fill the window depends on the screen
+ resolution, as the example does not support zoom; and it may be that one
+ screen is \l {High DPI Displays}{high DPI} while another is not. We need to
+ draw the background too, as the default is gray.
+
+ After that, we simply draw the pixmap to the top left of the widget.
Here is the implementation of \c paintPixmap():
diff --git a/examples/widgets/doc/src/validators.qdoc b/examples/widgets/doc/src/validators.qdoc
index f3f4dc5e63..bbb2e5f7b6 100644
--- a/examples/widgets/doc/src/validators.qdoc
+++ b/examples/widgets/doc/src/validators.qdoc
@@ -31,4 +31,6 @@
\ingroup examples-widgets
\brief The Validators example shows the signal emission behavior of input
validators.
+
+ \borderedimage validators.png
*/
diff --git a/examples/widgets/draganddrop/draggableicons/dragwidget.h b/examples/widgets/draganddrop/draggableicons/dragwidget.h
index 18be074b61..98e623a5e3 100644
--- a/examples/widgets/draganddrop/draggableicons/dragwidget.h
+++ b/examples/widgets/draganddrop/draggableicons/dragwidget.h
@@ -62,7 +62,7 @@ QT_END_NAMESPACE
class DragWidget : public QFrame
{
public:
- DragWidget(QWidget *parent = 0);
+ explicit DragWidget(QWidget *parent = nullptr);
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
diff --git a/examples/widgets/draganddrop/draggabletext/dragwidget.cpp b/examples/widgets/draganddrop/draggabletext/dragwidget.cpp
index fb169b953b..2135ba2ef9 100644
--- a/examples/widgets/draganddrop/draggabletext/dragwidget.cpp
+++ b/examples/widgets/draganddrop/draggabletext/dragwidget.cpp
@@ -123,7 +123,7 @@ void DragWidget::dropEvent(QDropEvent *event)
hotSpot.setY(hotSpotPos.last().toInt());
}
- foreach (const QString &piece, pieces) {
+ for (const QString &piece : pieces) {
QLabel *newLabel = createDragLabel(piece, this);
newLabel->move(position - hotSpot);
newLabel->show();
@@ -141,7 +141,7 @@ void DragWidget::dropEvent(QDropEvent *event)
} else {
event->ignore();
}
- foreach (QWidget *widget, findChildren<QWidget *>()) {
+ for (QWidget *widget : findChildren<QWidget *>()) {
if (!widget->isVisible())
widget->deleteLater();
}
diff --git a/examples/widgets/draganddrop/draggabletext/dragwidget.h b/examples/widgets/draganddrop/draggabletext/dragwidget.h
index 24d1f6f5c7..38abb0ceb8 100644
--- a/examples/widgets/draganddrop/draggabletext/dragwidget.h
+++ b/examples/widgets/draganddrop/draggabletext/dragwidget.h
@@ -61,7 +61,7 @@ QT_END_NAMESPACE
class DragWidget : public QWidget
{
public:
- DragWidget(QWidget *parent = 0);
+ explicit DragWidget(QWidget *parent = nullptr);
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
diff --git a/examples/widgets/draganddrop/dropsite/droparea.h b/examples/widgets/draganddrop/dropsite/droparea.h
index 5b6e209dfa..ab1de8ea44 100644
--- a/examples/widgets/draganddrop/dropsite/droparea.h
+++ b/examples/widgets/draganddrop/dropsite/droparea.h
@@ -63,13 +63,13 @@ class DropArea : public QLabel
Q_OBJECT
public:
- DropArea(QWidget *parent = 0);
+ explicit DropArea(QWidget *parent = nullptr);
public slots:
void clear();
signals:
- void changed(const QMimeData *mimeData = 0);
+ void changed(const QMimeData *mimeData = nullptr);
//! [DropArea header part1]
//! [DropArea header part2]
diff --git a/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp b/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp
index dc865ac171..28a42ee614 100644
--- a/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp
+++ b/examples/widgets/draganddrop/dropsite/dropsitewindow.cpp
@@ -88,8 +88,8 @@ DropSiteWindow::DropSiteWindow()
buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
- connect(quitButton, &QAbstractButton::pressed, this, &QWidget::close);
- connect(clearButton, &QAbstractButton::pressed, dropArea, &DropArea::clear);
+ connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close);
+ connect(clearButton, &QAbstractButton::clicked, dropArea, &DropArea::clear);
//! [constructor part4]
//! [constructor part5]
@@ -113,7 +113,7 @@ void DropSiteWindow::updateFormatsTable(const QMimeData *mimeData)
//! [updateFormatsTable() part1]
//! [updateFormatsTable() part2]
- foreach (QString format, mimeData->formats()) {
+ for (const QString &format : mimeData->formats()) {
QTableWidgetItem *formatItem = new QTableWidgetItem(format);
formatItem->setFlags(Qt::ItemIsEnabled);
formatItem->setTextAlignment(Qt::AlignTop | Qt::AlignLeft);
diff --git a/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp b/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp
index b185b2900d..451b53f623 100644
--- a/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp
+++ b/examples/widgets/draganddrop/fridgemagnets/dragwidget.cpp
@@ -167,7 +167,7 @@ void DragWidget::dropEvent(QDropEvent *event)
QString::SkipEmptyParts);
QPoint position = event->pos();
- foreach (const QString &piece, pieces) {
+ for (const QString &piece : pieces) {
DragLabel *newLabel = new DragLabel(piece, this);
newLabel->move(position);
newLabel->show();
diff --git a/examples/widgets/draganddrop/fridgemagnets/dragwidget.h b/examples/widgets/draganddrop/fridgemagnets/dragwidget.h
index 104e500134..ff513a33d8 100644
--- a/examples/widgets/draganddrop/fridgemagnets/dragwidget.h
+++ b/examples/widgets/draganddrop/fridgemagnets/dragwidget.h
@@ -62,7 +62,7 @@ QT_END_NAMESPACE
class DragWidget : public QWidget
{
public:
- DragWidget(QWidget *parent = 0);
+ explicit DragWidget(QWidget *parent = nullptr);
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
diff --git a/examples/widgets/draganddrop/puzzle/main.cpp b/examples/widgets/draganddrop/puzzle/main.cpp
index 0bf65a89c5..d013bf078d 100644
--- a/examples/widgets/draganddrop/puzzle/main.cpp
+++ b/examples/widgets/draganddrop/puzzle/main.cpp
@@ -48,10 +48,10 @@
**
****************************************************************************/
-#include <QApplication>
-
#include "mainwindow.h"
+#include <QApplication>
+
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(puzzle);
diff --git a/examples/widgets/draganddrop/puzzle/mainwindow.cpp b/examples/widgets/draganddrop/puzzle/mainwindow.cpp
index 806133583a..98a7cd4265 100644
--- a/examples/widgets/draganddrop/puzzle/mainwindow.cpp
+++ b/examples/widgets/draganddrop/puzzle/mainwindow.cpp
@@ -67,12 +67,19 @@ MainWindow::MainWindow(QWidget *parent)
void MainWindow::openImage()
{
- const QString fileName =
- QFileDialog::getOpenFileName(this, tr("Open Image"), QString(),
- tr("Image Files (*.png *.jpg *.bmp)"));
-
- if (!fileName.isEmpty())
- loadImage(fileName);
+ const QString directory =
+ QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath());
+ QFileDialog dialog(this, tr("Open Image"), directory);
+ dialog.setAcceptMode(QFileDialog::AcceptOpen);
+ dialog.setFileMode(QFileDialog::ExistingFile);
+ QStringList mimeTypeFilters;
+ for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes())
+ mimeTypeFilters.append(mimeTypeName);
+ mimeTypeFilters.sort();
+ dialog.setMimeTypeFilters(mimeTypeFilters);
+ dialog.selectMimeTypeFilter("image/jpeg");
+ if (dialog.exec() == QDialog::Accepted)
+ loadImage(dialog.selectedFiles().constFirst());
}
void MainWindow::loadImage(const QString &fileName)
@@ -101,8 +108,8 @@ void MainWindow::setCompleted()
void MainWindow::setupPuzzle()
{
int size = qMin(puzzleImage.width(), puzzleImage.height());
- puzzleImage = puzzleImage.copy((puzzleImage.width() - size)/2,
- (puzzleImage.height() - size)/2, size, size).scaled(puzzleWidget->width(),
+ puzzleImage = puzzleImage.copy((puzzleImage.width() - size) / 2,
+ (puzzleImage.height() - size) / 2, size, size).scaled(puzzleWidget->width(),
puzzleWidget->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
piecesList->clear();
@@ -115,10 +122,8 @@ void MainWindow::setupPuzzle()
}
}
- qsrand(QCursor::pos().x() ^ QCursor::pos().y());
-
for (int i = 0; i < piecesList->count(); ++i) {
- if (int(2.0*qrand()/(RAND_MAX+1.0)) == 1) {
+ if (QRandomGenerator::global()->bounded(2) == 1) {
QListWidgetItem *item = piecesList->takeItem(i);
piecesList->insertItem(0, item);
}
diff --git a/examples/widgets/draganddrop/puzzle/mainwindow.h b/examples/widgets/draganddrop/puzzle/mainwindow.h
index e43f52cab8..626612ebe8 100644
--- a/examples/widgets/draganddrop/puzzle/mainwindow.h
+++ b/examples/widgets/draganddrop/puzzle/mainwindow.h
@@ -51,8 +51,8 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
-#include <QPixmap>
#include <QMainWindow>
+#include <QPixmap>
class PiecesList;
class PuzzleWidget;
@@ -65,7 +65,7 @@ class MainWindow : public QMainWindow
Q_OBJECT
public:
- MainWindow(QWidget *parent = 0);
+ explicit MainWindow(QWidget *parent = nullptr);
void loadImage(const QString &path);
public slots:
diff --git a/examples/widgets/draganddrop/puzzle/pieceslist.cpp b/examples/widgets/draganddrop/puzzle/pieceslist.cpp
index 30890ecf9b..7846d37ed2 100644
--- a/examples/widgets/draganddrop/puzzle/pieceslist.cpp
+++ b/examples/widgets/draganddrop/puzzle/pieceslist.cpp
@@ -101,7 +101,7 @@ void PiecesList::dropEvent(QDropEvent *event)
}
}
-void PiecesList::addPiece(QPixmap pixmap, QPoint location)
+void PiecesList::addPiece(const QPixmap &pixmap, const QPoint &location)
{
QListWidgetItem *pieceItem = new QListWidgetItem(this);
pieceItem->setIcon(QIcon(pixmap));
diff --git a/examples/widgets/draganddrop/puzzle/pieceslist.h b/examples/widgets/draganddrop/puzzle/pieceslist.h
index b67d2bdaf7..a508d17d72 100644
--- a/examples/widgets/draganddrop/puzzle/pieceslist.h
+++ b/examples/widgets/draganddrop/puzzle/pieceslist.h
@@ -58,8 +58,8 @@ class PiecesList : public QListWidget
Q_OBJECT
public:
- explicit PiecesList(int pieceSize, QWidget *parent = 0);
- void addPiece(QPixmap pixmap, QPoint location);
+ explicit PiecesList(int pieceSize, QWidget *parent = nullptr);
+ void addPiece(const QPixmap &pixmap, const QPoint &location);
static QString puzzleMimeType() { return QStringLiteral("image/x-puzzle-piece"); }
diff --git a/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp b/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp
index 2093d7820c..72f2662bce 100644
--- a/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp
+++ b/examples/widgets/draganddrop/puzzle/puzzlewidget.cpp
@@ -66,9 +66,7 @@ PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent)
void PuzzleWidget::clear()
{
- pieceLocations.clear();
- piecePixmaps.clear();
- pieceRects.clear();
+ pieces.clear();
highlightedRect = QRect();
inPlace = 0;
update();
@@ -95,7 +93,7 @@ void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event)
QRect updateRect = highlightedRect.united(targetSquare(event->pos()));
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())
- && pieceRects.indexOf(targetSquare(event->pos())) == -1) {
+ && findPiece(targetSquare(event->pos())) == -1) {
highlightedRect = targetSquare(event->pos());
event->setDropAction(Qt::MoveAction);
@@ -111,26 +109,23 @@ void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event)
void PuzzleWidget::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())
- && pieceRects.indexOf(targetSquare(event->pos())) == -1) {
+ && findPiece(targetSquare(event->pos())) == -1) {
QByteArray pieceData = event->mimeData()->data(PiecesList::puzzleMimeType());
QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
- QRect square = targetSquare(event->pos());
- QPixmap pixmap;
- QPoint location;
- dataStream >> pixmap >> location;
+ Piece piece;
+ piece.rect = targetSquare(event->pos());
+ dataStream >> piece.pixmap >> piece.location;
- pieceLocations.append(location);
- piecePixmaps.append(pixmap);
- pieceRects.append(square);
+ pieces.append(piece);
highlightedRect = QRect();
- update(square);
+ update(piece.rect);
event->setDropAction(Qt::MoveAction);
event->accept();
- if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) {
+ if (piece.location == piece.rect.topLeft() / pieceSize()) {
inPlace++;
if (inPlace == 25)
emit puzzleCompleted();
@@ -141,21 +136,26 @@ void PuzzleWidget::dropEvent(QDropEvent *event)
}
}
+int PuzzleWidget::findPiece(const QRect &pieceRect) const
+{
+ for (int i = 0, size = pieces.size(); i < size; ++i) {
+ if (pieces.at(i).rect == pieceRect)
+ return i;
+ }
+ return -1;
+}
+
void PuzzleWidget::mousePressEvent(QMouseEvent *event)
{
QRect square = targetSquare(event->pos());
- int found = pieceRects.indexOf(square);
+ const int found = findPiece(square);
if (found == -1)
return;
- QPoint location = pieceLocations[found];
- QPixmap pixmap = piecePixmaps[found];
- pieceLocations.removeAt(found);
- piecePixmaps.removeAt(found);
- pieceRects.removeAt(found);
+ Piece piece = pieces.takeAt(found);
- if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize()))
+ if (piece.location == square.topLeft() / pieceSize())
inPlace--;
update(square);
@@ -163,7 +163,7 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
- dataStream << pixmap << location;
+ dataStream << piece.pixmap << piece.location;
QMimeData *mimeData = new QMimeData;
mimeData->setData(PiecesList::puzzleMimeType(), itemData);
@@ -171,23 +171,20 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setHotSpot(event->pos() - square.topLeft());
- drag->setPixmap(pixmap);
+ drag->setPixmap(piece.pixmap);
- if (!(drag->exec(Qt::MoveAction) == Qt::MoveAction)) {
- pieceLocations.insert(found, location);
- piecePixmaps.insert(found, pixmap);
- pieceRects.insert(found, square);
+ if (drag->exec(Qt::MoveAction) != Qt::MoveAction) {
+ pieces.insert(found, piece);
update(targetSquare(event->pos()));
- if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize()))
+ if (piece.location == square.topLeft() / pieceSize())
inPlace++;
}
}
void PuzzleWidget::paintEvent(QPaintEvent *event)
{
- QPainter painter;
- painter.begin(this);
+ QPainter painter(this);
painter.fillRect(event->rect(), Qt::white);
if (highlightedRect.isValid()) {
@@ -196,14 +193,14 @@ void PuzzleWidget::paintEvent(QPaintEvent *event)
painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1));
}
- for (int i = 0; i < pieceRects.size(); ++i)
- painter.drawPixmap(pieceRects[i], piecePixmaps[i]);
- painter.end();
+ for (const Piece &piece : pieces)
+ painter.drawPixmap(piece.rect, piece.pixmap);
}
const QRect PuzzleWidget::targetSquare(const QPoint &position) const
{
- return QRect(position.x()/pieceSize() * pieceSize(), position.y()/pieceSize() * pieceSize(), pieceSize(), pieceSize());
+ return QRect(position / pieceSize() * pieceSize(),
+ QSize(pieceSize(), pieceSize()));
}
int PuzzleWidget::pieceSize() const
diff --git a/examples/widgets/draganddrop/puzzle/puzzlewidget.h b/examples/widgets/draganddrop/puzzle/puzzlewidget.h
index 7dcb7dd497..40dd654af6 100644
--- a/examples/widgets/draganddrop/puzzle/puzzlewidget.h
+++ b/examples/widgets/draganddrop/puzzle/puzzlewidget.h
@@ -51,9 +51,9 @@
#ifndef PUZZLEWIDGET_H
#define PUZZLEWIDGET_H
-#include <QList>
#include <QPoint>
#include <QPixmap>
+#include <QVector>
#include <QWidget>
QT_BEGIN_NAMESPACE
@@ -67,7 +67,7 @@ class PuzzleWidget : public QWidget
Q_OBJECT
public:
- explicit PuzzleWidget(int imageSize, QWidget *parent = 0);
+ explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr);
void clear();
int pieceSize() const;
@@ -85,11 +85,16 @@ protected:
void paintEvent(QPaintEvent *event) override;
private:
+ struct Piece {
+ QPixmap pixmap;
+ QRect rect;
+ QPoint location;
+ };
+
+ int findPiece(const QRect &pieceRect) const;
const QRect targetSquare(const QPoint &position) const;
- QList<QPixmap> piecePixmaps;
- QList<QRect> pieceRects;
- QList<QPoint> pieceLocations;
+ QVector<Piece> pieces;
QRect highlightedRect;
int inPlace;
int m_ImageSize;
diff --git a/examples/widgets/effects/blurpicker/blurpicker.cpp b/examples/widgets/effects/blurpicker/blurpicker.cpp
index 43823bed30..a00af2144a 100644
--- a/examples/widgets/effects/blurpicker/blurpicker.cpp
+++ b/examples/widgets/effects/blurpicker/blurpicker.cpp
@@ -52,13 +52,9 @@
#include <QtWidgets>
#include <QtCore/qmath.h>
-
+#include <qmath.h>
#include "blureffect.h"
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
BlurPicker::BlurPicker(QWidget *parent): QGraphicsView(parent), m_index(0.0), m_animation(this, "index")
{
setBackgroundBrush(QPixmap(":/images/background.jpg"));
@@ -84,9 +80,10 @@ void BlurPicker::setIndex(qreal index)
m_index = index;
qreal baseline = 0;
+ const qreal iconAngle = 2 * M_PI / m_icons.count();
for (int i = 0; i < m_icons.count(); ++i) {
QGraphicsItem *icon = m_icons[i];
- qreal a = ((i + m_index) * 2 * M_PI) / m_icons.count();
+ qreal a = (i + m_index) * iconAngle;
qreal xs = 170 * qSin(a);
qreal ys = 100 * qCos(a);
QPointF pos(xs, ys);
diff --git a/examples/widgets/effects/effects.pro b/examples/widgets/effects/effects.pro
index 795e0508ac..05911979b9 100644
--- a/examples/widgets/effects/effects.pro
+++ b/examples/widgets/effects/effects.pro
@@ -2,5 +2,4 @@ TEMPLATE = \
subdirs
SUBDIRS = \
blurpicker \
- lighting \
fademessage
diff --git a/examples/widgets/effects/lighting/lighting.cpp b/examples/widgets/effects/lighting/lighting.cpp
deleted file mode 100644
index 68350f32b7..0000000000
--- a/examples/widgets/effects/lighting/lighting.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "lighting.h"
-
-#include <QtWidgets>
-#include <QtCore/qmath.h>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-Lighting::Lighting(QWidget *parent): QGraphicsView(parent), angle(0.0)
-{
- setScene(&m_scene);
-
- setupScene();
-
- QTimer *timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), SLOT(animate()));
- timer->setInterval(30);
- timer->start();
-
- setRenderHint(QPainter::Antialiasing, true);
- setFrameStyle(QFrame::NoFrame);
-}
-
-void Lighting::setupScene()
-{
- m_scene.setSceneRect(-300, -200, 600, 460);
-
- QLinearGradient linearGrad(QPointF(-100, -100), QPointF(100, 100));
- linearGrad.setColorAt(0, QColor(255, 255, 255));
- linearGrad.setColorAt(1, QColor(192, 192, 255));
- setBackgroundBrush(linearGrad);
-
- QRadialGradient radialGrad(30, 30, 30);
- radialGrad.setColorAt(0, Qt::yellow);
- radialGrad.setColorAt(0.2, Qt::yellow);
- radialGrad.setColorAt(1, Qt::transparent);
- QPixmap pixmap(60, 60);
- pixmap.fill(Qt::transparent);
- QPainter painter(&pixmap);
- painter.setPen(Qt::NoPen);
- painter.setBrush(radialGrad);
- painter.drawEllipse(0, 0, 60, 60);
- painter.end();
-
- m_lightSource = m_scene.addPixmap(pixmap);
- m_lightSource->setZValue(2);
-
- for (int i = -2; i < 3; ++i)
- for (int j = -2; j < 3; ++j) {
- QAbstractGraphicsShapeItem *item;
- if ((i + j) & 1)
- item = new QGraphicsEllipseItem(0, 0, 50, 50);
- else
- item = new QGraphicsRectItem(0, 0, 50, 50);
-
- item->setPen(QPen(Qt::black, 1));
- item->setBrush(QBrush(Qt::white));
- QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
- effect->setBlurRadius(8);
- item->setGraphicsEffect(effect);
- item->setZValue(1);
- item->setPos(i * 80, j * 80);
- m_scene.addItem(item);
- m_items << item;
- }
-
-
-}
-
-void Lighting::animate()
-{
- angle += (M_PI / 30);
- qreal xs = 200 * qSin(angle) - 40 + 25;
- qreal ys = 200 * qCos(angle) - 40 + 25;
- m_lightSource->setPos(xs, ys);
-
- for (int i = 0; i < m_items.size(); ++i) {
- QGraphicsItem *item = m_items.at(i);
- Q_ASSERT(item);
- QGraphicsDropShadowEffect *effect = static_cast<QGraphicsDropShadowEffect *>(item->graphicsEffect());
- Q_ASSERT(effect);
-
- QPointF delta(item->x() - xs, item->y() - ys);
- effect->setOffset(delta.toPoint() / 30);
-
- qreal dx = delta.x();
- qreal dy = delta.y();
- qreal dd = qSqrt(dx * dx + dy * dy);
- QColor color = effect->color();
- color.setAlphaF(qBound(0.4, 1 - dd / 200.0, 0.7));
- effect->setColor(color);
- }
-
- m_scene.update();
-}
-
-void Lighting::resizeEvent(QResizeEvent * /* event */)
-{
-}
diff --git a/examples/widgets/effects/lighting/lighting.pro b/examples/widgets/effects/lighting/lighting.pro
deleted file mode 100644
index 0a3b397de5..0000000000
--- a/examples/widgets/effects/lighting/lighting.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-QT += widgets
-
-SOURCES += main.cpp lighting.cpp
-HEADERS += lighting.h
-
-# install
-target.path = $$[QT_INSTALL_EXAMPLES]/widgets/effects/lighting
-INSTALLS += target
diff --git a/examples/widgets/graphicsview/boxes/glbuffers.cpp b/examples/widgets/graphicsview/boxes/glbuffers.cpp
index 1481292e76..851cd17796 100644
--- a/examples/widgets/graphicsview/boxes/glbuffers.cpp
+++ b/examples/widgets/graphicsview/boxes/glbuffers.cpp
@@ -50,11 +50,11 @@
#include "glbuffers.h"
#include <QtGui/qmatrix4x4.h>
-
+#include <QtCore/qmath.h>
void qgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
- const GLdouble ymax = zNear * tan(fovy * M_PI / 360.0);
+ const GLdouble ymax = zNear * tan(qDegreesToRadians(fovy) / 2.0);
const GLdouble ymin = -ymax;
const GLdouble xmin = ymin * aspect;
const GLdouble xmax = ymax * aspect;
diff --git a/examples/widgets/graphicsview/boxes/qtbox.cpp b/examples/widgets/graphicsview/boxes/qtbox.cpp
index 9a19985fac..3a184dd0b6 100644
--- a/examples/widgets/graphicsview/boxes/qtbox.cpp
+++ b/examples/widgets/graphicsview/boxes/qtbox.cpp
@@ -414,7 +414,7 @@ void QtBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi
CircleItem::CircleItem(int size, int x, int y) : ItemBase(size, x, y)
{
- m_color = QColor::fromHsv(rand() % 360, 255, 255);
+ m_color = QColor::fromHsv(QRandomGenerator::global()->bounded(360), 255, 255);
}
void CircleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
diff --git a/examples/widgets/graphicsview/boxes/scene.cpp b/examples/widgets/graphicsview/boxes/scene.cpp
index 9ac429c667..f51cad99ac 100644
--- a/examples/widgets/graphicsview/boxes/scene.cpp
+++ b/examples/widgets/graphicsview/boxes/scene.cpp
@@ -50,9 +50,10 @@
#include <QDebug>
#include "scene.h"
+#include <QtCore/QRandomGenerator>
#include <QtGui/qmatrix4x4.h>
#include <QtGui/qvector3d.h>
-#include <cmath>
+#include <qmath.h>
#include "3rdparty/fbm.h"
@@ -868,11 +869,12 @@ void Scene::renderCubemaps()
QVector3D center;
+ const float eachAngle = 2 * M_PI / m_cubemaps.size();
for (int i = m_frame % N; i < m_cubemaps.size(); i += N) {
if (0 == m_cubemaps[i])
continue;
- float angle = 2.0f * PI * i / m_cubemaps.size();
+ float angle = i * eachAngle;
center = m_trackBalls[1].rotation().rotatedVector(QVector3D(std::cos(angle), std::sin(angle), 0.0f));
@@ -1071,13 +1073,16 @@ void Scene::newItem(ItemDialog::ItemType type)
QSize size = sceneRect().size().toSize();
switch (type) {
case ItemDialog::QtBoxItem:
- addItem(new QtBox(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ addItem(new QtBox(64, QRandomGenerator::global()->bounded(size.width() - 64) + 32,
+ QRandomGenerator::global()->bounded(size.height() - 64) + 32));
break;
case ItemDialog::CircleItem:
- addItem(new CircleItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ addItem(new CircleItem(64, QRandomGenerator::global()->bounded(size.width() - 64) + 32,
+ QRandomGenerator::global()->bounded(size.height() - 64) + 32));
break;
case ItemDialog::SquareItem:
- addItem(new SquareItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ addItem(new SquareItem(64, QRandomGenerator::global()->bounded(size.width() - 64) + 32,
+ QRandomGenerator::global()->bounded(size.height() - 64) + 32));
break;
default:
break;
diff --git a/examples/widgets/graphicsview/boxes/scene.h b/examples/widgets/graphicsview/boxes/scene.h
index a2ba1d0b5a..ccb6f368cd 100644
--- a/examples/widgets/graphicsview/boxes/scene.h
+++ b/examples/widgets/graphicsview/boxes/scene.h
@@ -63,8 +63,6 @@
#include "glbuffers.h"
#include "qtbox.h"
-#define PI 3.14159265358979
-
QT_BEGIN_NAMESPACE
class QMatrix4x4;
QT_END_NAMESPACE
diff --git a/examples/widgets/graphicsview/boxes/trackball.cpp b/examples/widgets/graphicsview/boxes/trackball.cpp
index 15f3af77d1..794ce7ac37 100644
--- a/examples/widgets/graphicsview/boxes/trackball.cpp
+++ b/examples/widgets/graphicsview/boxes/trackball.cpp
@@ -50,6 +50,7 @@
#include "trackball.h"
#include "scene.h"
+#include <qmath.h>
#include <cmath>
//============================================================================//
@@ -101,10 +102,11 @@ void TrackBall::move(const QPointF& p, const QQuaternion &transformation)
case Plane:
{
QLineF delta(m_lastPos, p);
- m_angularVelocity = 180*delta.length() / (PI*msecs);
+ const float angleDelta = qRadiansToDegrees(float(delta.length()));
+ m_angularVelocity = angleDelta / msecs;
m_axis = QVector3D(-delta.dy(), delta.dx(), 0.0f).normalized();
m_axis = transformation.rotatedVector(m_axis);
- m_rotation = QQuaternion::fromAxisAndAngle(m_axis, 180 / PI * delta.length()) * m_rotation;
+ m_rotation = QQuaternion::fromAxisAndAngle(m_axis, angleDelta) * m_rotation;
}
break;
case Sphere:
@@ -124,7 +126,7 @@ void TrackBall::move(const QPointF& p, const QQuaternion &transformation)
currentPos3D.normalize();
m_axis = QVector3D::crossProduct(lastPos3D, currentPos3D);
- float angle = 180 / PI * std::asin(std::sqrt(QVector3D::dotProduct(m_axis, m_axis)));
+ float angle = qRadiansToDegrees(std::asin(m_axis.length()));
m_angularVelocity = angle / msecs;
m_axis.normalize();
diff --git a/examples/widgets/graphicsview/collidingmice/main.cpp b/examples/widgets/graphicsview/collidingmice/main.cpp
index a0659b9bc1..91aee70b86 100644
--- a/examples/widgets/graphicsview/collidingmice/main.cpp
+++ b/examples/widgets/graphicsview/collidingmice/main.cpp
@@ -60,7 +60,6 @@ static const int MouseCount = 7;
int main(int argc, char **argv)
{
QApplication app(argc, argv);
- qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
//! [0]
//! [1]
diff --git a/examples/widgets/graphicsview/collidingmice/mouse.cpp b/examples/widgets/graphicsview/collidingmice/mouse.cpp
index b94c650c18..14f887f6e3 100644
--- a/examples/widgets/graphicsview/collidingmice/mouse.cpp
+++ b/examples/widgets/graphicsview/collidingmice/mouse.cpp
@@ -52,12 +52,12 @@
#include <QGraphicsScene>
#include <QPainter>
+#include <QRandomGenerator>
#include <QStyleOption>
+#include <qmath.h>
-#include <math.h>
-
-static const double Pi = 3.14159265358979323846264338327950288419717;
-static double TwoPi = 2.0 * Pi;
+const qreal Pi = M_PI;
+const qreal TwoPi = 2 * M_PI;
static qreal normalizeAngle(qreal angle)
{
@@ -71,9 +71,9 @@ static qreal normalizeAngle(qreal angle)
//! [0]
Mouse::Mouse()
: angle(0), speed(0), mouseEyeDirection(0),
- color(qrand() % 256, qrand() % 256, qrand() % 256)
+ color(QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256))
{
- setRotation(qrand() % (360 * 16));
+ setRotation(QRandomGenerator::global()->bounded(360 * 16));
}
//! [0]
@@ -140,9 +140,7 @@ void Mouse::advance(int step)
//! [5]
QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0));
if (lineToCenter.length() > 150) {
- qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length());
- if (lineToCenter.dy() < 0)
- angleToCenter = TwoPi - angleToCenter;
+ qreal angleToCenter = std::atan2(lineToCenter.dy(), lineToCenter.dx());
angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2);
if (angleToCenter < Pi && angleToCenter > Pi / 4) {
@@ -171,9 +169,7 @@ void Mouse::advance(int step)
continue;
QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0));
- qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length());
- if (lineToMouse.dy() < 0)
- angleToMouse = TwoPi - angleToMouse;
+ qreal angleToMouse = std::atan2(lineToMouse.dy(), lineToMouse.dx());
angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2);
if (angleToMouse >= 0 && angleToMouse < Pi / 2) {
@@ -190,16 +186,16 @@ void Mouse::advance(int step)
// Add some random movement
//! [10]
- if (dangerMice.size() > 1 && (qrand() % 10) == 0) {
- if (qrand() % 1)
- angle += (qrand() % 100) / 500.0;
+ if (dangerMice.size() > 1 && QRandomGenerator::global()->bounded(10) == 0) {
+ if (QRandomGenerator::global()->bounded(1))
+ angle += QRandomGenerator::global()->bounded(1 / 500.0);
else
- angle -= (qrand() % 100) / 500.0;
+ angle -= QRandomGenerator::global()->bounded(1 / 500.0);
}
//! [10]
//! [11]
- speed += (-50 + qrand() % 100) / 100.0;
+ speed += (-50 + QRandomGenerator::global()->bounded(100)) / 100.0;
qreal dx = ::sin(angle) * 10;
mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5;
diff --git a/examples/widgets/graphicsview/diagramscene/arrow.cpp b/examples/widgets/graphicsview/diagramscene/arrow.cpp
index 012b9ea2ed..88160d9399 100644
--- a/examples/widgets/graphicsview/diagramscene/arrow.cpp
+++ b/examples/widgets/graphicsview/diagramscene/arrow.cpp
@@ -51,13 +51,10 @@
#include "arrow.h"
-#include <math.h>
-
+#include <qmath.h>
#include <QPen>
#include <QPainter>
-const qreal Pi = 3.14;
-
//! [0]
Arrow::Arrow(DiagramItem *startItem, DiagramItem *endItem, QGraphicsItem *parent)
: QGraphicsLineItem(parent)
@@ -132,14 +129,12 @@ void Arrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
setLine(QLineF(intersectPoint, myStartItem->pos()));
//! [5] //! [6]
- double angle = ::acos(line().dx() / line().length());
- if (line().dy() >= 0)
- angle = (Pi * 2) - angle;
+ double angle = std::atan2(-line().dy(), line().dx());
- QPointF arrowP1 = line().p1() + QPointF(sin(angle + Pi / 3) * arrowSize,
- cos(angle + Pi / 3) * arrowSize);
- QPointF arrowP2 = line().p1() + QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
- cos(angle + Pi - Pi / 3) * arrowSize);
+ QPointF arrowP1 = line().p1() + QPointF(sin(angle + M_PI / 3) * arrowSize,
+ cos(angle + M_PI / 3) * arrowSize);
+ QPointF arrowP2 = line().p1() + QPointF(sin(angle + M_PI - M_PI / 3) * arrowSize,
+ cos(angle + M_PI - M_PI / 3) * arrowSize);
arrowHead.clear();
arrowHead << line().p1() << arrowP1 << arrowP2;
diff --git a/examples/widgets/graphicsview/dragdroprobot/coloritem.cpp b/examples/widgets/graphicsview/dragdroprobot/coloritem.cpp
index 64a715d31f..262e18a317 100644
--- a/examples/widgets/graphicsview/dragdroprobot/coloritem.cpp
+++ b/examples/widgets/graphicsview/dragdroprobot/coloritem.cpp
@@ -54,7 +54,7 @@
//! [0]
ColorItem::ColorItem()
- : color(qrand() % 256, qrand() % 256, qrand() % 256)
+ : color(QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256))
{
setToolTip(QString("QColor(%1, %2, %3)\n%4")
.arg(color.red()).arg(color.green()).arg(color.blue())
@@ -107,7 +107,7 @@ void ColorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
//! [6]
static int n = 0;
- if (n++ > 2 && (qrand() % 3) == 0) {
+ if (n++ > 2 && QRandomGenerator::global()->bounded(3) == 0) {
QImage image(":/images/head.png");
mime->setImageData(image);
diff --git a/examples/widgets/graphicsview/dragdroprobot/main.cpp b/examples/widgets/graphicsview/dragdroprobot/main.cpp
index 20cec92d26..045e184569 100644
--- a/examples/widgets/graphicsview/dragdroprobot/main.cpp
+++ b/examples/widgets/graphicsview/dragdroprobot/main.cpp
@@ -73,7 +73,6 @@ int main(int argc, char **argv)
{
QApplication app(argc, argv);
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
//! [0]
//! [1]
QGraphicsScene scene(-200, -200, 400, 400);
diff --git a/examples/widgets/graphicsview/elasticnodes/edge.cpp b/examples/widgets/graphicsview/elasticnodes/edge.cpp
index e794e803cf..aec12b4225 100644
--- a/examples/widgets/graphicsview/elasticnodes/edge.cpp
+++ b/examples/widgets/graphicsview/elasticnodes/edge.cpp
@@ -51,13 +51,9 @@
#include "edge.h"
#include "node.h"
-#include <math.h>
-
+#include <qmath.h>
#include <QPainter>
-static const double Pi = 3.14159265358979323846264338327950288419717;
-static double TwoPi = 2.0 * Pi;
-
//! [0]
Edge::Edge(Node *sourceNode, Node *destNode)
: arrowSize(10)
@@ -139,18 +135,16 @@ void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
//! [6]
// Draw the arrows
- double angle = ::acos(line.dx() / line.length());
- if (line.dy() >= 0)
- angle = TwoPi - angle;
-
- QPointF sourceArrowP1 = sourcePoint + QPointF(sin(angle + Pi / 3) * arrowSize,
- cos(angle + Pi / 3) * arrowSize);
- QPointF sourceArrowP2 = sourcePoint + QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
- cos(angle + Pi - Pi / 3) * arrowSize);
- QPointF destArrowP1 = destPoint + QPointF(sin(angle - Pi / 3) * arrowSize,
- cos(angle - Pi / 3) * arrowSize);
- QPointF destArrowP2 = destPoint + QPointF(sin(angle - Pi + Pi / 3) * arrowSize,
- cos(angle - Pi + Pi / 3) * arrowSize);
+ double angle = std::atan2(-line.dy(), line.dx());
+
+ QPointF sourceArrowP1 = sourcePoint + QPointF(sin(angle + M_PI / 3) * arrowSize,
+ cos(angle + M_PI / 3) * arrowSize);
+ QPointF sourceArrowP2 = sourcePoint + QPointF(sin(angle + M_PI - M_PI / 3) * arrowSize,
+ cos(angle + M_PI - M_PI / 3) * arrowSize);
+ QPointF destArrowP1 = destPoint + QPointF(sin(angle - M_PI / 3) * arrowSize,
+ cos(angle - M_PI / 3) * arrowSize);
+ QPointF destArrowP2 = destPoint + QPointF(sin(angle - M_PI + M_PI / 3) * arrowSize,
+ cos(angle - M_PI + M_PI / 3) * arrowSize);
painter->setBrush(Qt::black);
painter->drawPolygon(QPolygonF() << line.p1() << sourceArrowP1 << sourceArrowP2);
diff --git a/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp b/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp
index 844c8f8aac..4259aab803 100644
--- a/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp
+++ b/examples/widgets/graphicsview/elasticnodes/graphwidget.cpp
@@ -55,6 +55,7 @@
#include <math.h>
#include <QKeyEvent>
+#include <QRandomGenerator>
//! [0]
GraphWidget::GraphWidget(QWidget *parent)
@@ -247,7 +248,7 @@ void GraphWidget::shuffle()
{
foreach (QGraphicsItem *item, scene()->items()) {
if (qgraphicsitem_cast<Node *>(item))
- item->setPos(-150 + qrand() % 300, -150 + qrand() % 300);
+ item->setPos(-150 + QRandomGenerator::global()->bounded(300), -150 + QRandomGenerator::global()->bounded(300));
}
}
diff --git a/examples/widgets/graphicsview/elasticnodes/main.cpp b/examples/widgets/graphicsview/elasticnodes/main.cpp
index 75cc4b0f69..1e372a9f6d 100644
--- a/examples/widgets/graphicsview/elasticnodes/main.cpp
+++ b/examples/widgets/graphicsview/elasticnodes/main.cpp
@@ -57,7 +57,6 @@
int main(int argc, char **argv)
{
QApplication app(argc, argv);
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
GraphWidget *widget = new GraphWidget;
diff --git a/examples/widgets/itemviews/addressbook/addresswidget.cpp b/examples/widgets/itemviews/addressbook/addresswidget.cpp
index cff35ad78f..143f6266dd 100644
--- a/examples/widgets/itemviews/addressbook/addresswidget.cpp
+++ b/examples/widgets/itemviews/addressbook/addresswidget.cpp
@@ -85,10 +85,7 @@ void AddressWidget::showAddEntryDialog()
//! [3]
void AddressWidget::addEntry(QString name, QString address)
{
- QList<QPair<QString, QString> >list = table->getList();
- QPair<QString, QString> pair(name, address);
-
- if (!list.contains(pair)) {
+ if (!table->getContacts().contains({ name, address })) {
table->insertRows(0, 1, QModelIndex());
QModelIndex index = table->index(0, 0, QModelIndex());
@@ -195,6 +192,12 @@ void AddressWidget::setupTabs()
&QItemSelectionModel::selectionChanged,
this, &AddressWidget::selectionChanged);
+ connect(this, &QTabWidget::currentChanged, this, [this](int tabIndex) {
+ auto *tableView = qobject_cast<QTableView *>(widget(tabIndex));
+ if (tableView)
+ emit selectionChanged(tableView->selectionModel()->selection());
+ });
+
addTab(tableView, str);
}
}
@@ -211,18 +214,16 @@ void AddressWidget::readFromFile(const QString &fileName)
return;
}
- QList<QPair<QString, QString> > pairs = table->getList();
+ QList<Contact> contacts;
QDataStream in(&file);
- in >> pairs;
+ in >> contacts;
- if (pairs.isEmpty()) {
+ if (contacts.isEmpty()) {
QMessageBox::information(this, tr("No contacts in file"),
tr("The file you are attempting to open contains no contacts."));
} else {
- for (int i=0; i<pairs.size(); ++i) {
- QPair<QString, QString> p = pairs.at(i);
- addEntry(p.first, p.second);
- }
+ for (const auto &contact: qAsConst(contacts))
+ addEntry(contact.name, contact.address);
}
}
//! [7]
@@ -237,8 +238,7 @@ void AddressWidget::writeToFile(const QString &fileName)
return;
}
- QList<QPair<QString, QString> > pairs = table->getList();
QDataStream out(&file);
- out << pairs;
+ out << table->getContacts();
}
//! [6]
diff --git a/examples/widgets/itemviews/addressbook/tablemodel.cpp b/examples/widgets/itemviews/addressbook/tablemodel.cpp
index d701ef3223..674e312753 100644
--- a/examples/widgets/itemviews/addressbook/tablemodel.cpp
+++ b/examples/widgets/itemviews/addressbook/tablemodel.cpp
@@ -56,10 +56,10 @@ TableModel::TableModel(QObject *parent)
{
}
-TableModel::TableModel(QList<QPair<QString, QString> > pairs, QObject *parent)
+TableModel::TableModel(QList<Contact> contacts, QObject *parent)
: QAbstractTableModel(parent)
+ , contacts(contacts)
{
- listOfPairs = pairs;
}
//! [0]
@@ -67,7 +67,7 @@ TableModel::TableModel(QList<QPair<QString, QString> > pairs, QObject *parent)
int TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
- return listOfPairs.size();
+ return contacts.size();
}
int TableModel::columnCount(const QModelIndex &parent) const
@@ -83,16 +83,16 @@ QVariant TableModel::data(const QModelIndex &index, int role) const
if (!index.isValid())
return QVariant();
- if (index.row() >= listOfPairs.size() || index.row() < 0)
+ if (index.row() >= contacts.size() || index.row() < 0)
return QVariant();
if (role == Qt::DisplayRole) {
- QPair<QString, QString> pair = listOfPairs.at(index.row());
+ const auto &contact = contacts.at(index.row());
if (index.column() == 0)
- return pair.first;
+ return contact.name;
else if (index.column() == 1)
- return pair.second;
+ return contact.address;
}
return QVariant();
}
@@ -126,10 +126,8 @@ bool TableModel::insertRows(int position, int rows, const QModelIndex &index)
Q_UNUSED(index);
beginInsertRows(QModelIndex(), position, position + rows - 1);
- for (int row = 0; row < rows; ++row) {
- QPair<QString, QString> pair(" ", " ");
- listOfPairs.insert(position, pair);
- }
+ for (int row = 0; row < rows; ++row)
+ contacts.insert(position, { QString(), QString() });
endInsertRows();
return true;
@@ -142,9 +140,8 @@ bool TableModel::removeRows(int position, int rows, const QModelIndex &index)
Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position + rows - 1);
- for (int row = 0; row < rows; ++row) {
- listOfPairs.removeAt(position);
- }
+ for (int row = 0; row < rows; ++row)
+ contacts.removeAt(position);
endRemoveRows();
return true;
@@ -157,16 +154,16 @@ bool TableModel::setData(const QModelIndex &index, const QVariant &value, int ro
if (index.isValid() && role == Qt::EditRole) {
int row = index.row();
- QPair<QString, QString> p = listOfPairs.value(row);
+ auto contact = contacts.value(row);
if (index.column() == 0)
- p.first = value.toString();
+ contact.name = value.toString();
else if (index.column() == 1)
- p.second = value.toString();
+ contact.address = value.toString();
else
return false;
- listOfPairs.replace(row, p);
+ contacts.replace(row, contact);
emit(dataChanged(index, index));
return true;
@@ -187,8 +184,8 @@ Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
//! [7]
//! [8]
-QList< QPair<QString, QString> > TableModel::getList()
+QList<Contact> TableModel::getContacts() const
{
- return listOfPairs;
+ return contacts;
}
//! [8]
diff --git a/examples/widgets/itemviews/addressbook/tablemodel.h b/examples/widgets/itemviews/addressbook/tablemodel.h
index 9a669c508d..1004a35d31 100644
--- a/examples/widgets/itemviews/addressbook/tablemodel.h
+++ b/examples/widgets/itemviews/addressbook/tablemodel.h
@@ -53,16 +53,37 @@
#include <QAbstractTableModel>
#include <QList>
-#include <QPair>
//! [0]
+
+struct Contact
+{
+ QString name;
+ QString address;
+
+ bool operator==(const Contact &other) const
+ {
+ return name == other.name && address == other.address;
+ }
+};
+
+inline QDataStream &operator<<(QDataStream &stream, const Contact &contact)
+{
+ return stream << contact.name << contact.address;
+}
+
+inline QDataStream &operator>>(QDataStream &stream, Contact &contact)
+{
+ return stream >> contact.name >> contact.address;
+}
+
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
TableModel(QObject *parent = 0);
- TableModel(QList<QPair<QString, QString> > listofPairs, QObject *parent = 0);
+ TableModel(QList<Contact> contacts, QObject *parent = 0);
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
@@ -72,10 +93,10 @@ public:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
- QList<QPair<QString, QString> > getList();
+ QList<Contact> getContacts() const;
private:
- QList<QPair<QString, QString> > listOfPairs;
+ QList<Contact> contacts;
};
//! [0]
diff --git a/examples/widgets/itemviews/chart/pieview.cpp b/examples/widgets/itemviews/chart/pieview.cpp
index fb439fae67..3f85e397ee 100644
--- a/examples/widgets/itemviews/chart/pieview.cpp
+++ b/examples/widgets/itemviews/chart/pieview.cpp
@@ -49,12 +49,8 @@
****************************************************************************/
#include <QtWidgets>
+#include <qmath.h>
#include <cmath>
-
-#ifndef M_PI
-#define M_PI 3.1415927
-#endif
-
#include "pieview.h"
PieView::PieView(QWidget *parent)
@@ -125,9 +121,9 @@ QModelIndex PieView::indexAt(const QPoint &point) const
return QModelIndex();
// Determine the angle of the point.
- double angle = (180 / M_PI) * std::acos(cx / d);
- if (cy < 0)
- angle = 360 - angle;
+ double angle = qRadiansToDegrees(std::atan2(cy, cx));
+ if (angle < 0)
+ angle = 360 + angle;
// Find the relevant slice of the pie.
double startAngle = 0.0;
diff --git a/examples/widgets/itemviews/puzzle/main.cpp b/examples/widgets/itemviews/puzzle/main.cpp
index 1f5e7ee9b2..d013bf078d 100644
--- a/examples/widgets/itemviews/puzzle/main.cpp
+++ b/examples/widgets/itemviews/puzzle/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
MainWindow window;
- window.loadImage(":/images/example.jpg");
+ window.loadImage(QStringLiteral(":/images/example.jpg"));
window.show();
return app.exec();
}
diff --git a/examples/widgets/itemviews/puzzle/mainwindow.cpp b/examples/widgets/itemviews/puzzle/mainwindow.cpp
index 282a7b477b..d598dc9017 100644
--- a/examples/widgets/itemviews/puzzle/mainwindow.cpp
+++ b/examples/widgets/itemviews/puzzle/mainwindow.cpp
@@ -69,12 +69,19 @@ MainWindow::MainWindow(QWidget *parent)
void MainWindow::openImage()
{
- const QString fileName =
- QFileDialog::getOpenFileName(this,
- tr("Open Image"), QString(),
- tr("Image Files (*.png *.jpg *.bmp)"));
- if (!fileName.isEmpty())
- loadImage(fileName);
+ const QString directory =
+ QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath());
+ QFileDialog dialog(this, tr("Open Image"), directory);
+ dialog.setAcceptMode(QFileDialog::AcceptOpen);
+ dialog.setFileMode(QFileDialog::ExistingFile);
+ QStringList mimeTypeFilters;
+ for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes())
+ mimeTypeFilters.append(mimeTypeName);
+ mimeTypeFilters.sort();
+ dialog.setMimeTypeFilters(mimeTypeFilters);
+ dialog.selectMimeTypeFilter("image/jpeg");
+ if (dialog.exec() == QDialog::Accepted)
+ loadImage(dialog.selectedFiles().constFirst());
}
void MainWindow::loadImage(const QString &fileName)
@@ -83,7 +90,7 @@ void MainWindow::loadImage(const QString &fileName)
if (!newImage.load(fileName)) {
QMessageBox::warning(this, tr("Open Image"),
tr("The image file could not be loaded."),
- QMessageBox::Cancel);
+ QMessageBox::Close);
return;
}
puzzleImage = newImage;
@@ -107,8 +114,6 @@ void MainWindow::setupPuzzle()
(puzzleImage.height() - size) / 2, size, size).scaled(puzzleWidget->imageSize(),
puzzleWidget->imageSize(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
- qsrand(QCursor::pos().x() ^ QCursor::pos().y());
-
model->addPieces(puzzleImage);
puzzleWidget->clear();
}
@@ -117,19 +122,15 @@ void MainWindow::setupMenus()
{
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
- QAction *openAction = fileMenu->addAction(tr("&Open..."));
+ QAction *openAction = fileMenu->addAction(tr("&Open..."), this, &MainWindow::openImage);
openAction->setShortcuts(QKeySequence::Open);
- QAction *exitAction = fileMenu->addAction(tr("E&xit"));
+ QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QCoreApplication::quit);
exitAction->setShortcuts(QKeySequence::Quit);
QMenu *gameMenu = menuBar()->addMenu(tr("&Game"));
- QAction *restartAction = gameMenu->addAction(tr("&Restart"));
-
- connect(openAction, &QAction::triggered, this, &MainWindow::openImage);
- connect(exitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
- connect(restartAction, &QAction::triggered, this, &MainWindow::setupPuzzle);
+ gameMenu->addAction(tr("&Restart"), this, &MainWindow::setupPuzzle);
}
void MainWindow::setupWidgets()
diff --git a/examples/widgets/itemviews/puzzle/mainwindow.h b/examples/widgets/itemviews/puzzle/mainwindow.h
index 7e27dc6f3a..208d3a5281 100644
--- a/examples/widgets/itemviews/puzzle/mainwindow.h
+++ b/examples/widgets/itemviews/puzzle/mainwindow.h
@@ -65,7 +65,7 @@ class MainWindow : public QMainWindow
Q_OBJECT
public:
- MainWindow(QWidget *parent = 0);
+ explicit MainWindow(QWidget *parent = nullptr);
public slots:
void openImage();
diff --git a/examples/widgets/itemviews/puzzle/piecesmodel.cpp b/examples/widgets/itemviews/puzzle/piecesmodel.cpp
index 0fbf0cdcc2..f0649d3776 100644
--- a/examples/widgets/itemviews/puzzle/piecesmodel.cpp
+++ b/examples/widgets/itemviews/puzzle/piecesmodel.cpp
@@ -52,6 +52,7 @@
#include <QIcon>
#include <QMimeData>
+#include <QRandomGenerator>
PiecesModel::PiecesModel(int pieceSize, QObject *parent)
: QAbstractListModel(parent), m_PieceSize(pieceSize)
@@ -77,7 +78,7 @@ QVariant PiecesModel::data(const QModelIndex &index, int role) const
void PiecesModel::addPiece(const QPixmap &pixmap, const QPoint &location)
{
int row;
- if (int(2.0 * qrand() / (RAND_MAX + 1.0)) == 1)
+ if (QRandomGenerator::global()->bounded(2) == 1)
row = 0;
else
row = pixmaps.size();
diff --git a/examples/widgets/itemviews/puzzle/puzzlewidget.cpp b/examples/widgets/itemviews/puzzle/puzzlewidget.cpp
index 78931a95a3..06968da80f 100644
--- a/examples/widgets/itemviews/puzzle/puzzlewidget.cpp
+++ b/examples/widgets/itemviews/puzzle/puzzlewidget.cpp
@@ -62,9 +62,7 @@ PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent)
void PuzzleWidget::clear()
{
- pieceLocations.clear();
- piecePixmaps.clear();
- pieceRects.clear();
+ pieces.clear();
highlightedRect = QRect();
inPlace = 0;
update();
@@ -110,23 +108,20 @@ void PuzzleWidget::dropEvent(QDropEvent *event)
&& findPiece(targetSquare(event->pos())) == -1) {
QByteArray pieceData = event->mimeData()->data("image/x-puzzle-piece");
- QDataStream stream(&pieceData, QIODevice::ReadOnly);
- QRect square = targetSquare(event->pos());
- QPixmap pixmap;
- QPoint location;
- stream >> pixmap >> location;
+ QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
+ Piece piece;
+ piece.rect = targetSquare(event->pos());
+ dataStream >> piece.pixmap >> piece.location;
- pieceLocations.append(location);
- piecePixmaps.append(pixmap);
- pieceRects.append(square);
+ pieces.append(piece);
highlightedRect = QRect();
- update(square);
+ update(piece.rect);
event->setDropAction(Qt::MoveAction);
event->accept();
- if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) {
+ if (piece.location == piece.rect.topLeft() / pieceSize()) {
inPlace++;
if (inPlace == 25)
emit puzzleCompleted();
@@ -139,8 +134,8 @@ void PuzzleWidget::dropEvent(QDropEvent *event)
int PuzzleWidget::findPiece(const QRect &pieceRect) const
{
- for (int i = 0; i < pieceRects.size(); ++i) {
- if (pieceRect == pieceRects[i])
+ for (int i = 0, size = pieces.size(); i < size; ++i) {
+ if (pieces.at(i).rect == pieceRect)
return i;
}
return -1;
@@ -154,13 +149,9 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
if (found == -1)
return;
- QPoint location = pieceLocations[found];
- QPixmap pixmap = piecePixmaps[found];
- pieceLocations.removeAt(found);
- piecePixmaps.removeAt(found);
- pieceRects.removeAt(found);
+ Piece piece = pieces.takeAt(found);
- if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize()))
+ if (piece.location == square.topLeft() / pieceSize())
inPlace--;
update(square);
@@ -168,7 +159,7 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
- dataStream << pixmap << location;
+ dataStream << piece.pixmap << piece.location;
QMimeData *mimeData = new QMimeData;
mimeData->setData("image/x-puzzle-piece", itemData);
@@ -176,23 +167,20 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setHotSpot(event->pos() - square.topLeft());
- drag->setPixmap(pixmap);
+ drag->setPixmap(piece.pixmap);
- if (drag->start(Qt::MoveAction) == 0) {
- pieceLocations.insert(found, location);
- piecePixmaps.insert(found, pixmap);
- pieceRects.insert(found, square);
+ if (drag->start(Qt::MoveAction) == Qt::IgnoreAction) {
+ pieces.insert(found, piece);
update(targetSquare(event->pos()));
- if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize()))
+ if (piece.location == QPoint(square.x() / pieceSize(), square.y() / pieceSize()))
inPlace++;
}
}
void PuzzleWidget::paintEvent(QPaintEvent *event)
{
- QPainter painter;
- painter.begin(this);
+ QPainter painter(this);
painter.fillRect(event->rect(), Qt::white);
if (highlightedRect.isValid()) {
@@ -201,15 +189,14 @@ void PuzzleWidget::paintEvent(QPaintEvent *event)
painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1));
}
- for (int i = 0; i < pieceRects.size(); ++i) {
- painter.drawPixmap(pieceRects[i], piecePixmaps[i]);
- }
- painter.end();
+ for (const Piece &piece : pieces)
+ painter.drawPixmap(piece.rect, piece.pixmap);
}
const QRect PuzzleWidget::targetSquare(const QPoint &position) const
{
- return QRect(position.x()/pieceSize() * pieceSize(), position.y()/pieceSize() * pieceSize(), pieceSize(), pieceSize());
+ return QRect(position / pieceSize() * pieceSize(),
+ QSize(pieceSize(), pieceSize()));
}
int PuzzleWidget::pieceSize() const
diff --git a/examples/widgets/itemviews/puzzle/puzzlewidget.h b/examples/widgets/itemviews/puzzle/puzzlewidget.h
index 137e0b7162..40dd654af6 100644
--- a/examples/widgets/itemviews/puzzle/puzzlewidget.h
+++ b/examples/widgets/itemviews/puzzle/puzzlewidget.h
@@ -51,9 +51,9 @@
#ifndef PUZZLEWIDGET_H
#define PUZZLEWIDGET_H
-#include <QList>
-#include <QPixmap>
#include <QPoint>
+#include <QPixmap>
+#include <QVector>
#include <QWidget>
QT_BEGIN_NAMESPACE
@@ -67,7 +67,7 @@ class PuzzleWidget : public QWidget
Q_OBJECT
public:
- explicit PuzzleWidget(int imageSize, QWidget *parent = 0);
+ explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr);
void clear();
int pieceSize() const;
@@ -85,12 +85,16 @@ protected:
void paintEvent(QPaintEvent *event) override;
private:
+ struct Piece {
+ QPixmap pixmap;
+ QRect rect;
+ QPoint location;
+ };
+
int findPiece(const QRect &pieceRect) const;
const QRect targetSquare(const QPoint &position) const;
- QList<QPixmap> piecePixmaps;
- QList<QRect> pieceRects;
- QList<QPoint> pieceLocations;
+ QVector<Piece> pieces;
QRect highlightedRect;
int inPlace;
int m_ImageSize;
diff --git a/examples/widgets/itemviews/storageview/main.cpp b/examples/widgets/itemviews/storageview/main.cpp
index c8057186fc..f349e58fad 100644
--- a/examples/widgets/itemviews/storageview/main.cpp
+++ b/examples/widgets/itemviews/storageview/main.cpp
@@ -51,6 +51,7 @@
#include <QtWidgets/QApplication>
#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QShortcut>
#include <QtWidgets/QTreeView>
#include "storagemodel.h"
@@ -60,9 +61,16 @@ int main(int argc, char *argv[])
QApplication a(argc, argv);
QTreeView view;
- view.setModel(new StorageModel(&view));
view.resize(640, 480);
+ view.setWindowTitle("Storage View");
view.setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ StorageModel *model = new StorageModel(&view);
+ model->refresh();
+ QShortcut *refreshShortcut = new QShortcut(Qt::CTRL + Qt::Key_R, &view);
+ QObject::connect(refreshShortcut, &QShortcut::activated, model, &StorageModel::refresh);
+ view.setModel(model);
+
int columnCount = view.model()->columnCount();
for (int c = 0; c < columnCount; ++c)
view.resizeColumnToContents(c);
diff --git a/examples/widgets/itemviews/storageview/storagemodel.cpp b/examples/widgets/itemviews/storageview/storagemodel.cpp
index b7c594f8f7..063f126d86 100644
--- a/examples/widgets/itemviews/storageview/storagemodel.cpp
+++ b/examples/widgets/itemviews/storageview/storagemodel.cpp
@@ -52,29 +52,27 @@
#include "storagemodel.h"
#include <QDir>
+#include <QLocale>
#include <qmath.h>
+#include <algorithm>
#include <cmath>
-static QString sizeToString(qint64 size)
+StorageModel::StorageModel(QObject *parent) :
+ QAbstractTableModel(parent)
{
- static const char *const strings[] = { "b", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
-
- if (size <= 0)
- return StorageModel::tr("0 b");
-
- double power = std::log((double)size)/std::log(1024.0);
- int intPower = (int)power;
- intPower = intPower >= 8 ? 8 - 1 : intPower;
-
- double normSize = size / std::pow(1024.0, intPower);
- //: this should expand to "1.23 GB"
- return StorageModel::tr("%1 %2").arg(normSize, 0, 'f', intPower > 0 ? 2 : 0).arg(strings[intPower]);
}
-StorageModel::StorageModel(QObject *parent) :
- QAbstractTableModel(parent),
- m_volumes(QStorageInfo::mountedVolumes())
+void StorageModel::refresh()
{
+ beginResetModel();
+ m_volumes = QStorageInfo::mountedVolumes();
+ std::sort(m_volumes.begin(), m_volumes.end(),
+ [](const QStorageInfo &st1, const QStorageInfo &st2) {
+ static const QString rootSortString = QStringLiteral(" ");
+ return (st1.isRoot() ? rootSortString : st1.rootPath())
+ < (st2.isRoot() ? rootSortString : st2.rootPath());
+ });
+ endResetModel();
}
int StorageModel::columnCount(const QModelIndex &/*parent*/) const
@@ -89,6 +87,22 @@ int StorageModel::rowCount(const QModelIndex &parent) const
return m_volumes.count();
}
+Qt::ItemFlags StorageModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags result = QAbstractTableModel::flags(index);
+ switch (index.column()) {
+ case ColumnAvailable:
+ case ColumnIsReady:
+ case ColumnIsReadOnly:
+ case ColumnIsValid:
+ result |= Qt::ItemIsUserCheckable;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
QVariant StorageModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
@@ -106,11 +120,17 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
case ColumnFileSystemName:
return volume.fileSystemType();
case ColumnTotal:
- return sizeToString(volume.bytesTotal());
+ return QLocale().formattedDataSize(volume.bytesTotal());
case ColumnFree:
- return sizeToString(volume.bytesFree());
+ return QLocale().formattedDataSize(volume.bytesFree());
case ColumnAvailable:
- return sizeToString(volume.bytesAvailable());
+ return QLocale().formattedDataSize(volume.bytesAvailable());
+ default:
+ break;
+ }
+ } else if (role == Qt::CheckStateRole) {
+ const QStorageInfo &volume = m_volumes.at(index.row());
+ switch (index.column()) {
case ColumnIsReady:
return volume.isReady();
case ColumnIsReadOnly:
@@ -120,7 +140,18 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
default:
break;
}
+ } else if (role == Qt::TextAlignmentRole) {
+ switch (index.column()) {
+ case ColumnTotal:
+ case ColumnFree:
+ case ColumnAvailable:
+ return Qt::AlignTrailing;
+ default:
+ break;
+ }
+ return Qt::AlignLeading;
} else if (role == Qt::ToolTipRole) {
+ QLocale locale;
const QStorageInfo &volume = m_volumes.at(index.row());
return tr("Root path : %1\n"
"Name: %2\n"
@@ -140,9 +171,9 @@ QVariant StorageModel::data(const QModelIndex &index, int role) const
arg(volume.displayName()).
arg(QString::fromUtf8(volume.device())).
arg(QString::fromUtf8(volume.fileSystemType())).
- arg(sizeToString(volume.bytesTotal())).
- arg(sizeToString(volume.bytesFree())).
- arg(sizeToString(volume.bytesAvailable())).
+ arg(locale.formattedDataSize(volume.bytesTotal())).
+ arg(locale.formattedDataSize(volume.bytesFree())).
+ arg(locale.formattedDataSize(volume.bytesAvailable())).
arg(volume.isReady() ? tr("true") : tr("false")).
arg(volume.isReadOnly() ? tr("true") : tr("false")).
arg(volume.isValid() ? tr("true") : tr("false")).
@@ -161,13 +192,13 @@ QVariant StorageModel::headerData(int section, Qt::Orientation orientation, int
switch (section) {
case ColumnRootPath:
- return tr("Root path");
+ return tr("Root Path");
case ColumnName:
return tr("Volume Name");
case ColumnDevice:
return tr("Device");
case ColumnFileSystemName:
- return tr("File system");
+ return tr("File System");
case ColumnTotal:
return tr("Total");
case ColumnFree:
diff --git a/examples/widgets/itemviews/storageview/storagemodel.h b/examples/widgets/itemviews/storageview/storagemodel.h
index 2b37414d8d..787b2f04de 100644
--- a/examples/widgets/itemviews/storageview/storagemodel.h
+++ b/examples/widgets/itemviews/storageview/storagemodel.h
@@ -74,13 +74,17 @@ public:
ColumnCount
};
- explicit StorageModel(QObject *parent = 0);
+ explicit StorageModel(QObject *parent = nullptr);
- int columnCount(const QModelIndex &parent) const;
- int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const override;
+ int rowCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const;
- QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+public slots:
+ void refresh();
private:
QList<QStorageInfo> m_volumes;
diff --git a/examples/widgets/mainwindows/mainwindow/mainwindow.cpp b/examples/widgets/mainwindows/mainwindow/mainwindow.cpp
index 10e3dd045a..afceddfca1 100644
--- a/examples/widgets/mainwindows/mainwindow/mainwindow.cpp
+++ b/examples/widgets/mainwindows/mainwindow/mainwindow.cpp
@@ -63,7 +63,6 @@
#include <QFileDialog>
#include <QDialogButtonBox>
#include <QMessageBox>
-#include <QSignalMapper>
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
diff --git a/examples/widgets/mainwindows/mainwindow/toolbar.cpp b/examples/widgets/mainwindows/mainwindow/toolbar.cpp
index 97152a64a3..814cfc7f4d 100644
--- a/examples/widgets/mainwindows/mainwindow/toolbar.cpp
+++ b/examples/widgets/mainwindows/mainwindow/toolbar.cpp
@@ -50,6 +50,8 @@
#include "toolbar.h"
+#include <QRandomGenerator>
+
#include <QMainWindow>
#include <QMenu>
#include <QPainter>
@@ -257,7 +259,7 @@ void ToolBar::randomize()
QList<QAction *> randomized;
QList<QAction *> actions = this->actions();
while (!actions.isEmpty()) {
- QAction *action = actions.takeAt(rand() % actions.size());
+ QAction *action = actions.takeAt(QRandomGenerator::global()->bounded(actions.size()));
randomized.append(action);
}
clear();
diff --git a/examples/widgets/painting/affine/xform.cpp b/examples/widgets/painting/affine/xform.cpp
index e47bc9d251..20f6eb3c6d 100644
--- a/examples/widgets/painting/affine/xform.cpp
+++ b/examples/widgets/painting/affine/xform.cpp
@@ -77,8 +77,8 @@ XFormView::XFormView(QWidget *parent)
pts->setBoundingRect(QRectF(0, 0, 500, 500));
ctrlPoints << QPointF(250, 250) << QPointF(350, 250);
pts->setPoints(ctrlPoints);
- connect(pts, SIGNAL(pointsChanged(QPolygonF)),
- this, SLOT(updateCtrlPoints(QPolygonF)));
+ connect(pts, &HoverPoints::pointsChanged,
+ this,&XFormView::updateCtrlPoints);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
@@ -876,29 +876,29 @@ XFormWidget::XFormWidget(QWidget *parent)
#endif
mainGroupLayout->addWidget(whatsThisButton);
- connect(rotateSlider, SIGNAL(valueChanged(int)), view, SLOT(changeRotation(int)));
- connect(shearSlider, SIGNAL(valueChanged(int)), view, SLOT(changeShear(int)));
- connect(scaleSlider, SIGNAL(valueChanged(int)), view, SLOT(changeScale(int)));
-
- connect(vectorType, SIGNAL(clicked()), view, SLOT(setVectorType()));
- connect(pixmapType, SIGNAL(clicked()), view, SLOT(setPixmapType()));
- connect(textType, SIGNAL(clicked()), view, SLOT(setTextType()));
- connect(textType, SIGNAL(toggled(bool)), textEditor, SLOT(setEnabled(bool)));
- connect(textEditor, SIGNAL(textChanged(QString)), view, SLOT(setText(QString)));
-
- connect(view, SIGNAL(rotationChanged(int)), rotateSlider, SLOT(setValue(int)));
- connect(view, SIGNAL(scaleChanged(int)), scaleSlider, SLOT(setValue(int)));
- connect(view, SIGNAL(shearChanged(int)), shearSlider, SLOT(setValue(int)));
-
- connect(resetButton, SIGNAL(clicked()), view, SLOT(reset()));
- connect(animateButton, SIGNAL(clicked(bool)), view, SLOT(setAnimation(bool)));
- connect(whatsThisButton, SIGNAL(clicked(bool)), view, SLOT(setDescriptionEnabled(bool)));
- connect(whatsThisButton, SIGNAL(clicked(bool)), view->hoverPoints(), SLOT(setDisabled(bool)));
- connect(view, SIGNAL(descriptionEnabledChanged(bool)), view->hoverPoints(), SLOT(setDisabled(bool)));
- connect(view, SIGNAL(descriptionEnabledChanged(bool)), whatsThisButton, SLOT(setChecked(bool)));
- connect(showSourceButton, SIGNAL(clicked()), view, SLOT(showSource()));
+ connect(rotateSlider, &QSlider::valueChanged, view, &XFormView::changeRotation);
+ connect(shearSlider, &QSlider::valueChanged, view, &XFormView::changeShear);
+ connect(scaleSlider, &QSlider::valueChanged, view, &XFormView::changeScale);
+
+ connect(vectorType, &QRadioButton::clicked, view, &XFormView::setVectorType);
+ connect(pixmapType, &QRadioButton::clicked, view, &XFormView::setPixmapType);
+ connect(textType, &QRadioButton::clicked, view, &XFormView::setTextType);
+ connect(textType, &QRadioButton::toggled, textEditor, &XFormView::setEnabled);
+ connect(textEditor, &QLineEdit::textChanged, view, &XFormView::setText);
+
+ connect(view, &XFormView::rotationChanged, rotateSlider, &QSlider::setValue);
+ connect(view, &XFormView::scaleChanged, scaleSlider, &QAbstractSlider::setValue);
+ connect(view, &XFormView::shearChanged, shearSlider, &QAbstractSlider::setValue);
+
+ connect(resetButton, &QPushButton::clicked, view, &XFormView::reset);
+ connect(animateButton, &QPushButton::clicked, view, &XFormView::setAnimation);
+ connect(whatsThisButton, &QPushButton::clicked, view, &ArthurFrame::setDescriptionEnabled);
+ connect(whatsThisButton, &QPushButton::clicked, view->hoverPoints(), &HoverPoints::setDisabled);
+ connect(view, &XFormView::descriptionEnabledChanged, view->hoverPoints(), &HoverPoints::setDisabled);
+ connect(view, &XFormView::descriptionEnabledChanged, whatsThisButton, &QPushButton::setChecked);
+ connect(showSourceButton, &QPushButton::clicked, view, &XFormView::showSource);
#ifdef QT_OPENGL_SUPPORT
- connect(enableOpenGLButton, SIGNAL(clicked(bool)), view, SLOT(enableOpenGL(bool)));
+ connect(enableOpenGLButton, &QPushButton::clicked, view, &XFormView::enableOpenGL);
#endif
view->loadSourceFile(":res/affine/xform.cpp");
view->loadDescription(":res/affine/xform.html");
diff --git a/examples/widgets/painting/composition/composition.cpp b/examples/widgets/painting/composition/composition.cpp
index d5d674fd83..0b57d3c7d3 100644
--- a/examples/widgets/painting/composition/composition.cpp
+++ b/examples/widgets/painting/composition/composition.cpp
@@ -464,7 +464,7 @@ void CompositionRenderer::paint(QPainter *painter)
drawBase(p);
}
- memcpy(m_buffer.bits(), m_base_buffer.bits(), m_buffer.byteCount());
+ memcpy(m_buffer.bits(), m_base_buffer.bits(), m_buffer.sizeInBytes());
{
QPainter p(&m_buffer);
diff --git a/examples/widgets/painting/painterpaths/window.cpp b/examples/widgets/painting/painterpaths/window.cpp
index 7122411a6c..a987937b39 100644
--- a/examples/widgets/painting/painterpaths/window.cpp
+++ b/examples/widgets/painting/painterpaths/window.cpp
@@ -53,11 +53,7 @@
#include <QtWidgets>
-#include <cmath>
-
-//! [0]
-const float Pi = 3.14159f;
-//! [0]
+#include <qmath.h>
//! [1]
Window::Window()
@@ -133,8 +129,8 @@ Window::Window()
QPainterPath starPath;
starPath.moveTo(90, 50);
for (int i = 1; i < 5; ++i) {
- starPath.lineTo(50 + 40 * std::cos(0.8 * i * Pi),
- 50 + 40 * std::sin(0.8 * i * Pi));
+ starPath.lineTo(50 + 40 * std::cos(0.8 * i * M_PI),
+ 50 + 40 * std::sin(0.8 * i * M_PI));
}
starPath.closeSubpath();
//! [9]
diff --git a/examples/widgets/statemachine/rogue/window.cpp b/examples/widgets/statemachine/rogue/window.cpp
index 428d4c3af6..3515138382 100644
--- a/examples/widgets/statemachine/rogue/window.cpp
+++ b/examples/widgets/statemachine/rogue/window.cpp
@@ -248,11 +248,9 @@ void Window::movePlayer(Direction direction)
void Window::setupMap()
{
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
-
for (int x = 0; x < WIDTH; ++x)
for (int y = 0; y < HEIGHT; ++y) {
- if (x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1 || qrand() % 40 == 0)
+ if (x == 0 || x == WIDTH - 1 || y == 0 || y == HEIGHT - 1 || QRandomGenerator::global()->bounded(40) == 0)
map[x][y] = '#';
else
map[x][y] = '.';
diff --git a/examples/widgets/tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp b/examples/widgets/tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp
index c929ff6922..92620ddd8c 100644
--- a/examples/widgets/tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp
+++ b/examples/widgets/tools/plugandpaint/plugins/basictools/basictoolsplugin.cpp
@@ -50,13 +50,11 @@
#include <QtWidgets>
-#include <cmath>
+#include <qmath.h>
#include <stdlib.h>
#include "basictoolsplugin.h"
-const float Pi = 3.14159f;
-
//! [0]
QStringList BasicToolsPlugin::brushes() const
{
@@ -103,7 +101,7 @@ QRect BasicToolsPlugin::mouseMove(const QString &brush, QPainter &painter,
thickness, thickness);
}
} else if (brush == tr("Random Letters")) {
- QChar ch('A' + (qrand() % 26));
+ QChar ch(QRandomGenerator::global()->bounded('A', 'Z' + 1));
QFont biggerFont = painter.font();
biggerFont.setBold(true);
@@ -149,8 +147,8 @@ QPainterPath BasicToolsPlugin::generateShape(const QString &shape,
} else if (shape == tr("Star")) {
path.moveTo(90, 50);
for (int i = 1; i < 5; ++i) {
- path.lineTo(50 + 40 * std::cos(0.8 * i * Pi),
- 50 + 40 * std::sin(0.8 * i * Pi));
+ path.lineTo(50 + 40 * std::cos(0.8 * i * M_PI),
+ 50 + 40 * std::sin(0.8 * i * M_PI));
}
path.closeSubpath();
} else if (shape == tr("Text...")) {
diff --git a/examples/widgets/tools/undo/mainwindow.cpp b/examples/widgets/tools/undo/mainwindow.cpp
index aa570caa80..5976163f3f 100644
--- a/examples/widgets/tools/undo/mainwindow.cpp
+++ b/examples/widgets/tools/undo/mainwindow.cpp
@@ -52,6 +52,7 @@
#include <QUndoStack>
#include <QFileDialog>
#include <QMessageBox>
+#include <QRandomGenerator>
#include <QTextStream>
#include <QToolButton>
#include "document.h"
@@ -321,7 +322,7 @@ void MainWindow::newDocument()
static QColor randomColor()
{
- int r = (int) (3.0*(rand()/(RAND_MAX + 1.0)));
+ int r = QRandomGenerator::global()->bounded(3);
switch (r) {
case 0:
return Qt::red;
@@ -337,10 +338,10 @@ static QRect randomRect(const QSize &s)
{
QSize min = Shape::minSize;
- int left = (int) ((0.0 + s.width() - min.width())*(rand()/(RAND_MAX + 1.0)));
- int top = (int) ((0.0 + s.height() - min.height())*(rand()/(RAND_MAX + 1.0)));
- int width = (int) ((0.0 + s.width() - left - min.width())*(rand()/(RAND_MAX + 1.0))) + min.width();
- int height = (int) ((0.0 + s.height() - top - min.height())*(rand()/(RAND_MAX + 1.0))) + min.height();
+ int left = (int) ((0.0 + s.width() - min.width())*(QRandomGenerator::global()->bounded(1.0)));
+ int top = (int) ((0.0 + s.height() - min.height())*(QRandomGenerator::global()->bounded(1.0)));
+ int width = (int) ((0.0 + s.width() - left - min.width())*(QRandomGenerator::global()->bounded(1.0))) + min.width();
+ int height = (int) ((0.0 + s.height() - top - min.height())*(QRandomGenerator::global()->bounded(1.0))) + min.height();
return QRect(left, top, width, height);
}
diff --git a/examples/widgets/tools/undoframework/diagramitem.cpp b/examples/widgets/tools/undoframework/diagramitem.cpp
index 754baa2377..723645c9b2 100644
--- a/examples/widgets/tools/undoframework/diagramitem.cpp
+++ b/examples/widgets/tools/undoframework/diagramitem.cpp
@@ -65,8 +65,7 @@ DiagramItem::DiagramItem(DiagramType diagramType, QGraphicsItem *item)
setPolygon(trianglePolygon);
}
- QColor color(static_cast<int>(qrand()) % 256,
- static_cast<int>(qrand()) % 256, static_cast<int>(qrand()) % 256);
+ QColor color(QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256), QRandomGenerator::global()->bounded(256));
QBrush brush(color);
setBrush(brush);
setFlag(QGraphicsItem::ItemIsSelectable);
diff --git a/examples/widgets/widgets/tablet/mainwindow.cpp b/examples/widgets/widgets/tablet/mainwindow.cpp
index 0d63ac316b..feae16dd83 100644
--- a/examples/widgets/widgets/tablet/mainwindow.cpp
+++ b/examples/widgets/widgets/tablet/mainwindow.cpp
@@ -60,6 +60,7 @@ MainWindow::MainWindow(TabletCanvas *canvas)
createMenus();
setWindowTitle(tr("Tablet Example"));
setCentralWidget(m_canvas);
+ QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
}
//! [0]
@@ -97,6 +98,11 @@ void MainWindow::setSaturationValuator(QAction *action)
}
//! [4]
+void MainWindow::setEventCompression(bool compress)
+{
+ QCoreApplication::setAttribute(Qt::AA_CompressTabletEvents, compress);
+}
+
//! [5]
void MainWindow::save()
{
@@ -220,6 +226,10 @@ void MainWindow::createMenus()
connect(colorSaturationGroup, &QActionGroup::triggered,
this, &MainWindow::setSaturationValuator);
+ QAction *compressAction = tabletMenu->addAction(tr("Co&mpress events"));
+ compressAction->setCheckable(true);
+ connect(compressAction, &QAction::toggled, this, &MainWindow::setEventCompression);
+
QMenu *helpMenu = menuBar()->addMenu("&Help");
helpMenu->addAction(tr("A&bout"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
diff --git a/examples/widgets/widgets/tablet/mainwindow.h b/examples/widgets/widgets/tablet/mainwindow.h
index 68af1f1687..4b99324f04 100644
--- a/examples/widgets/widgets/tablet/mainwindow.h
+++ b/examples/widgets/widgets/tablet/mainwindow.h
@@ -71,6 +71,7 @@ private slots:
void setAlphaValuator(QAction *action);
void setLineWidthValuator(QAction *action);
void setSaturationValuator(QAction *action);
+ void setEventCompression(bool compress);
void save();
void load();
void about();
diff --git a/examples/widgets/widgets/tablet/tabletcanvas.cpp b/examples/widgets/widgets/tablet/tabletcanvas.cpp
index 90b3222970..4b11568dfe 100644
--- a/examples/widgets/widgets/tablet/tabletcanvas.cpp
+++ b/examples/widgets/widgets/tablet/tabletcanvas.cpp
@@ -65,21 +65,9 @@ TabletCanvas::TabletCanvas()
, m_deviceDown(false)
{
resize(500, 500);
- initPixmap();
setAutoFillBackground(true);
setAttribute(Qt::WA_TabletTracking);
}
-
-void TabletCanvas::initPixmap()
-{
- QPixmap newPixmap = QPixmap(width(), height());
- newPixmap.fill(Qt::white);
- QPainter painter(&newPixmap);
- if (!m_pixmap.isNull())
- painter.drawPixmap(0, 0, m_pixmap);
- painter.end();
- m_pixmap = newPixmap;
-}
//! [0]
//! [1]
@@ -105,23 +93,26 @@ bool TabletCanvas::loadImage(const QString &file)
//! [3]
void TabletCanvas::tabletEvent(QTabletEvent *event)
{
-
switch (event->type()) {
case QEvent::TabletPress:
if (!m_deviceDown) {
m_deviceDown = true;
lastPoint.pos = event->posF();
+ lastPoint.pressure = event->pressure();
lastPoint.rotation = event->rotation();
}
break;
case QEvent::TabletMove:
+#ifndef Q_OS_IOS
if (event->device() == QTabletEvent::RotationStylus)
updateCursor(event);
+#endif
if (m_deviceDown) {
updateBrush(event);
QPainter painter(&m_pixmap);
paintPixmap(painter, event);
lastPoint.pos = event->posF();
+ lastPoint.pressure = event->pressure();
lastPoint.rotation = event->rotation();
}
break;
@@ -138,8 +129,23 @@ void TabletCanvas::tabletEvent(QTabletEvent *event)
//! [3]
//! [4]
+void TabletCanvas::initPixmap()
+{
+ qreal dpr = devicePixelRatioF();
+ QPixmap newPixmap = QPixmap(width() * dpr, height() * dpr);
+ newPixmap.setDevicePixelRatio(dpr);
+ newPixmap.fill(Qt::white);
+ QPainter painter(&newPixmap);
+ if (!m_pixmap.isNull())
+ painter.drawPixmap(0, 0, m_pixmap);
+ painter.end();
+ m_pixmap = newPixmap;
+}
+
void TabletCanvas::paintEvent(QPaintEvent *)
{
+ if (m_pixmap.isNull())
+ initPixmap();
QPainter painter(this);
painter.drawPixmap(0, 0, m_pixmap);
}
@@ -171,13 +177,14 @@ void TabletCanvas::paintPixmap(QPainter &painter, QTabletEvent *event)
painter.setPen(Qt::NoPen);
painter.setBrush(m_brush);
QPolygonF poly;
- qreal halfWidth = m_pen.widthF();
- QPointF brushAdjust(qSin(qDegreesToRadians(lastPoint.rotation)) * halfWidth,
- qCos(qDegreesToRadians(lastPoint.rotation)) * halfWidth);
+ qreal halfWidth = pressureToWidth(lastPoint.pressure);
+ QPointF brushAdjust(qSin(qDegreesToRadians(-lastPoint.rotation)) * halfWidth,
+ qCos(qDegreesToRadians(-lastPoint.rotation)) * halfWidth);
poly << lastPoint.pos + brushAdjust;
poly << lastPoint.pos - brushAdjust;
- brushAdjust = QPointF(qSin(qDegreesToRadians(event->rotation())) * halfWidth,
- qCos(qDegreesToRadians(event->rotation())) * halfWidth);
+ halfWidth = m_pen.widthF();
+ brushAdjust = QPointF(qSin(qDegreesToRadians(-event->rotation())) * halfWidth,
+ qCos(qDegreesToRadians(-event->rotation())) * halfWidth);
poly << event->posF() - brushAdjust;
poly << event->posF() + brushAdjust;
painter.drawConvexPolygon(poly);
@@ -215,6 +222,11 @@ void TabletCanvas::paintPixmap(QPainter &painter, QTabletEvent *event)
}
//! [5]
+qreal TabletCanvas::pressureToWidth(qreal pressure)
+{
+ return pressure * 10 + 1;
+}
+
//! [7]
void TabletCanvas::updateBrush(const QTabletEvent *event)
{
@@ -260,7 +272,7 @@ void TabletCanvas::updateBrush(const QTabletEvent *event)
//! [9] //! [10]
switch (m_lineWidthValuator) {
case PressureValuator:
- m_pen.setWidthF(event->pressure() * 10 + 1);
+ m_pen.setWidthF(pressureToWidth(event->pressure()));
break;
case TiltValuator:
m_pen.setWidthF(maximum(abs(vValue - 127), abs(hValue - 127)) / 12);
@@ -305,7 +317,7 @@ void TabletCanvas::updateCursor(const QTabletEvent *event)
QPainter painter(&img);
QTransform transform = painter.transform();
transform.translate(16, 16);
- transform.rotate(-event->rotation());
+ transform.rotate(event->rotation());
painter.setTransform(transform);
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.drawImage(-24, -24, origImg);
diff --git a/examples/widgets/widgets/tablet/tabletcanvas.h b/examples/widgets/widgets/tablet/tabletcanvas.h
index 1784e05916..a1b31c65bf 100644
--- a/examples/widgets/widgets/tablet/tabletcanvas.h
+++ b/examples/widgets/widgets/tablet/tabletcanvas.h
@@ -103,6 +103,7 @@ private:
void initPixmap();
void paintPixmap(QPainter &painter, QTabletEvent *event);
Qt::BrushStyle brushPattern(qreal value);
+ qreal pressureToWidth(qreal pressure);
void updateBrush(const QTabletEvent *event);
void updateCursor(const QTabletEvent *event);
@@ -117,6 +118,7 @@ private:
struct Point {
QPointF pos;
+ qreal pressure;
qreal rotation;
} lastPoint;
};
diff --git a/examples/widgets/widgets/tetrix/main.cpp b/examples/widgets/widgets/tetrix/main.cpp
index 886e94de7c..2698190e76 100644
--- a/examples/widgets/widgets/tetrix/main.cpp
+++ b/examples/widgets/widgets/tetrix/main.cpp
@@ -59,6 +59,5 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
TetrixWindow window;
window.show();
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
return app.exec();
}
diff --git a/examples/widgets/widgets/tetrix/tetrixpiece.cpp b/examples/widgets/widgets/tetrix/tetrixpiece.cpp
index 69e1733ac4..3d8fa86860 100644
--- a/examples/widgets/widgets/tetrix/tetrixpiece.cpp
+++ b/examples/widgets/widgets/tetrix/tetrixpiece.cpp
@@ -57,7 +57,7 @@
//! [0]
void TetrixPiece::setRandomShape()
{
- setShape(TetrixShape(qrand() % 7 + 1));
+ setShape(TetrixShape(QRandomGenerator::global()->bounded(7) + 1));
}
//! [0]
diff --git a/examples/widgets/widgets/tooltips/main.cpp b/examples/widgets/widgets/tooltips/main.cpp
index 3c64a33a4c..8276b3dc8d 100644
--- a/examples/widgets/widgets/tooltips/main.cpp
+++ b/examples/widgets/widgets/tooltips/main.cpp
@@ -57,7 +57,6 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(tooltips);
QApplication app(argc, argv);
- qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
SortingBox sortingBox;
sortingBox.show();
return app.exec();
diff --git a/examples/widgets/widgets/tooltips/sortingbox.cpp b/examples/widgets/widgets/tooltips/sortingbox.cpp
index c15fdcf95b..4769a30c64 100644
--- a/examples/widgets/widgets/tooltips/sortingbox.cpp
+++ b/examples/widgets/widgets/tooltips/sortingbox.cpp
@@ -292,7 +292,7 @@ QPoint SortingBox::initialItemPosition(const QPainterPath &path)
//! [24]
QPoint SortingBox::randomItemPosition()
{
- return QPoint(qrand() % (width() - 120), qrand() % (height() - 120));
+ return QPoint(QRandomGenerator::global()->bounded(width() - 120), QRandomGenerator::global()->bounded(height() - 120));
}
//! [24]
@@ -306,6 +306,6 @@ QColor SortingBox::initialItemColor()
//! [26]
QColor SortingBox::randomItemColor()
{
- return QColor::fromHsv(qrand() % 256, 255, 190);
+ return QColor::fromHsv(QRandomGenerator::global()->bounded(256), 255, 190);
}
//! [26]
diff --git a/examples/xml/dombookmarks/mainwindow.cpp b/examples/xml/dombookmarks/mainwindow.cpp
index e0f208d336..fade2dfc96 100644
--- a/examples/xml/dombookmarks/mainwindow.cpp
+++ b/examples/xml/dombookmarks/mainwindow.cpp
@@ -58,13 +58,13 @@ MainWindow::MainWindow()
xbelTree = new XbelTree;
setCentralWidget(xbelTree);
- createActions();
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("DOM Bookmarks"));
- resize(480, 320);
+ const QSize availableSize = QApplication::desktop()->availableGeometry(this).size();
+ resize(availableSize.width() / 2, availableSize.height() / 3);
}
void MainWindow::open()
@@ -80,8 +80,8 @@ void MainWindow::open()
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot read file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
+ .arg(QDir::toNativeSeparators(fileName),
+ file.errorString()));
return;
}
@@ -102,8 +102,8 @@ void MainWindow::saveAs()
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot write file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
+ .arg(QDir::toNativeSeparators(fileName),
+ file.errorString()));
return;
}
@@ -119,37 +119,21 @@ void MainWindow::about()
"documents."));
}
-void MainWindow::createActions()
+void MainWindow::createMenus()
{
- openAct = new QAction(tr("&Open..."), this);
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+ QAction *openAct = fileMenu->addAction(tr("&Open..."), this, &MainWindow::open);
openAct->setShortcuts(QKeySequence::Open);
- connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
- saveAsAct = new QAction(tr("&Save As..."), this);
+ QAction *saveAsAct = fileMenu->addAction(tr("&Save As..."), this, &MainWindow::saveAs);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
- connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
- exitAct = new QAction(tr("E&xit"), this);
+ QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
- connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
-
- aboutAct = new QAction(tr("&About"), this);
- connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
-
- aboutQtAct = new QAction(tr("About &Qt"), this);
- connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
-}
-
-void MainWindow::createMenus()
-{
- fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(openAct);
- fileMenu->addAction(saveAsAct);
- fileMenu->addAction(exitAct);
menuBar()->addSeparator();
- helpMenu = menuBar()->addMenu(tr("&Help"));
- helpMenu->addAction(aboutAct);
- helpMenu->addAction(aboutQtAct);
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(tr("&About"), this, &MainWindow::about);
+ helpMenu->addAction(tr("About &Qt"), qApp, &QCoreApplication::quit);
}
diff --git a/examples/xml/dombookmarks/mainwindow.h b/examples/xml/dombookmarks/mainwindow.h
index 6d490caf64..0a8c7bdd82 100644
--- a/examples/xml/dombookmarks/mainwindow.h
+++ b/examples/xml/dombookmarks/mainwindow.h
@@ -68,18 +68,9 @@ public slots:
void about();
private:
- void createActions();
void createMenus();
XbelTree *xbelTree;
-
- QMenu *fileMenu;
- QMenu *helpMenu;
- QAction *openAct;
- QAction *saveAsAct;
- QAction *exitAct;
- QAction *aboutAct;
- QAction *aboutQtAct;
};
#endif
diff --git a/examples/xml/dombookmarks/xbeltree.cpp b/examples/xml/dombookmarks/xbeltree.cpp
index 82afc48bd9..f7ff1de638 100644
--- a/examples/xml/dombookmarks/xbeltree.cpp
+++ b/examples/xml/dombookmarks/xbeltree.cpp
@@ -52,6 +52,18 @@
#include "xbeltree.h"
+enum { DomElementRole = Qt::UserRole + 1 };
+
+Q_DECLARE_METATYPE(QDomElement)
+
+static inline QString titleElement() { return QStringLiteral("title"); }
+static inline QString folderElement() { return QStringLiteral("folder"); }
+static inline QString bookmarkElement() { return QStringLiteral("bookmark"); }
+
+static inline QString versionAttribute() { return QStringLiteral("version"); }
+static inline QString hrefAttribute() { return QStringLiteral("href"); }
+static inline QString foldedAttribute() { return QStringLiteral("folded"); }
+
XbelTree::XbelTree(QWidget *parent)
: QTreeWidget(parent)
{
@@ -68,6 +80,24 @@ XbelTree::XbelTree(QWidget *parent)
bookmarkIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
}
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+void XbelTree::contextMenuEvent(QContextMenuEvent *event)
+{
+ const QTreeWidgetItem *item = itemAt(event->pos());
+ if (!item)
+ return;
+ const QString url = item->text(1);
+ QMenu contextMenu;
+ QAction *copyAction = contextMenu.addAction(tr("Copy Link to Clipboard"));
+ QAction *openAction = contextMenu.addAction(tr("Open"));
+ QAction *action = contextMenu.exec(event->globalPos());
+ if (action == copyAction)
+ QGuiApplication::clipboard()->setText(url);
+ else if (action == openAction)
+ QDesktopServices::openUrl(QUrl(url));
+}
+#endif // !QT_NO_CONTEXTMENU && !QT_NO_CLIPBOARD
+
bool XbelTree::read(QIODevice *device)
{
QString errorStr;
@@ -89,8 +119,8 @@ bool XbelTree::read(QIODevice *device)
QMessageBox::information(window(), tr("DOM Bookmarks"),
tr("The file is not an XBEL file."));
return false;
- } else if (root.hasAttribute("version")
- && root.attribute("version") != "1.0") {
+ } else if (root.hasAttribute(versionAttribute())
+ && root.attribute(versionAttribute()) != QLatin1String("1.0")) {
QMessageBox::information(window(), tr("DOM Bookmarks"),
tr("The file is not an XBEL version 1.0 "
"file."));
@@ -99,22 +129,20 @@ bool XbelTree::read(QIODevice *device)
clear();
- disconnect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
- this, SLOT(updateDomElement(QTreeWidgetItem*,int)));
+ disconnect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
- QDomElement child = root.firstChildElement("folder");
+ QDomElement child = root.firstChildElement(folderElement());
while (!child.isNull()) {
parseFolderElement(child);
- child = child.nextSiblingElement("folder");
+ child = child.nextSiblingElement(folderElement());
}
- connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
- this, SLOT(updateDomElement(QTreeWidgetItem*,int)));
+ connect(this, &QTreeWidget::itemChanged, this, &XbelTree::updateDomElement);
return true;
}
-bool XbelTree::write(QIODevice *device)
+bool XbelTree::write(QIODevice *device) const
{
const int IndentSize = 4;
@@ -123,21 +151,21 @@ bool XbelTree::write(QIODevice *device)
return true;
}
-void XbelTree::updateDomElement(QTreeWidgetItem *item, int column)
+void XbelTree::updateDomElement(const QTreeWidgetItem *item, int column)
{
- QDomElement element = domElementForItem.value(item);
+ QDomElement element = item->data(0, DomElementRole).value<QDomElement>();
if (!element.isNull()) {
if (column == 0) {
- QDomElement oldTitleElement = element.firstChildElement("title");
- QDomElement newTitleElement = domDocument.createElement("title");
+ QDomElement oldTitleElement = element.firstChildElement(titleElement());
+ QDomElement newTitleElement = domDocument.createElement(titleElement());
QDomText newTitleText = domDocument.createTextNode(item->text(0));
newTitleElement.appendChild(newTitleText);
element.replaceChild(newTitleElement, oldTitleElement);
} else {
- if (element.tagName() == "bookmark")
- element.setAttribute("href", item->text(1));
+ if (element.tagName() == bookmarkElement())
+ element.setAttribute(hrefAttribute(), item->text(1));
}
}
}
@@ -147,7 +175,7 @@ void XbelTree::parseFolderElement(const QDomElement &element,
{
QTreeWidgetItem *item = createItem(element, parentItem);
- QString title = element.firstChildElement("title").text();
+ QString title = element.firstChildElement(titleElement()).text();
if (title.isEmpty())
title = QObject::tr("Folder");
@@ -155,25 +183,25 @@ void XbelTree::parseFolderElement(const QDomElement &element,
item->setIcon(0, folderIcon);
item->setText(0, title);
- bool folded = (element.attribute("folded") != "no");
+ bool folded = (element.attribute(foldedAttribute()) != QLatin1String("no"));
setItemExpanded(item, !folded);
QDomElement child = element.firstChildElement();
while (!child.isNull()) {
- if (child.tagName() == "folder") {
+ if (child.tagName() == folderElement()) {
parseFolderElement(child, item);
- } else if (child.tagName() == "bookmark") {
+ } else if (child.tagName() == bookmarkElement()) {
QTreeWidgetItem *childItem = createItem(child, item);
- QString title = child.firstChildElement("title").text();
+ QString title = child.firstChildElement(titleElement()).text();
if (title.isEmpty())
title = QObject::tr("Folder");
childItem->setFlags(item->flags() | Qt::ItemIsEditable);
childItem->setIcon(0, bookmarkIcon);
childItem->setText(0, title);
- childItem->setText(1, child.attribute("href"));
- } else if (child.tagName() == "separator") {
+ childItem->setText(1, child.attribute(hrefAttribute()));
+ } else if (child.tagName() == QLatin1String("separator")) {
QTreeWidgetItem *childItem = createItem(child, item);
childItem->setFlags(item->flags() & ~(Qt::ItemIsSelectable | Qt::ItemIsEditable));
childItem->setText(0, QString(30, 0xB7));
@@ -191,6 +219,6 @@ QTreeWidgetItem *XbelTree::createItem(const QDomElement &element,
} else {
item = new QTreeWidgetItem(this);
}
- domElementForItem.insert(item, element);
+ item->setData(0, DomElementRole, QVariant::fromValue(element));
return item;
}
diff --git a/examples/xml/dombookmarks/xbeltree.h b/examples/xml/dombookmarks/xbeltree.h
index bf4b55ea74..f6c7ef8bfe 100644
--- a/examples/xml/dombookmarks/xbeltree.h
+++ b/examples/xml/dombookmarks/xbeltree.h
@@ -52,7 +52,6 @@
#define XBELTREE_H
#include <QDomDocument>
-#include <QHash>
#include <QIcon>
#include <QTreeWidget>
@@ -64,10 +63,15 @@ public:
XbelTree(QWidget *parent = 0);
bool read(QIODevice *device);
- bool write(QIODevice *device);
+ bool write(QIODevice *device) const;
+
+protected:
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+ void contextMenuEvent(QContextMenuEvent *event) Q_DECL_OVERRIDE;
+#endif
private slots:
- void updateDomElement(QTreeWidgetItem *item, int column);
+ void updateDomElement(const QTreeWidgetItem *item, int column);
private:
void parseFolderElement(const QDomElement &element,
@@ -76,7 +80,6 @@ private:
QTreeWidgetItem *parentItem = 0);
QDomDocument domDocument;
- QHash<QTreeWidgetItem *, QDomElement> domElementForItem;
QIcon folderIcon;
QIcon bookmarkIcon;
};
diff --git a/examples/xml/saxbookmarks/mainwindow.cpp b/examples/xml/saxbookmarks/mainwindow.cpp
index 2ce2b9a508..0583cd82cf 100644
--- a/examples/xml/saxbookmarks/mainwindow.cpp
+++ b/examples/xml/saxbookmarks/mainwindow.cpp
@@ -62,17 +62,40 @@ MainWindow::MainWindow()
treeWidget = new QTreeWidget;
treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
treeWidget->setHeaderLabels(labels);
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+ treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(treeWidget, &QWidget::customContextMenuRequested,
+ this, &MainWindow::onCustomContextMenuRequested);
+#endif
setCentralWidget(treeWidget);
- createActions();
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("SAX Bookmarks"));
- resize(480, 320);
+ const QSize availableSize = QApplication::desktop()->availableGeometry(this).size();
+ resize(availableSize.width() / 2, availableSize.height() / 3);
}
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+void MainWindow::onCustomContextMenuRequested(const QPoint &pos)
+{
+ const QTreeWidgetItem *item = treeWidget->itemAt(pos);
+ if (!item)
+ return;
+ const QString url = item->text(1);
+ QMenu contextMenu;
+ QAction *copyAction = contextMenu.addAction(tr("Copy Link to Clipboard"));
+ QAction *openAction = contextMenu.addAction(tr("Open"));
+ QAction *action = contextMenu.exec(treeWidget->viewport()->mapToGlobal(pos));
+ if (action == copyAction)
+ QGuiApplication::clipboard()->setText(url);
+ else if (action == openAction)
+ QDesktopServices::openUrl(QUrl(url));
+}
+#endif // !QT_NO_CONTEXTMENU && !QT_NO_CLIPBOARD
+
void MainWindow::open()
{
QString fileName =
@@ -93,8 +116,8 @@ void MainWindow::open()
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot read file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
+ .arg(QDir::toNativeSeparators(fileName),
+ file.errorString()));
return;
}
@@ -116,8 +139,8 @@ void MainWindow::saveAs()
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("SAX Bookmarks"),
tr("Cannot write file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
+ .arg(QDir::toNativeSeparators(fileName),
+ file.errorString()));
return;
}
@@ -134,37 +157,21 @@ void MainWindow::about()
"hand."));
}
-void MainWindow::createActions()
+void MainWindow::createMenus()
{
- openAct = new QAction(tr("&Open..."), this);
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+ QAction *openAct = fileMenu->addAction(tr("&Open..."), this, &MainWindow::open);
openAct->setShortcuts(QKeySequence::Open);
- connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
- saveAsAct = new QAction(tr("&Save As..."), this);
+ QAction *saveAsAct = fileMenu->addAction(tr("&Save As..."), this, &MainWindow::saveAs);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
- connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
- exitAct = new QAction(tr("E&xit"), this);
+ QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
- connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
-
- aboutAct = new QAction(tr("&About"), this);
- connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
-
- aboutQtAct = new QAction(tr("About &Qt"), this);
- connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
-}
-
-void MainWindow::createMenus()
-{
- fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(openAct);
- fileMenu->addAction(saveAsAct);
- fileMenu->addAction(exitAct);
menuBar()->addSeparator();
- helpMenu = menuBar()->addMenu(tr("&Help"));
- helpMenu->addAction(aboutAct);
- helpMenu->addAction(aboutQtAct);
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(tr("&About"), this, &MainWindow::about);
+ helpMenu->addAction(tr("About &Qt"), qApp, &QCoreApplication::quit);
}
diff --git a/examples/xml/saxbookmarks/mainwindow.h b/examples/xml/saxbookmarks/mainwindow.h
index 828a0ed14e..20a11bb202 100644
--- a/examples/xml/saxbookmarks/mainwindow.h
+++ b/examples/xml/saxbookmarks/mainwindow.h
@@ -68,20 +68,13 @@ public slots:
void open();
void saveAs();
void about();
-
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+ void onCustomContextMenuRequested(const QPoint &pos);
+#endif
private:
- void createActions();
void createMenus();
QTreeWidget *treeWidget;
-
- QMenu *fileMenu;
- QMenu *helpMenu;
- QAction *openAct;
- QAction *saveAsAct;
- QAction *exitAct;
- QAction *aboutAct;
- QAction *aboutQtAct;
};
#endif
diff --git a/examples/xml/saxbookmarks/xbelgenerator.cpp b/examples/xml/saxbookmarks/xbelgenerator.cpp
index 30ce1428e6..ee6f113f9c 100644
--- a/examples/xml/saxbookmarks/xbelgenerator.cpp
+++ b/examples/xml/saxbookmarks/xbelgenerator.cpp
@@ -52,7 +52,7 @@
#include "xbelgenerator.h"
-XbelGenerator::XbelGenerator(QTreeWidget *treeWidget)
+XbelGenerator::XbelGenerator(const QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
}
@@ -81,25 +81,25 @@ QString XbelGenerator::indent(int depth)
QString XbelGenerator::escapedText(const QString &str)
{
QString result = str;
- result.replace("&", "&amp;");
- result.replace("<", "&lt;");
- result.replace(">", "&gt;");
+ result.replace('&', "&amp;");
+ result.replace('<', "&lt;");
+ result.replace('>', "&gt;");
return result;
}
QString XbelGenerator::escapedAttribute(const QString &str)
{
QString result = escapedText(str);
- result.replace("\"", "&quot;");
+ result.replace(QLatin1Char('"'), "&quot;");
result.prepend(QLatin1Char('"'));
result.append(QLatin1Char('"'));
return result;
}
-void XbelGenerator::generateItem(QTreeWidgetItem *item, int depth)
+void XbelGenerator::generateItem(const QTreeWidgetItem *item, int depth)
{
QString tagName = item->data(0, Qt::UserRole).toString();
- if (tagName == "folder") {
+ if (tagName == QLatin1String("folder")) {
bool folded = !treeWidget->isItemExpanded(item);
out << indent(depth) << "<folder folded=\"" << (folded ? "yes" : "no")
<< "\">\n"
@@ -110,7 +110,7 @@ void XbelGenerator::generateItem(QTreeWidgetItem *item, int depth)
generateItem(item->child(i), depth + 1);
out << indent(depth) << "</folder>\n";
- } else if (tagName == "bookmark") {
+ } else if (tagName == QLatin1String("bookmark")) {
out << indent(depth) << "<bookmark";
if (!item->text(1).isEmpty())
out << " href=" << escapedAttribute(item->text(1));
@@ -118,7 +118,7 @@ void XbelGenerator::generateItem(QTreeWidgetItem *item, int depth)
<< indent(depth + 1) << "<title>" << escapedText(item->text(0))
<< "</title>\n"
<< indent(depth) << "</bookmark>\n";
- } else if (tagName == "separator") {
+ } else if (tagName == QLatin1String("separator")) {
out << indent(depth) << "<separator/>\n";
}
}
diff --git a/examples/xml/saxbookmarks/xbelgenerator.h b/examples/xml/saxbookmarks/xbelgenerator.h
index 44069599e2..abfabfd75c 100644
--- a/examples/xml/saxbookmarks/xbelgenerator.h
+++ b/examples/xml/saxbookmarks/xbelgenerator.h
@@ -61,7 +61,7 @@ QT_END_NAMESPACE
class XbelGenerator
{
public:
- XbelGenerator(QTreeWidget *treeWidget);
+ explicit XbelGenerator(const QTreeWidget *treeWidget);
bool write(QIODevice *device);
@@ -69,9 +69,9 @@ private:
static QString indent(int indentLevel);
static QString escapedText(const QString &str);
static QString escapedAttribute(const QString &str);
- void generateItem(QTreeWidgetItem *item, int depth);
+ void generateItem(const QTreeWidgetItem *item, int depth);
- QTreeWidget *treeWidget;
+ const QTreeWidget *treeWidget;
QTextStream out;
};
diff --git a/examples/xml/saxbookmarks/xbelhandler.cpp b/examples/xml/saxbookmarks/xbelhandler.cpp
index 03b16c81f1..7e2a9db3c2 100644
--- a/examples/xml/saxbookmarks/xbelhandler.cpp
+++ b/examples/xml/saxbookmarks/xbelhandler.cpp
@@ -52,6 +52,10 @@
#include "xbelhandler.h"
+static inline QString versionAttribute() { return QStringLiteral("version"); }
+static inline QString hrefAttribute() { return QStringLiteral("href"); }
+static inline QString foldedAttribute() { return QStringLiteral("folded"); }
+
XbelHandler::XbelHandler(QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
@@ -72,32 +76,32 @@ bool XbelHandler::startElement(const QString & /* namespaceURI */,
const QString &qName,
const QXmlAttributes &attributes)
{
- if (!metXbelTag && qName != "xbel") {
+ if (!metXbelTag && qName != QLatin1String("xbel")) {
errorStr = QObject::tr("The file is not an XBEL file.");
return false;
}
- if (qName == "xbel") {
- QString version = attributes.value("version");
- if (!version.isEmpty() && version != "1.0") {
+ if (qName == QLatin1String("xbel")) {
+ QString version = attributes.value(versionAttribute());
+ if (!version.isEmpty() && version != QLatin1String("1.0")) {
errorStr = QObject::tr("The file is not an XBEL version 1.0 file.");
return false;
}
metXbelTag = true;
- } else if (qName == "folder") {
+ } else if (qName == QLatin1String("folder")) {
item = createChildItem(qName);
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setIcon(0, folderIcon);
item->setText(0, QObject::tr("Folder"));
- bool folded = (attributes.value("folded") != "no");
+ bool folded = (attributes.value(foldedAttribute()) != QLatin1String("no"));
treeWidget->setItemExpanded(item, !folded);
- } else if (qName == "bookmark") {
+ } else if (qName == QLatin1String("bookmark")) {
item = createChildItem(qName);
item->setFlags(item->flags() | Qt::ItemIsEditable);
item->setIcon(0, bookmarkIcon);
item->setText(0, QObject::tr("Unknown title"));
- item->setText(1, attributes.value("href"));
- } else if (qName == "separator") {
+ item->setText(1, attributes.value(hrefAttribute()));
+ } else if (qName == QLatin1String("separator")) {
item = createChildItem(qName);
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
item->setText(0, QString(30, 0xB7));
@@ -111,11 +115,11 @@ bool XbelHandler::endElement(const QString & /* namespaceURI */,
const QString & /* localName */,
const QString &qName)
{
- if (qName == "title") {
+ if (qName == QLatin1String("title")) {
if (item)
item->setText(0, currentText);
- } else if (qName == "folder" || qName == "bookmark"
- || qName == "separator") {
+ } else if (qName == QLatin1String("folder") || qName == QLatin1String("bookmark")
+ || qName == QLatin1String("separator")) {
item = item->parent();
}
return true;
diff --git a/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc b/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc
index 0720e3eadd..ad093c2098 100644
--- a/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc
+++ b/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc
@@ -167,7 +167,7 @@
add them to the \c fileMenu and \c helpMenu. The connections are as shown
below:
- \snippet streambookmarks/mainwindow.cpp 4
+ \snippet streambookmarks/mainwindow.cpp 5
The \c createMenus() function creates the \c fileMenu and \c helpMenu
and adds the QAction objects to them in order to create the menu shown
diff --git a/examples/xml/streambookmarks/mainwindow.cpp b/examples/xml/streambookmarks/mainwindow.cpp
index 7c0fd8720d..c9a18fa3c4 100644
--- a/examples/xml/streambookmarks/mainwindow.cpp
+++ b/examples/xml/streambookmarks/mainwindow.cpp
@@ -63,18 +63,41 @@ MainWindow::MainWindow()
treeWidget = new QTreeWidget;
treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
treeWidget->setHeaderLabels(labels);
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+ treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(treeWidget, &QWidget::customContextMenuRequested,
+ this, &MainWindow::onCustomContextMenuRequested);
+#endif
setCentralWidget(treeWidget);
- createActions();
createMenus();
statusBar()->showMessage(tr("Ready"));
setWindowTitle(tr("QXmlStream Bookmarks"));
- resize(480, 320);
+ const QSize availableSize = QApplication::desktop()->availableGeometry(this).size();
+ resize(availableSize.width() / 2, availableSize.height() / 3);
}
//! [0]
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+void MainWindow::onCustomContextMenuRequested(const QPoint &pos)
+{
+ const QTreeWidgetItem *item = treeWidget->itemAt(pos);
+ if (!item)
+ return;
+ const QString url = item->text(1);
+ QMenu contextMenu;
+ QAction *copyAction = contextMenu.addAction(tr("Copy Link to Clipboard"));
+ QAction *openAction = contextMenu.addAction(tr("Open"));
+ QAction *action = contextMenu.exec(treeWidget->viewport()->mapToGlobal(pos));
+ if (action == copyAction)
+ QGuiApplication::clipboard()->setText(url);
+ else if (action == openAction)
+ QDesktopServices::openUrl(QUrl(url));
+}
+#endif // !QT_NO_CONTEXTMENU && !QT_NO_CLIPBOARD
+
//! [1]
void MainWindow::open()
{
@@ -92,8 +115,8 @@ void MainWindow::open()
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Cannot read file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
+ .arg(QDir::toNativeSeparators(fileName),
+ file.errorString()));
return;
}
@@ -101,8 +124,8 @@ void MainWindow::open()
if (!reader.read(&file)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Parse error in file %1:\n\n%2")
- .arg(fileName)
- .arg(reader.errorString()));
+ .arg(QDir::toNativeSeparators(fileName),
+ reader.errorString()));
} else {
statusBar()->showMessage(tr("File loaded"), 2000);
}
@@ -124,8 +147,8 @@ void MainWindow::saveAs()
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
tr("Cannot write file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
+ .arg(QDir::toNativeSeparators(fileName),
+ file.errorString()));
return;
}
@@ -144,41 +167,23 @@ void MainWindow::about()
}
//! [3]
-//! [4]
-void MainWindow::createActions()
+//! [5]
+void MainWindow::createMenus()
{
- openAct = new QAction(tr("&Open..."), this);
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+ QAction *openAct = fileMenu->addAction(tr("&Open..."), this, &MainWindow::open);
openAct->setShortcuts(QKeySequence::Open);
- connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
- saveAsAct = new QAction(tr("&Save As..."), this);
+ QAction *saveAsAct = fileMenu->addAction(tr("&Save As..."), this, &MainWindow::saveAs);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
- connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
- exitAct = new QAction(tr("E&xit"), this);
+ QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
- connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
-
- aboutAct = new QAction(tr("&About"), this);
- connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
-
- aboutQtAct = new QAction(tr("About &Qt"), this);
- connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
-}
-//! [4]
-
-//! [5]
-void MainWindow::createMenus()
-{
- fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(openAct);
- fileMenu->addAction(saveAsAct);
- fileMenu->addAction(exitAct);
menuBar()->addSeparator();
- helpMenu = menuBar()->addMenu(tr("&Help"));
- helpMenu->addAction(aboutAct);
- helpMenu->addAction(aboutQtAct);
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(tr("&About"), this, &MainWindow::about);
+ helpMenu->addAction(tr("About &Qt"), qApp, &QCoreApplication::quit);
}
//! [5]
diff --git a/examples/xml/streambookmarks/mainwindow.h b/examples/xml/streambookmarks/mainwindow.h
index 2b6feeb26f..fbdc1e0c62 100644
--- a/examples/xml/streambookmarks/mainwindow.h
+++ b/examples/xml/streambookmarks/mainwindow.h
@@ -69,20 +69,13 @@ public slots:
void open();
void saveAs();
void about();
-
+#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD)
+ void onCustomContextMenuRequested(const QPoint &pos);
+#endif
private:
- void createActions();
void createMenus();
QTreeWidget *treeWidget;
-
- QMenu *fileMenu;
- QMenu *helpMenu;
- QAction *openAct;
- QAction *saveAsAct;
- QAction *exitAct;
- QAction *aboutAct;
- QAction *aboutQtAct;
};
//! [0]
diff --git a/examples/xml/streambookmarks/xbelreader.cpp b/examples/xml/streambookmarks/xbelreader.cpp
index 53d6b94ba0..099985d91e 100644
--- a/examples/xml/streambookmarks/xbelreader.cpp
+++ b/examples/xml/streambookmarks/xbelreader.cpp
@@ -72,10 +72,12 @@ bool XbelReader::read(QIODevice *device)
xml.setDevice(device);
if (xml.readNextStartElement()) {
- if (xml.name() == "xbel" && xml.attributes().value("version") == "1.0")
+ if (xml.name() == QLatin1String("xbel")
+ && xml.attributes().value(versionAttribute()) == QLatin1String("1.0")) {
readXBEL();
- else
+ } else {
xml.raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
+ }
}
return !xml.error();
@@ -95,14 +97,14 @@ QString XbelReader::errorString() const
//! [3]
void XbelReader::readXBEL()
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "xbel");
+ Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("xbel"));
while (xml.readNextStartElement()) {
- if (xml.name() == "folder")
+ if (xml.name() == QLatin1String("folder"))
readFolder(0);
- else if (xml.name() == "bookmark")
+ else if (xml.name() == QLatin1String("bookmark"))
readBookmark(0);
- else if (xml.name() == "separator")
+ else if (xml.name() == QLatin1String("separator"))
readSeparator(0);
else
xml.skipCurrentElement();
@@ -113,7 +115,7 @@ void XbelReader::readXBEL()
//! [4]
void XbelReader::readTitle(QTreeWidgetItem *item)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "title");
+ Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("title"));
QString title = xml.readElementText();
item->setText(0, title);
@@ -123,7 +125,7 @@ void XbelReader::readTitle(QTreeWidgetItem *item)
//! [5]
void XbelReader::readSeparator(QTreeWidgetItem *item)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "separator");
+ Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("separator"));
QTreeWidgetItem *separator = createChildItem(item);
separator->setFlags(item->flags() & ~Qt::ItemIsSelectable);
@@ -134,20 +136,20 @@ void XbelReader::readSeparator(QTreeWidgetItem *item)
void XbelReader::readFolder(QTreeWidgetItem *item)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "folder");
+ Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("folder"));
QTreeWidgetItem *folder = createChildItem(item);
- bool folded = (xml.attributes().value("folded") != "no");
+ bool folded = (xml.attributes().value(foldedAttribute()) != QLatin1String("no"));
treeWidget->setItemExpanded(folder, !folded);
while (xml.readNextStartElement()) {
- if (xml.name() == "title")
+ if (xml.name() == QLatin1String("title"))
readTitle(folder);
- else if (xml.name() == "folder")
+ else if (xml.name() == QLatin1String("folder"))
readFolder(folder);
- else if (xml.name() == "bookmark")
+ else if (xml.name() == QLatin1String("bookmark"))
readBookmark(folder);
- else if (xml.name() == "separator")
+ else if (xml.name() == QLatin1String("separator"))
readSeparator(folder);
else
xml.skipCurrentElement();
@@ -156,16 +158,16 @@ void XbelReader::readFolder(QTreeWidgetItem *item)
void XbelReader::readBookmark(QTreeWidgetItem *item)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "bookmark");
+ Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("bookmark"));
QTreeWidgetItem *bookmark = createChildItem(item);
bookmark->setFlags(bookmark->flags() | Qt::ItemIsEditable);
bookmark->setIcon(0, bookmarkIcon);
bookmark->setText(0, QObject::tr("Unknown title"));
- bookmark->setText(1, xml.attributes().value("href").toString());
+ bookmark->setText(1, xml.attributes().value(hrefAttribute()).toString());
while (xml.readNextStartElement()) {
- if (xml.name() == "title")
+ if (xml.name() == QLatin1String("title"))
readTitle(bookmark);
else
xml.skipCurrentElement();
diff --git a/examples/xml/streambookmarks/xbelreader.h b/examples/xml/streambookmarks/xbelreader.h
index 3175441ddd..fd486a430f 100644
--- a/examples/xml/streambookmarks/xbelreader.h
+++ b/examples/xml/streambookmarks/xbelreader.h
@@ -71,6 +71,10 @@ public:
QString errorString() const;
+ static inline QString versionAttribute() { return QStringLiteral("version"); }
+ static inline QString hrefAttribute() { return QStringLiteral("href"); }
+ static inline QString foldedAttribute() { return QStringLiteral("folded"); }
+
private:
//! [2]
void readXBEL();
diff --git a/examples/xml/streambookmarks/xbelwriter.cpp b/examples/xml/streambookmarks/xbelwriter.cpp
index fdf2e1095e..2959680678 100644
--- a/examples/xml/streambookmarks/xbelwriter.cpp
+++ b/examples/xml/streambookmarks/xbelwriter.cpp
@@ -51,9 +51,14 @@
#include <QtWidgets>
#include "xbelwriter.h"
+#include "xbelreader.h"
+
+static inline QString yesValue() { return QStringLiteral("yes"); }
+static inline QString noValue() { return QStringLiteral("no"); }
+static inline QString titleElement() { return QStringLiteral("title"); }
//! [0]
-XbelWriter::XbelWriter(QTreeWidget *treeWidget)
+XbelWriter::XbelWriter(const QTreeWidget *treeWidget)
: treeWidget(treeWidget)
{
xml.setAutoFormatting(true);
@@ -66,9 +71,9 @@ bool XbelWriter::writeFile(QIODevice *device)
xml.setDevice(device);
xml.writeStartDocument();
- xml.writeDTD("<!DOCTYPE xbel>");
- xml.writeStartElement("xbel");
- xml.writeAttribute("version", "1.0");
+ xml.writeDTD(QStringLiteral("<!DOCTYPE xbel>"));
+ xml.writeStartElement(QStringLiteral("xbel"));
+ xml.writeAttribute(XbelReader::versionAttribute(), QStringLiteral("1.0"));
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
writeItem(treeWidget->topLevelItem(i));
@@ -78,24 +83,24 @@ bool XbelWriter::writeFile(QIODevice *device)
//! [1]
//! [2]
-void XbelWriter::writeItem(QTreeWidgetItem *item)
+void XbelWriter::writeItem(const QTreeWidgetItem *item)
{
QString tagName = item->data(0, Qt::UserRole).toString();
- if (tagName == "folder") {
+ if (tagName == QLatin1String("folder")) {
bool folded = !treeWidget->isItemExpanded(item);
xml.writeStartElement(tagName);
- xml.writeAttribute("folded", folded ? "yes" : "no");
- xml.writeTextElement("title", item->text(0));
+ xml.writeAttribute(XbelReader::foldedAttribute(), folded ? yesValue() : noValue());
+ xml.writeTextElement(titleElement(), item->text(0));
for (int i = 0; i < item->childCount(); ++i)
writeItem(item->child(i));
xml.writeEndElement();
- } else if (tagName == "bookmark") {
+ } else if (tagName == QLatin1String("bookmark")) {
xml.writeStartElement(tagName);
if (!item->text(1).isEmpty())
- xml.writeAttribute("href", item->text(1));
- xml.writeTextElement("title", item->text(0));
+ xml.writeAttribute(XbelReader::hrefAttribute(), item->text(1));
+ xml.writeTextElement(titleElement(), item->text(0));
xml.writeEndElement();
- } else if (tagName == "separator") {
+ } else if (tagName == QLatin1String("separator")) {
xml.writeEmptyElement(tagName);
}
}
diff --git a/examples/xml/streambookmarks/xbelwriter.h b/examples/xml/streambookmarks/xbelwriter.h
index b15bf60e31..465d8f0dc4 100644
--- a/examples/xml/streambookmarks/xbelwriter.h
+++ b/examples/xml/streambookmarks/xbelwriter.h
@@ -62,13 +62,13 @@ QT_END_NAMESPACE
class XbelWriter
{
public:
- XbelWriter(QTreeWidget *treeWidget);
+ explicit XbelWriter(const QTreeWidget *treeWidget);
bool writeFile(QIODevice *device);
private:
- void writeItem(QTreeWidgetItem *item);
+ void writeItem(const QTreeWidgetItem *item);
QXmlStreamWriter xml;
- QTreeWidget *treeWidget;
+ const QTreeWidget *treeWidget;
};
//! [0]