summaryrefslogtreecommitdiffstats
path: root/tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp')
-rw-r--r--tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp1516
1 files changed, 1516 insertions, 0 deletions
diff --git a/tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp b/tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp
new file mode 100644
index 0000000..786ef3a
--- /dev/null
+++ b/tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp
@@ -0,0 +1,1516 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtStudio3D/q3dssurfaceviewer.h>
+#include <QtStudio3D/q3dsviewersettings.h>
+#include <QtStudio3D/q3dspresentation.h>
+#include <QtStudio3D/q3dssceneelement.h>
+#include <QtStudio3D/q3dselement.h>
+#include <QtStudio3D/q3dsdatainput.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qoffscreensurface.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qfile.h>
+#include "../shared/shared_presentations.h"
+
+class tst_Q3DSSurfaceViewer : public QObject
+{
+ Q_OBJECT
+public:
+ tst_Q3DSSurfaceViewer();
+ ~tst_Q3DSSurfaceViewer() {}
+
+private slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+ void testBasics_data();
+ void testBasics();
+ void testSourceChange_data();
+ void testSourceChange();
+ void testSizeChange_data();
+ void testSizeChange();
+ void testUpdateInterval_data();
+ void testUpdateInterval();
+ void testMultiple_data();
+ void testMultiple();
+ void testGrab_data();
+ void testGrab();
+ void testReset_data();
+ void testReset();
+ void testSettings_data();
+ void testSettings();
+ void testPresentation_data();
+ void testPresentation();
+ void testPresentationActivation_data();
+ void testPresentationActivation();
+ void testSceneElement_data();
+ void testSceneElement();
+ void testElement_data();
+ void testElement();
+ void testMouseInput_data();
+ void testMouseInput();
+ void testDataInput_data();
+ void testDataInput();
+
+private:
+ QWindow *createWindow(const QSize &size);
+ QOffscreenSurface *createOffscreen();
+ QOpenGLFramebufferObject *createFbo(const QSize &size);
+
+ // Created viewers are returned via *&viewer parameter rather than return value, so that we can
+ // use QCOMPARE and QVERIFY inside these functions (they require void return value).
+ void createViewer(Q3DSSurfaceViewer *&viewer, QSurface *surface, const QUrl &url,
+ bool autoSize, const QSize &size, int updateInterval, int fboId);
+ void createWindowAndViewer(Q3DSSurfaceViewer *&viewer, const QUrl &url = RED,
+ bool autoSize = true, const QSize &size = QSize(),
+ int updateInterval = 0);
+ void createOffscreenAndViewer(Q3DSSurfaceViewer *&viewer, const QUrl &url = RED,
+ const QSize &size = QSize(), int updateInterval = 0);
+ void checkPixel(Q3DSSurfaceViewer *viewer, const QColor &color,
+ const QPoint &pixel = QPoint(50, 50));
+
+ QWindow *m_window;
+ QOffscreenSurface *m_surface;
+ Q3DSSurfaceViewer *m_viewer;
+ QSurfaceFormat m_format;
+ QOpenGLContext *m_context;
+ QOpenGLFramebufferObject *m_fbo;
+};
+
+tst_Q3DSSurfaceViewer::tst_Q3DSSurfaceViewer()
+ : m_window(nullptr)
+ , m_surface(nullptr)
+ , m_viewer(nullptr)
+ , m_context(nullptr)
+ , m_fbo(nullptr)
+{
+}
+
+//#define DUMP_LOGFILE // Uncomment log Qt 3D Studio internal messages to log.txt file
+void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ Q_UNUSED(context);
+ switch (type) {
+ // case QtDebugMsg:
+ case QtInfoMsg:
+ case QtWarningMsg:
+ case QtCriticalMsg: {
+#ifdef DUMP_LOGFILE
+ QFile file("log.txt");
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
+ QTextStream stream(&file);
+ stream << msg << "\n";
+ }
+ file.close();
+#endif
+ } break; // swallow
+ case QtFatalMsg:
+ QFAIL(msg.toLocal8Bit().constData());
+ }
+}
+
+void tst_Q3DSSurfaceViewer::initTestCase()
+{
+ qInstallMessageHandler(messageOutput);
+#ifdef DUMP_LOGFILE
+ QFile file("log.txt");
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ QTextStream stream(&file);
+ stream << "Log file: " << QTime::currentTime().toString() << "\n";
+ }
+ file.close();
+#endif
+
+ QWindow *dummy = createWindow(QSize(100, 100));
+ m_format = dummy->format();
+ qDebug() << m_format;
+ delete dummy;
+}
+
+void tst_Q3DSSurfaceViewer::init()
+{
+ m_context = new QOpenGLContext();
+ m_context->setFormat(m_format);
+ m_context->create();
+}
+
+void tst_Q3DSSurfaceViewer::cleanup()
+{
+ if (m_window)
+ m_window->close();
+
+ delete m_viewer;
+ m_viewer = nullptr;
+
+ delete m_window;
+ m_window = nullptr;
+
+ delete m_surface;
+ m_surface = nullptr;
+
+ delete m_fbo;
+ m_fbo = nullptr;
+
+ delete m_context;
+ m_context = nullptr;
+}
+
+QWindow *tst_Q3DSSurfaceViewer::createWindow(const QSize &size)
+{
+ QWindow *window = new QWindow();
+
+ window->resize(size);
+ window->setSurfaceType(QSurface::OpenGLSurface);
+ window->setFormat(m_format);
+ window->setTitle(QStringLiteral("Q3DSSurfaceViewer test window"));
+ window->create();
+
+ return window;
+}
+
+QOffscreenSurface *tst_Q3DSSurfaceViewer::createOffscreen()
+{
+ QOffscreenSurface *surface = new QOffscreenSurface();
+ surface->setFormat(m_format);
+ surface->create();
+
+ return surface;
+}
+
+QOpenGLFramebufferObject *tst_Q3DSSurfaceViewer::createFbo(const QSize &size)
+{
+ QOpenGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ return new QOpenGLFramebufferObject(size, fboFormat);
+}
+
+void tst_Q3DSSurfaceViewer::createViewer(Q3DSSurfaceViewer *&viewer, QSurface *surface,
+ const QUrl &url, bool autoSize, const QSize &size,
+ int updateInterval, int fboId)
+{
+ viewer = new Q3DSSurfaceViewer();
+ QSignalSpy spy(viewer, &Q3DSSurfaceViewer::runningChanged);
+
+ viewer->presentation()->setSource(url);
+ QCOMPARE(viewer->presentation()->source(), url);
+
+ QVERIFY(spy.isValid());
+ QCOMPARE(spy.count(), 0);
+
+ viewer->setAutoSize(autoSize);
+ if (!autoSize)
+ viewer->setSize(size);
+ viewer->setUpdateInterval(updateInterval);
+
+ QVERIFY(viewer->create(surface, m_context, fboId));
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(viewer->isRunning());
+
+ QVERIFY(viewer->fboId() == fboId);
+ QVERIFY(viewer->surface() == surface);
+ QVERIFY(viewer->context() == m_context);
+}
+
+void tst_Q3DSSurfaceViewer::createWindowAndViewer(Q3DSSurfaceViewer *&viewer,
+ const QUrl &url, bool autoSize,
+ const QSize &size, int updateInterval)
+{
+ QSize actualSize = size;
+ if (actualSize.isEmpty())
+ actualSize = QSize(300, 200);
+
+ m_window = createWindow(actualSize);
+
+ createViewer(viewer, m_window, url, autoSize, actualSize, updateInterval, 0);
+
+ m_window->show();
+ QGuiApplication::processEvents();
+}
+
+void tst_Q3DSSurfaceViewer::createOffscreenAndViewer(Q3DSSurfaceViewer *&viewer,
+ const QUrl &url, const QSize &size,
+ int updateInterval)
+{
+ QSize actualSize = size;
+ if (actualSize.isEmpty())
+ actualSize = QSize(300, 200);
+
+ m_surface = createOffscreen();
+ m_context->makeCurrent(m_surface);
+ m_fbo = createFbo(actualSize);
+
+ createViewer(viewer, m_surface, url, false, actualSize, updateInterval, m_fbo->handle());
+}
+
+void tst_Q3DSSurfaceViewer::checkPixel(Q3DSSurfaceViewer *viewer, const QColor &color,
+ const QPoint &pixel)
+{
+ // Grab operation is potentially costly, so retry only every second instead of using
+ // QTRY_COMPARE which would try it every 50ms. We also want to wait first as it takes some time
+ // for the presentation to be displayed.
+ QColor grabColor;
+ for (int i = 0; i < 20; i++) {
+ // Note: If checkpixel is ever changed to not have this wait, some
+ // QGuiApplication::processEvents() calls may be necessary in various test cases to
+ // ensure expected signaling order.
+ QTest::qWait(1000);
+ QImage image = viewer->grab(QRect(pixel, QSize(1, 1)));
+ grabColor = QColor(image.pixel(0, 0));
+ if (grabColor == color)
+ break;
+ }
+ QCOMPARE(grabColor, color);
+}
+
+void tst_Q3DSSurfaceViewer::testBasics_data()
+{
+ QTest::addColumn<bool>("isWindow");
+ QTest::newRow("window") << true;
+ QTest::newRow("offscreen") << false;
+}
+
+void tst_Q3DSSurfaceViewer::testBasics()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, RED);
+ else
+ createOffscreenAndViewer(m_viewer, RED);
+
+ QSignalSpy spy(m_viewer, &Q3DSSurfaceViewer::runningChanged);
+ QVERIFY(spy.isValid());
+
+ checkPixel(m_viewer, Qt::red);
+
+ m_viewer->destroy();
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(!m_viewer->isRunning());
+}
+
+void tst_Q3DSSurfaceViewer::testSourceChange_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSourceChange()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, RED);
+ else
+ createOffscreenAndViewer(m_viewer, RED);
+
+ QSignalSpy spy(m_viewer->presentation(), &Q3DSPresentation::sourceChanged);
+ QVERIFY(spy.isValid());
+ QVERIFY(m_viewer->presentation()->source() == RED);
+
+ checkPixel(m_viewer, Qt::red);
+
+ // Different source
+ m_viewer->presentation()->setSource(BLUE);
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(m_viewer->presentation()->source() == BLUE);
+
+ checkPixel(m_viewer, Qt::blue);
+
+ // Reset same source
+ m_viewer->presentation()->setSource(BLUE);
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(m_viewer->presentation()->source() == BLUE);
+
+ checkPixel(m_viewer, Qt::blue);
+
+ // Different source again
+ m_viewer->presentation()->setSource(RED);
+ QCOMPARE(spy.count(), 2);
+ QVERIFY(m_viewer->presentation()->source() == RED);
+
+ checkPixel(m_viewer, Qt::red);
+}
+
+void tst_Q3DSSurfaceViewer::testSizeChange_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSizeChange()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow) {
+ createWindowAndViewer(m_viewer, MIXED, true, QSize(600, 600));
+ } else {
+ // Changing size for offscreen surface means recreating the fbo. There's no guarantee
+ // we can get the same fbo id if we do that, so we would have to reinitialize anyway
+ QSKIP("Skipping size change testing for offscreen surfaces");
+ }
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spy1(m_viewer, &Q3DSSurfaceViewer::sizeChanged);
+ QVERIFY(spy1.isValid());
+ QSignalSpy spy2(m_viewer, &Q3DSSurfaceViewer::autoSizeChanged);
+ QVERIFY(spy2.isValid());
+
+ QPoint leftPoint(m_viewer->size().width() * 11 / 24, m_viewer->size().height() / 2);
+ QPoint rightPoint(m_viewer->size().width() * 13 / 24, m_viewer->size().height() / 2);
+
+ // MIXED presentation has left side blue, right side red
+ checkPixel(m_viewer, Qt::blue, leftPoint);
+ checkPixel(m_viewer, Qt::red, rightPoint);
+
+ m_window->resize(QSize(800, 800));
+ QGuiApplication::processEvents();
+ QCOMPARE(spy1.count(), 1);
+
+ checkPixel(m_viewer, Qt::blue, leftPoint);
+ checkPixel(m_viewer, Qt::blue, rightPoint);
+
+ m_window->resize(QSize(400, 400));
+ QGuiApplication::processEvents();
+ QCOMPARE(spy1.count(), 2);
+
+ checkPixel(m_viewer, Qt::red, leftPoint);
+ checkPixel(m_viewer, Qt::red, rightPoint);
+
+ m_viewer->setAutoSize(false);
+ QCOMPARE(spy2.count(), 1);
+
+ // Size should not change since autosize is no longer on
+ m_window->resize(QSize(600, 600));
+ QGuiApplication::processEvents();
+ QCOMPARE(spy1.count(), 2);
+
+ checkPixel(m_viewer, Qt::red, leftPoint);
+ checkPixel(m_viewer, Qt::red, rightPoint);
+
+ m_viewer->setSize(QSize(700, 700));
+ QCOMPARE(spy1.count(), 3);
+
+ checkPixel(m_viewer, Qt::blue, leftPoint);
+ checkPixel(m_viewer, Qt::blue, rightPoint);
+}
+
+void tst_Q3DSSurfaceViewer::testUpdateInterval_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testUpdateInterval()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, ANIMATION);
+ else
+ createOffscreenAndViewer(m_viewer, ANIMATION);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spy(m_viewer, &Q3DSSurfaceViewer::updateIntervalChanged);
+ QVERIFY(spy.isValid());
+ QVERIFY(m_viewer->updateInterval() == 0);
+
+ checkPixel(m_viewer, Qt::black);
+ {
+ // Grab two images two seconds apart to verify animation is happening
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+
+ }
+ {
+ m_viewer->setUpdateInterval(100000);
+ QVERIFY(m_viewer->updateInterval() == 100000);
+ QCOMPARE(spy.count(), 1);
+ // Can't test if animation actually stopped, as grabbing the viewer forces update on it
+ }
+ {
+ m_viewer->setUpdateInterval(20);
+ QCOMPARE(spy.count(), 2);
+ QVERIFY(m_viewer->updateInterval() == 20);
+
+ // Non-zero interval short enough to see animation
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ }
+ {
+ m_viewer->setUpdateInterval(-1);
+ QCOMPARE(spy.count(), 3);
+ QVERIFY(m_viewer->updateInterval() == -1);
+ // Can't test if animation actually stopped, as grabbing the viewer forces update on it
+ }
+}
+
+void tst_Q3DSSurfaceViewer::testMultiple_data()
+{
+ QTest::addColumn<int>("windowCount");
+ QTest::addColumn<int>("offscreenCount");
+ QTest::newRow("windows") << 2 << 0;
+ QTest::newRow("offscreens") << 0 << 2;
+ QTest::newRow("mixed") << 1 << 1;
+}
+
+void tst_Q3DSSurfaceViewer::testMultiple()
+{
+ QFETCH(int, windowCount);
+ QFETCH(int, offscreenCount);
+
+ QVector<QWindow *> windows;
+ QVector<QOffscreenSurface *> surfaces;
+ QVector<Q3DSSurfaceViewer *> viewers;
+ QVector<QOpenGLFramebufferObject *> fbos;
+
+ int viewerCount = windowCount + offscreenCount;
+ windows.resize(windowCount);
+ surfaces.resize(offscreenCount);
+ fbos.resize(offscreenCount);
+ viewers.resize(viewerCount);
+
+ QSize size(200, 150);
+ QUrl url;
+ for (int i = 0; i < windowCount; i++) {
+ windows[i] = createWindow(size);
+ if (i % 2)
+ url = RED;
+ else
+ url = BLUE;
+ createViewer(viewers[i], windows[i], url, true, size, 0, 0);
+ windows[i]->setPosition(10 + i * 50, 10 + i * 50);
+ windows[i]->show();
+ QGuiApplication::processEvents();
+ }
+ for (int i = 0; i < offscreenCount; i++) {
+ surfaces[i] = createOffscreen();
+ m_context->makeCurrent(surfaces[i]);
+ fbos[i] = createFbo(size);
+ if ((i + windowCount) % 2)
+ url = RED;
+ else
+ url = BLUE;
+ createViewer(viewers[i + windowCount], surfaces[i], url, false, size, 0,
+ fbos[i]->handle());
+ }
+
+ for (int i = 0; i < viewerCount; i++) {
+ if (i % 2)
+ checkPixel(viewers[i], Qt::red);
+ else
+ checkPixel(viewers[i], Qt::blue);
+ }
+
+ for (QWindow *w : windows) {
+ w->close();
+ delete w;
+ }
+ windows.clear();
+
+ for (QOffscreenSurface *s : surfaces)
+ delete s;
+ surfaces.clear();
+
+ for (Q3DSSurfaceViewer *v : viewers)
+ delete v;
+ viewers.clear();
+
+ for (QOpenGLFramebufferObject *f : fbos)
+ delete f;
+ fbos.clear();
+}
+
+void tst_Q3DSSurfaceViewer::testGrab_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testGrab()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MIXED_VERTICAL);
+ else
+ createOffscreenAndViewer(m_viewer, MIXED_VERTICAL);
+
+ // Single pixels
+ int w = m_viewer->size().width();
+ int h = m_viewer->size().height();
+
+ checkPixel(m_viewer, Qt::blue, QPoint(w / 2, h / 4));
+ checkPixel(m_viewer, Qt::red, QPoint(w / 2, 3 * h / 4));
+
+ checkPixel(m_viewer, Qt::blue, QPoint(0, 0));
+ checkPixel(m_viewer, Qt::blue, QPoint(w - 1, 0));
+ checkPixel(m_viewer, Qt::red, QPoint(0, h - 1));
+ checkPixel(m_viewer, Qt::red, QPoint(w - 1, h - 1));
+
+ // Full buffer
+ QImage img = m_viewer->grab();
+ QColor grabColor1 = img.pixel(w / 2, h / 4);
+ QColor grabColor2 = img.pixel(w / 2, 3 * h / 4);
+ QCOMPARE(grabColor1, QColor(Qt::blue));
+ QCOMPARE(grabColor2, QColor(Qt::red));
+
+ // Partial buffer
+ img = m_viewer->grab(QRect(w / 3, h / 3, w / 2, h / 2));
+ grabColor1 = img.pixel(0, 0);
+ grabColor2 = img.pixel(w / 2 - 1, h / 2 - 1);
+ QCOMPARE(grabColor1, QColor(Qt::blue));
+ QCOMPARE(grabColor2, QColor(Qt::red));
+}
+
+void tst_Q3DSSurfaceViewer::testReset_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testReset()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, RED);
+ else
+ createOffscreenAndViewer(m_viewer, RED);
+
+ checkPixel(m_viewer, Qt::red);
+
+ m_viewer->presentation()->setAttribute(QStringLiteral("Scene.Layer.Rectangle.Material"),
+ QStringLiteral("diffuse.r"), QVariant(0.0));
+ m_viewer->presentation()->setAttribute(QStringLiteral("Scene.Layer.Rectangle.Material"),
+ QStringLiteral("diffuse.b"), QVariant(1.0));
+ checkPixel(m_viewer, Qt::blue);
+
+ // Note: reset() is private method now, instead can reload presentation by switching sources
+ // m_viewer->reset();
+ m_viewer->presentation()->setSource(ANIMATION);
+ m_viewer->presentation()->setSource(RED);
+
+ checkPixel(m_viewer, Qt::red);
+}
+
+void tst_Q3DSSurfaceViewer::testSettings_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSettings()
+{
+ QFETCH(bool, isWindow);
+
+ int width = 500;
+ int height = 500;
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, SETTINGS, false, QSize(width, height));
+ else
+ createOffscreenAndViewer(m_viewer, SETTINGS, QSize(width, height));
+
+ Q3DSViewerSettings *s = m_viewer->settings();
+
+ QSignalSpy spy1(s, &Q3DSViewerSettings::matteColorChanged);
+ QSignalSpy spy2(s, &Q3DSViewerSettings::showRenderStatsChanged);
+ QSignalSpy spy4(s, &Q3DSViewerSettings::scaleModeChanged);
+ QVERIFY(spy1.isValid());
+ QVERIFY(spy2.isValid());
+ QVERIFY(spy4.isValid());
+
+ // Check defaults
+ QCOMPARE(s->matteColor(), QColor(Qt::black));
+ QCOMPARE(s->isShowRenderStats(), false);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeCenter);
+
+ // Matte
+ checkPixel(m_viewer, Qt::black);
+
+ s->setMatteColor(Qt::cyan);
+ QCOMPARE(s->matteColor(), QColor(Qt::cyan));
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 0);
+ QCOMPARE(spy4.count(), 0);
+
+ checkPixel(m_viewer, Qt::cyan);
+
+ // Render stats
+ QImage image1 = m_viewer->grab();
+
+ s->setShowRenderStats(true);
+ QCOMPARE(s->isShowRenderStats(), true);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy4.count(), 0);
+
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+
+ s->setShowRenderStats(false);
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy4.count(), 0);
+
+ // ScaleMode
+ checkPixel(m_viewer, Qt::cyan);
+ checkPixel(m_viewer, Qt::cyan, QPoint(50, height / 2));
+ s->setScaleMode(Q3DSViewerSettings::ScaleModeFit);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFit);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy4.count(), 1);
+
+ checkPixel(m_viewer, Qt::cyan);
+ checkPixel(m_viewer, Qt::red, QPoint(50, height / 2));
+
+ s->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFill);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+
+ checkPixel(m_viewer, Qt::blue);
+ checkPixel(m_viewer, Qt::red, QPoint(50, height / 2));
+
+ // Saving & loading settings
+ s->save(QStringLiteral("testViewer"), QStringLiteral("The Qt Company"),
+ QStringLiteral("tst_q3dsurfaceviewer"));
+
+ image1 = m_viewer->grab();
+
+ s->setMatteColor(Qt::yellow);
+ s->setShowRenderStats(true);
+ s->setScaleMode(Q3DSViewerSettings::ScaleModeFit);
+
+ QCOMPARE(s->matteColor(), QColor(Qt::yellow));
+ QCOMPARE(s->isShowRenderStats(), true);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFit);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 3);
+ QCOMPARE(spy4.count(), 3);
+
+ image2 = m_viewer->grab();
+
+ s->load(QStringLiteral("testViewer"), QStringLiteral("The Qt Company"),
+ QStringLiteral("tst_q3dsurfaceviewer"));
+
+ QCOMPARE(s->matteColor(), QColor(Qt::cyan));
+ QCOMPARE(s->isShowRenderStats(), false);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFill);
+
+ QCOMPARE(spy1.count(), 3);
+ QCOMPARE(spy2.count(), 4);
+ QCOMPARE(spy4.count(), 4);
+
+ QImage image3 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ QVERIFY(image3 != image2);
+ QVERIFY(image1 == image3);
+
+ // Clean up the settings so they don't pollute the system (and we have clean slate next time)
+ QSettings(QStringLiteral("The Qt Company"), QStringLiteral("tst_q3dsurfaceviewer")).clear();
+}
+
+void tst_Q3DSSurfaceViewer::testPresentation_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testPresentation()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MULTISLIDE);
+ else
+ createOffscreenAndViewer(m_viewer, MULTISLIDE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QList<QVariant> args;
+ Q3DSPresentation *p = m_viewer->presentation();
+ QSignalSpy spy1(p, &Q3DSPresentation::slideEntered);
+ QSignalSpy spy2(p, &Q3DSPresentation::slideExited);
+ QVERIFY(spy1.isValid());
+ QVERIFY(spy2.isValid());
+
+ // There are three different "scenes":
+ // The main Scene, three slides: S1, S2, S3
+ // Two components on Scene.Layer:
+ // Scene.Layer.Component1, two slides: C1S1, C1S2
+ // Scene.Layer.Component2, two slides: C2S1, C2S2
+ // The component slides also get enter when parent slide is entered, but they do not get
+ // the corresponding exit if parent slide is exited.
+ QString path = QStringLiteral("Scene");
+ QString pathC1 = QStringLiteral("Scene.Layer.Component1");
+ QString pathC2 = QStringLiteral("Scene.Layer.Component2");
+ QPoint mainPoint(m_viewer->size().width() * 2 / 8, m_viewer->size().height() / 2);
+ QPoint bgPoint(m_viewer->size().width() * 2 / 8, m_viewer->size().height() / 32);
+ QPoint c1Point(m_viewer->size().width() * 5 / 8, m_viewer->size().height() / 2);
+ QPoint c2Point(m_viewer->size().width() * 7 / 8, m_viewer->size().height() / 2);
+
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ QCOMPARE(spy1.count(), 3);
+ QCOMPARE(spy2.count(), 0);
+
+ // String Attribute
+ QImage image1 = m_viewer->grab();
+ p->setAttribute(QStringLiteral("Scene.Layer.Text"),
+ QStringLiteral("textstring"), QStringLiteral("Test!"));
+ QImage image2 = m_viewer->grab();
+ QTRY_VERIFY(image1 != image2);
+
+ // Float Attribute
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.r"), 0.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.g"), 1.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.b"), 1.0);
+
+ checkPixel(m_viewer, Qt::cyan, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.r"), 1.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.g"), 0.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.b"), 0.0);
+
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ // Bool Attribute
+ checkPixel(m_viewer, Qt::yellow, bgPoint);
+ p->setAttribute(QStringLiteral("Scene"), QStringLiteral("bgcolorenable"), false);
+ checkPixel(m_viewer, Qt::black, bgPoint);
+
+ // Slide changes
+ p->goToSlide(path, 2);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::blue, c1Point);
+ checkPixel(m_viewer, Qt::blue, c2Point);
+
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 1);
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S2"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S1"));
+
+ // Time change
+ p->goToTime(path, 7.0f);
+ checkPixel(m_viewer, Qt::black, mainPoint);
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 1);
+
+ // More complex slide changes
+ // Changing slide that is not visible should not trigger enter signals
+ // The slides should still change, though, and become visible later when we switch back to S1
+ p->goToSlide(pathC1, QStringLiteral("C1S2"));
+ p->goToSlide(pathC2, QStringLiteral("C2S2"));
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 1);
+
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::cyan, c1Point);
+ checkPixel(m_viewer, Qt::magenta, c2Point);
+ QCOMPARE(spy1.count(), 7);
+ QCOMPARE(spy2.count(), 2);
+
+ p->goToSlide(pathC1, QStringLiteral("C1S1"));
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::magenta, c2Point);
+ QCOMPARE(spy1.count(), 8);
+ QCOMPARE(spy2.count(), 3);
+
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), pathC1);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C1S1"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), pathC1);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C1S2"));
+
+ p->goToSlide(pathC2, QStringLiteral("C2S1"));
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 9);
+ QCOMPARE(spy2.count(), 4);
+
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), pathC2);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C2S1"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), pathC2);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C2S2"));
+
+ p->goToSlide(path, true, true);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::blue, c1Point);
+ checkPixel(m_viewer, Qt::blue, c2Point);
+ QCOMPARE(spy1.count(), 10);
+ QCOMPARE(spy2.count(), 5);
+
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S2"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S1"));
+
+ p->goToSlide(path, false, true);
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 13);
+ QCOMPARE(spy2.count(), 6);
+
+ // No wrap, should not change
+ p->goToSlide(path, false, false);
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 13);
+ QCOMPARE(spy2.count(), 6);
+
+ // Should wrap
+ p->goToSlide(path, false, true);
+ checkPixel(m_viewer, Qt::green, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::green, c2Point);
+ QCOMPARE(spy1.count(), 14);
+ QCOMPARE(spy2.count(), 7);
+
+ // No wrap, should not change
+ p->goToSlide(path, true, false);
+ checkPixel(m_viewer, Qt::green, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::green, c2Point);
+ QCOMPARE(spy1.count(), 14);
+ QCOMPARE(spy2.count(), 7);
+
+ // Should wrap
+ p->goToSlide(path, true, true);
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 17);
+ QCOMPARE(spy2.count(), 8);
+}
+
+void tst_Q3DSSurfaceViewer::testPresentationActivation_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testPresentationActivation()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, ANIMATION);
+ else
+ createOffscreenAndViewer(m_viewer, ANIMATION);
+
+ // Note: Presentation filename isn't default ID anymore, need to set manually.
+ m_viewer->setPresentationId(QStringLiteral("animation"));
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ {
+ // Grab two images two seconds apart to verify animation is happening
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ }
+
+ m_viewer->presentation()->setPresentationActive(QStringLiteral("animation"), false);
+
+ {
+ // Grab two images two seconds apart to verify animation has stopped
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 == image2);
+ }
+
+ m_viewer->presentation()->setPresentationActive(QStringLiteral("animation"), true);
+
+ {
+ // Grab two images two seconds apart to verify animation is happening
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ }
+}
+
+void tst_Q3DSSurfaceViewer::testSceneElement_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSceneElement()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MULTISLIDE);
+ else
+ createOffscreenAndViewer(m_viewer, MULTISLIDE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QString path = QStringLiteral("Scene");
+ QString pathC1 = QStringLiteral("Scene.Layer.Component1");
+ QString pathC2 = QStringLiteral("Scene.Layer.Component2");
+
+ Q3DSPresentation *p = m_viewer->presentation();
+ Q3DSSceneElement *scene = new Q3DSSceneElement(path);
+ Q3DSSceneElement *sceneC1 = new Q3DSSceneElement(pathC1);
+ Q3DSSceneElement *sceneC2 = new Q3DSSceneElement(pathC2);
+ QSignalSpy spy1(scene, &Q3DSSceneElement::currentSlideIndexChanged);
+ QSignalSpy spy2(scene, &Q3DSSceneElement::previousSlideIndexChanged);
+ QSignalSpy spy3(scene, &Q3DSSceneElement::currentSlideNameChanged);
+ QSignalSpy spy4(scene, &Q3DSSceneElement::previousSlideNameChanged);
+ QSignalSpy spy5(scene, &Q3DSSceneElement::elementPathChanged);
+ QSignalSpy spy6(sceneC1, &Q3DSSceneElement::currentSlideIndexChanged);
+ QSignalSpy spy7(sceneC1, &Q3DSSceneElement::previousSlideIndexChanged);
+ QSignalSpy spy8(sceneC1, &Q3DSSceneElement::currentSlideNameChanged);
+ QSignalSpy spy9(sceneC1, &Q3DSSceneElement::previousSlideNameChanged);
+ QSignalSpy spy10(sceneC1, &Q3DSSceneElement::elementPathChanged);
+ QSignalSpy spy11(sceneC2, &Q3DSSceneElement::currentSlideIndexChanged);
+ QSignalSpy spy12(sceneC2, &Q3DSSceneElement::previousSlideIndexChanged);
+ QSignalSpy spy13(sceneC2, &Q3DSSceneElement::currentSlideNameChanged);
+ QSignalSpy spy14(sceneC2, &Q3DSSceneElement::previousSlideNameChanged);
+ QSignalSpy spy15(sceneC2, &Q3DSSceneElement::elementPathChanged);
+ QVERIFY(spy1.isValid());
+ QVERIFY(spy2.isValid());
+ QVERIFY(spy3.isValid());
+ QVERIFY(spy4.isValid());
+ QVERIFY(spy5.isValid());
+ QVERIFY(spy6.isValid());
+ QVERIFY(spy7.isValid());
+ QVERIFY(spy8.isValid());
+ QVERIFY(spy9.isValid());
+ QVERIFY(spy10.isValid());
+ QVERIFY(spy11.isValid());
+ QVERIFY(spy12.isValid());
+ QVERIFY(spy13.isValid());
+ QVERIFY(spy14.isValid());
+ QVERIFY(spy15.isValid());
+
+ // Defaults
+ QCOMPARE(scene->currentSlideIndex(), 0);
+ QCOMPARE(scene->previousSlideIndex(), 0);
+ QCOMPARE(scene->currentSlideName(), QStringLiteral(""));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral(""));
+ QCOMPARE(scene->elementPath(), path);
+
+ checkPixel(m_viewer, Qt::red);
+
+ // Ensure we have no pending events to confuse spy counts
+ QGuiApplication::processEvents();
+
+ p->registerElement(scene);
+ p->registerElement(sceneC1);
+ p->registerElement(sceneC2);
+
+ QCOMPARE(scene->currentSlideIndex(), 1);
+ QCOMPARE(scene->previousSlideIndex(), 0);
+ QCOMPARE(scene->currentSlideName(), QStringLiteral("S1"));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral(""));
+ QCOMPARE(scene->elementPath(), path);
+
+ p->goToSlide(path, QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy3.count(), 1);
+ QCOMPARE(spy4.count(), 1);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 0);
+ QCOMPARE(spy7.count(), 0);
+ QCOMPARE(spy8.count(), 0);
+ QCOMPARE(spy9.count(), 0);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 0);
+ QCOMPARE(spy12.count(), 0);
+ QCOMPARE(spy13.count(), 0);
+ QCOMPARE(spy14.count(), 0);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 0);
+ // Getting previous slide change without getting current slide change seems illogical here,
+ // but that's how the internal viewer logic for previous slide works. It makes sense when
+ // you consider the fact that we always get enter events for child slides when parent slide
+ // is entered.
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 0);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 0);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 0);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(pathC1, QStringLiteral("C1S2"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 1);
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 1);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 0);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 0);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(pathC2, QStringLiteral("C2S2"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 1);
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 1);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 1);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 1);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ // Subscenes revert to original slides when parent is re-entered
+ p->goToSlide(path, QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 3);
+ QCOMPARE(spy2.count(), 3);
+ QCOMPARE(spy3.count(), 3);
+ QCOMPARE(spy4.count(), 3);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 1);
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 1);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 1);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 1);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 4);
+ QCOMPARE(spy3.count(), 4);
+ QCOMPARE(spy4.count(), 4);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 2);
+ QCOMPARE(spy7.count(), 2);
+ QCOMPARE(spy8.count(), 2);
+ QCOMPARE(spy9.count(), 2);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 2);
+ QCOMPARE(spy12.count(), 2);
+ QCOMPARE(spy13.count(), 2);
+ QCOMPARE(spy14.count(), 2);
+ QCOMPARE(spy15.count(), 0);
+
+ p->unregisterElement(scene);
+ p->unregisterElement(sceneC1);
+ p->unregisterElement(sceneC2);
+
+ // No more signals after unregistering
+ p->goToSlide(path, QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 4);
+ QCOMPARE(spy3.count(), 4);
+ QCOMPARE(spy4.count(), 4);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 2);
+ QCOMPARE(spy7.count(), 2);
+ QCOMPARE(spy8.count(), 2);
+ QCOMPARE(spy9.count(), 2);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 2);
+ QCOMPARE(spy12.count(), 2);
+ QCOMPARE(spy13.count(), 2);
+ QCOMPARE(spy14.count(), 2);
+ QCOMPARE(spy15.count(), 0);
+
+ // Reregister
+ p->registerElement(scene);
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 5);
+ QCOMPARE(spy2.count(), 5);
+ QCOMPARE(spy3.count(), 5);
+ QCOMPARE(spy4.count(), 5);
+ QCOMPARE(spy5.count(), 0);
+
+ QCOMPARE(scene->currentSlideIndex(), 1);
+ QCOMPARE(scene->previousSlideIndex(), 2);
+ QCOMPARE(scene->currentSlideName(), QStringLiteral("S1"));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral("S2"));
+ QCOMPARE(scene->elementPath(), path);
+
+ scene->setCurrentSlideName(QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 6);
+ QCOMPARE(spy2.count(), 6);
+
+ scene->setCurrentSlideIndex(0);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 7);
+ QCOMPARE(spy2.count(), 7);
+
+ // Go to next slide, wrap parameter doesn't matter
+ scene->goToSlide(true, true);
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 8);
+ QCOMPARE(spy2.count(), 8);
+
+ // Go to next slide, wrap parameter doesn't matter
+ scene->goToSlide(true, false);
+ checkPixel(m_viewer, Qt::green);
+
+ QCOMPARE(spy1.count(), 9);
+ QCOMPARE(spy2.count(), 9);
+
+ // No wrap, should not change
+ scene->goToSlide(true, false);
+ checkPixel(m_viewer, Qt::green);
+
+ QCOMPARE(spy1.count(), 9);
+ QCOMPARE(spy2.count(), 9);
+
+ // Should wrap
+ scene->goToSlide(true, true);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 10);
+ QCOMPARE(spy2.count(), 10);
+
+ // No wrap, should not change
+ scene->goToSlide(false, false);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 10);
+ QCOMPARE(spy2.count(), 10);
+
+ // Should wrap
+ scene->goToSlide(false, true);
+ checkPixel(m_viewer, Qt::green);
+
+ QCOMPARE(spy1.count(), 11);
+ QCOMPARE(spy2.count(), 11);
+
+ // Time change
+ scene->goToTime(7.0f);
+ checkPixel(m_viewer, Qt::yellow);
+
+ QCOMPARE(spy1.count(), 11);
+ QCOMPARE(spy2.count(), 11);
+
+ // Back to first slide for further tests
+ scene->setCurrentSlideIndex(0);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 12);
+ QCOMPARE(spy2.count(), 12);
+
+ // Change element path
+ scene->setElementPath(pathC1);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 12);
+ QCOMPARE(spy2.count(), 12);
+ QCOMPARE(spy3.count(), 12);
+ QCOMPARE(spy4.count(), 12);
+ QCOMPARE(spy5.count(), 1);
+
+ QCOMPARE(scene->currentSlideIndex(), 1);
+ QCOMPARE(scene->previousSlideIndex(), 1);
+ // Having current and previous slides the same seems weird, but that's how the slide
+ // logic works internally.
+ QCOMPARE(scene->currentSlideName(), QStringLiteral("C1S1"));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral("C1S1"));
+ QCOMPARE(scene->elementPath(), pathC1);
+
+ p->goToSlide(pathC1, QStringLiteral("C1S2"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 13);
+ QCOMPARE(spy2.count(), 12);
+ QCOMPARE(spy3.count(), 13);
+ QCOMPARE(spy4.count(), 12);
+ QCOMPARE(spy5.count(), 1);
+}
+
+void tst_Q3DSSurfaceViewer::testElement_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testElement()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MULTISLIDE);
+ else
+ createOffscreenAndViewer(m_viewer, MULTISLIDE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QString path1 = QStringLiteral("Scene.Layer.Rect.Material"); // Red
+ QString path2 = QStringLiteral("Scene.Layer.Component1.Rectangle4.Material"); // Green
+ QString path3 = QStringLiteral("Scene.Layer.Component2.Rectangle6.Material"); // Yellow
+
+ QPoint mainPoint(m_viewer->size().width() * 2 / 8, m_viewer->size().height() / 2);
+ QPoint c1Point(m_viewer->size().width() * 5 / 8, m_viewer->size().height() / 2);
+ QPoint c2Point(m_viewer->size().width() * 7 / 8, m_viewer->size().height() / 2);
+
+ Q3DSPresentation *p = m_viewer->presentation();
+ Q3DSElement *element1 = new Q3DSElement(p, path1);
+ Q3DSElement *element2 = new Q3DSElement(p, path2);
+ QSignalSpy spy2(element2, &Q3DSSceneElement::elementPathChanged);
+ QVERIFY(spy2.isValid());
+
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ element1->setAttribute(QStringLiteral("diffuse.r"), 0.0);
+ element1->setAttribute(QStringLiteral("diffuse.g"), 0.0);
+ element1->setAttribute(QStringLiteral("diffuse.b"), 1.0);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ element2->setAttribute(QStringLiteral("diffuse.r"), 1.0);
+ element2->setAttribute(QStringLiteral("diffuse.g"), 0.0);
+ element2->setAttribute(QStringLiteral("diffuse.b"), 1.0);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::magenta, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ // Change elementpath, nothing changes visually
+ element2->setElementPath(path3);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::magenta, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy2.count(), 1);
+
+ element2->setAttribute(QStringLiteral("diffuse.r"), 0.0);
+ element2->setAttribute(QStringLiteral("diffuse.g"), 1.0);
+ element2->setAttribute(QStringLiteral("diffuse.b"), 1.0);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::magenta, c1Point);
+ checkPixel(m_viewer, Qt::cyan, c2Point);
+}
+
+void tst_Q3DSSurfaceViewer::testMouseInput_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testMouseInput()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MOUSE);
+ else
+ createOffscreenAndViewer(m_viewer, MOUSE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QPoint point1(m_viewer->size().width() * 1 / 4, m_viewer->size().height() / 2);
+ QPoint point2(m_viewer->size().width() * 3 / 4, m_viewer->size().height() / 2);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ QMouseEvent e1(QEvent::MouseButtonPress, point1, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mousePressEvent(&e1);
+
+ checkPixel(m_viewer, Qt::green, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ QMouseEvent e2(QEvent::MouseButtonRelease, point1, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mouseReleaseEvent(&e2);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ QMouseEvent e3(QEvent::MouseButtonPress, point2, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mousePressEvent(&e3);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::blue, point2);
+
+ QMouseEvent e4(QEvent::MouseButtonRelease, point2, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mouseReleaseEvent(&e4);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ // Note: No way yet to hook mouse move into anything in the presentation
+}
+
+void tst_Q3DSSurfaceViewer::testDataInput_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testDataInput()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, DATAINPUT);
+ else
+ createOffscreenAndViewer(m_viewer, DATAINPUT);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QPoint point1(m_viewer->size().width() / 4, m_viewer->size().height() / 4);
+
+ const QString animationName = QStringLiteral("animationInput");
+ const QString slideName = QStringLiteral("slideInput");
+
+ checkPixel(m_viewer, Qt::red, point1);
+ m_viewer->presentation()->setDataInputValue(animationName, 90);
+ checkPixel(m_viewer, Qt::blue, point1);
+ m_viewer->presentation()->setDataInputValue(animationName, 10);
+ checkPixel(m_viewer, Qt::red, point1);
+
+ Q3DSDataInput *animationInput = new Q3DSDataInput();
+ animationInput->setName(animationName);
+
+ m_viewer->presentation()->registerDataInput(animationInput);
+ QVERIFY(m_viewer->presentation()->registeredDataInput(animationInput->name()));
+
+ Q3DSDataInput *slideInput = new Q3DSDataInput(m_viewer->presentation(), slideName);
+ QVERIFY(m_viewer->presentation()->registeredDataInput(slideInput->name()));
+
+ animationInput->setValue(90);
+ checkPixel(m_viewer, Qt::blue, point1);
+ animationInput->setValue(10);
+ checkPixel(m_viewer, Qt::red, point1);
+
+ slideInput->setValue(QStringLiteral("Slide2"));
+ checkPixel(m_viewer, Qt::green, point1);
+ slideInput->setValue(QStringLiteral("Slide1"));
+ checkPixel(m_viewer, Qt::red, point1);
+
+ m_viewer->presentation()->unregisterDataInput(animationInput);
+ m_viewer->presentation()->unregisterDataInput(slideInput);
+ QVERIFY(!m_viewer->presentation()->registeredDataInput(animationInput->name()));
+ QVERIFY(!m_viewer->presentation()->registeredDataInput(slideInput->name()));
+ delete animationInput;
+ delete slideInput;
+}
+
+
+QTEST_MAIN(tst_Q3DSSurfaceViewer)
+
+#include "tst_q3dssurfaceviewer.moc"