summaryrefslogtreecommitdiffstats
path: root/demos/photobrowser3d
diff options
context:
space:
mode:
Diffstat (limited to 'demos/photobrowser3d')
-rw-r--r--demos/photobrowser3d/buttons.cpp134
-rw-r--r--demos/photobrowser3d/buttons.h63
-rw-r--r--demos/photobrowser3d/bytereader.cpp158
-rw-r--r--demos/photobrowser3d/bytereader.h66
-rw-r--r--demos/photobrowser3d/filescanner.cpp127
-rw-r--r--demos/photobrowser3d/filescanner.h79
-rw-r--r--demos/photobrowser3d/imagedisplay.cpp225
-rw-r--r--demos/photobrowser3d/imagedisplay.h85
-rw-r--r--demos/photobrowser3d/imageloader.cpp116
-rw-r--r--demos/photobrowser3d/imageloader.h84
-rw-r--r--demos/photobrowser3d/imagemanager.cpp134
-rw-r--r--demos/photobrowser3d/imagemanager.h79
-rw-r--r--demos/photobrowser3d/images/P1000223.JPGbin0 -> 29760 bytes
-rw-r--r--demos/photobrowser3d/images/P1000228.JPGbin0 -> 27685 bytes
-rw-r--r--demos/photobrowser3d/images/P1000441.JPGbin0 -> 453660 bytes
-rw-r--r--demos/photobrowser3d/images/P1000472.JPGbin0 -> 25850 bytes
-rw-r--r--demos/photobrowser3d/images/arrows-left.pngbin0 -> 5303 bytes
-rw-r--r--demos/photobrowser3d/images/arrows.xcfbin0 -> 289659 bytes
-rw-r--r--demos/photobrowser3d/images/default_sky_base.xcfbin0 -> 93208 bytes
-rw-r--r--demos/photobrowser3d/images/default_sky_down.pngbin0 -> 360 bytes
-rw-r--r--demos/photobrowser3d/images/default_sky_east.pngbin0 -> 29427 bytes
-rw-r--r--demos/photobrowser3d/images/default_sky_north.pngbin0 -> 38936 bytes
-rw-r--r--demos/photobrowser3d/images/default_sky_south.pngbin0 -> 29427 bytes
-rw-r--r--demos/photobrowser3d/images/default_sky_up.pngbin0 -> 21806 bytes
-rw-r--r--demos/photobrowser3d/images/default_sky_west.pngbin0 -> 29427 bytes
-rw-r--r--demos/photobrowser3d/images/girder.pngbin0 -> 196973 bytes
-rw-r--r--demos/photobrowser3d/images/no-images-yet.pngbin0 -> 111700 bytes
-rw-r--r--demos/photobrowser3d/images/no-images-yet.xcfbin0 -> 352839 bytes
-rw-r--r--demos/photobrowser3d/images/sample_image.jpgbin0 -> 498466 bytes
-rw-r--r--demos/photobrowser3d/launcher.cpp116
-rw-r--r--demos/photobrowser3d/main.cpp72
-rw-r--r--demos/photobrowser3d/pancontroller.cpp244
-rw-r--r--demos/photobrowser3d/pancontroller.h89
-rw-r--r--demos/photobrowser3d/photobrowser3d.pro62
-rw-r--r--demos/photobrowser3d/photobrowser3d.qrc24
-rw-r--r--demos/photobrowser3d/photobrowser3dview.cpp437
-rw-r--r--demos/photobrowser3d/photobrowser3dview.h112
-rw-r--r--demos/photobrowser3d/qatlas.cpp188
-rw-r--r--demos/photobrowser3d/qatlas.h102
-rw-r--r--demos/photobrowser3d/qfocusadaptor.cpp186
-rw-r--r--demos/photobrowser3d/qfocusadaptor.h80
-rw-r--r--demos/photobrowser3d/qphotobrowser3dscene.cpp58
-rw-r--r--demos/photobrowser3d/qphotobrowser3dscene.h60
-rw-r--r--demos/photobrowser3d/shaders/replace_texture.fsh54
-rw-r--r--demos/photobrowser3d/shaders/replace_texture.vsh58
-rw-r--r--demos/photobrowser3d/skybox.cpp223
-rw-r--r--demos/photobrowser3d/skybox.h70
-rw-r--r--demos/photobrowser3d/threadpool.cpp132
-rw-r--r--demos/photobrowser3d/threadpool.h81
-rw-r--r--demos/photobrowser3d/thumbnailableimage.cpp302
-rw-r--r--demos/photobrowser3d/thumbnailableimage.h98
-rw-r--r--demos/photobrowser3d/thumbnaileffect.cpp186
-rw-r--r--demos/photobrowser3d/thumbnaileffect.h70
-rw-r--r--demos/photobrowser3d/thumbnailnode.cpp281
-rw-r--r--demos/photobrowser3d/thumbnailnode.h97
55 files changed, 4832 insertions, 0 deletions
diff --git a/demos/photobrowser3d/buttons.cpp b/demos/photobrowser3d/buttons.cpp
new file mode 100644
index 000000000..497a4b5b2
--- /dev/null
+++ b/demos/photobrowser3d/buttons.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "buttons.h"
+#include "qglpainter.h"
+
+Buttons::Buttons(QObject *parent, QGLMaterialCollection *palette)
+ : QGLSceneNode(parent)
+{
+ setObjectName("Buttons");
+ setPalette(palette);
+ setOption(QGLSceneNode::CullBoundingBox, false);
+
+ m_left = new QGLSceneNode(this);
+ m_left->setObjectName("Left Button");
+ m_right = new QGLSceneNode(this);
+ m_right->setObjectName("Right Button");
+
+ QGLMaterial *mat = new QGLMaterial;
+ QImage im(":/controls/arrows-left.png");
+ m_size = im.size();
+ QGLTexture2D *tex = new QGLTexture2D(mat);
+ tex->setImage(im);
+ mat->setTexture(tex);
+
+ setMaterial(mat);
+ setEffect(QGL::FlatReplaceTexture2D);
+
+ QGeometryData data;
+ QSize f = im.size() / 2;
+ QVector2D a(-f.width(), -f.height());
+ QVector2D b(f.width(), -f.height());
+ QVector2D c(f.width(), f.height());
+ QVector2D d(-f.width(), f.height());
+ QVector2D ta(0, 1);
+ QVector2D tb(1, 1);
+ QVector2D tc(1, 0);
+ QVector2D td(0, 0);
+ data.appendVertex(a, b, c, d);
+ data.appendTexCoord(ta, tb, tc, td);
+ data.appendIndices(0, 1, 2);
+ data.appendIndices(0, 2, 3);
+
+ // the right hand arrow geometry is same as above, flipped X <-> -X
+ data.appendGeometry(data);
+ data.texCoord(4).setX(1);
+ data.texCoord(5).setX(0);
+ data.texCoord(6).setX(0);
+ data.texCoord(7).setX(1);
+ data.appendIndices(4, 5, 6);
+ data.appendIndices(4, 6, 7);
+
+ m_left->setGeometry(data);
+ m_left->setCount(6);
+ m_left->setOption(QGLSceneNode::CullBoundingBox, false);
+
+ m_right->setGeometry(data);
+ m_right->setStart(6);
+ m_right->setCount(6);
+ m_left->setOption(QGLSceneNode::CullBoundingBox, false);
+}
+
+void Buttons::draw(QGLPainter *painter)
+{
+ painter->projectionMatrix().push();
+ painter->modelViewMatrix().push();
+
+ QRect rect = painter->currentSurface()->viewportRect();
+ QMatrix4x4 projm;
+ projm.ortho(rect);
+ painter->projectionMatrix() = projm;
+ painter->modelViewMatrix().setToIdentity();
+
+ if (m_left->position().isNull())
+ {
+ QVector2D pos(m_size.width() / 2, rect.height() - m_size.height() / 2);
+ m_left->setPosition(pos);
+ pos.setX(rect.width() - (m_size.width() / 2));
+ m_right->setPosition(pos);
+ }
+
+ glDisable(GL_DEPTH_TEST);
+
+ QGLSceneNode::draw(painter);
+
+ glEnable(GL_DEPTH_TEST);
+
+ painter->projectionMatrix().pop();
+ painter->modelViewMatrix().pop();
+}
+
+void Buttons::clearPositions()
+{
+ m_left->setPosition(QVector3D());
+ m_right->setPosition(QVector3D());
+}
diff --git a/demos/photobrowser3d/buttons.h b/demos/photobrowser3d/buttons.h
new file mode 100644
index 000000000..1e4475faf
--- /dev/null
+++ b/demos/photobrowser3d/buttons.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef BUTTONS_H
+#define BUTTONS_H
+
+#include "qglscenenode.h"
+
+#include <Qt>
+
+class Buttons : public QGLSceneNode
+{
+ Q_OBJECT
+public:
+ explicit Buttons(QObject *parent, QGLMaterialCollection *palette);
+ void draw(QGLPainter *painter);
+ void clearPositions();
+private:
+ QGLSceneNode *m_left;
+ QGLSceneNode *m_right;
+ QSize m_size;
+};
+
+#endif // BUTTONS_H
diff --git a/demos/photobrowser3d/bytereader.cpp b/demos/photobrowser3d/bytereader.cpp
new file mode 100644
index 000000000..71c3b3f12
--- /dev/null
+++ b/demos/photobrowser3d/bytereader.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "bytereader.h"
+#include "thumbnailableimage.h"
+
+#include <QByteArray>
+#include <QThread>
+#include <QImage>
+#include <QImageReader>
+#include <QUrl>
+#include <QFile>
+#include <QCoreApplication>
+
+ByteReader::ByteReader()
+{
+ m_stop = 0;
+ m_loading = 0;
+}
+
+void ByteReader::loadFile(const ThumbnailableImage &image)
+{
+ if (!m_stop)
+ {
+ m_loading.ref();
+
+ // FIXME: actually handle remote files
+ QUrl url = image.url();
+ QString fn = url.toLocalFile();
+ int pos = fn.lastIndexOf('.');
+ QString ext;
+ if (pos != -1)
+ ext = fn.mid(pos).toUpper();
+ if (ext.isEmpty() ||
+ !QImageReader::supportedImageFormats().contains(ext.toLocal8Bit()))
+ ext = QString();
+ QImage im;
+ QFile f(fn);
+ QString errorMessage;
+ if (f.open(QIODevice::ReadOnly))
+ {
+ QByteArray bytes;
+ while (!f.atEnd() & !m_stop)
+ {
+ bytes.append(f.read(1024));
+ QCoreApplication::processEvents();
+ }
+ im = ext.isEmpty() ? QImage::fromData(bytes)
+ : QImage::fromData(bytes, qPrintable(ext));
+ }
+ else
+ {
+ errorMessage = tr("Could not read: %1").arg(url.toString());
+ }
+
+ QCoreApplication::processEvents();
+ if (!m_stop)
+ {
+ if (im.isNull())
+ {
+ im = QImage(QSize(128, 128), QImage::Format_ARGB32);
+ im.fill(qRgba(0, 30, 50, 64));
+ QPainter ptr;
+ ptr.begin(&im);
+ ptr.setBackgroundMode(Qt::TransparentMode);
+ if (errorMessage.isEmpty())
+ errorMessage = tr("Could not load: %1").arg(url.toString());
+ ptr.setPen(QColor("orange"));
+ ptr.drawText(im.rect(), Qt::AlignCenter, errorMessage);
+ ptr.end();
+ }
+ else
+ {
+ // TODO: Fix size limit
+ // This arbitrary size limit is really a debugging/development thing
+ // In a real program once you had loaded the full image, the photo-
+ // viewer would allow zooming and panning all around in the image
+ // so loading a 2896 pixel × 1944 pixel photo would make sense even
+ // on a small screen. For now work with fairly cruddy image quality.
+ // Probably the fix is to have a separate load call that re-fetches
+ // the full image on a zoom
+ QSize workSize(1024, 768);
+ Qt::TransformationMode mode = Qt::SmoothTransformation;
+ if (QThread::idealThreadCount() < 2)
+ {
+ workSize = workSize / 2;
+ mode = Qt::FastTransformation;
+ }
+ if (im.size().width() > workSize.width() || im.size().height() > workSize.height())
+ im = im.scaled(workSize, Qt::KeepAspectRatio, mode);
+ }
+
+ Q_ASSERT(!im.isNull());
+ ThumbnailableImage result(image);
+ result.setData(im);
+
+ // it would be nice to incur the cost of setThumbnailed() on the image
+ // at this point - in the background thread. Trouble is the atlas is
+ // constantly being accessed by the draw loop and to do anything about
+ // that would mean locking the GUI thread...
+
+ Q_ASSERT(!result.isNull());
+
+ emit imageLoaded(result);
+ }
+
+ m_loading.deref();
+ }
+
+ if (m_stop)
+ emit stopped();
+
+}
+
+void ByteReader::stop()
+{
+ m_stop.ref();
+ if (!m_loading)
+ emit stopped();
+}
diff --git a/demos/photobrowser3d/bytereader.h b/demos/photobrowser3d/bytereader.h
new file mode 100644
index 000000000..2aa7dadf2
--- /dev/null
+++ b/demos/photobrowser3d/bytereader.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BYTEREADER_H
+#define BYTEREADER_H
+
+#include <QObject>
+
+class ThumbnailableImage;
+class QUrl;
+
+class ByteReader : public QObject
+{
+ Q_OBJECT
+public:
+ ByteReader();
+signals:
+ void imageLoaded(const ThumbnailableImage &image);
+ void stopped();
+public slots:
+ void loadFile(const ThumbnailableImage &url);
+ void stop();
+private:
+ QAtomicInt m_stop;
+ QAtomicInt m_loading;
+};
+
+#endif // BYTEREADER_H
diff --git a/demos/photobrowser3d/filescanner.cpp b/demos/photobrowser3d/filescanner.cpp
new file mode 100644
index 000000000..4010ebdab
--- /dev/null
+++ b/demos/photobrowser3d/filescanner.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "filescanner.h"
+
+#include <QTime>
+#include <QFileInfo>
+#include <QStringList>
+#include <QSet>
+#include <QDir>
+#include <QCoreApplication>
+#include <QImageReader>
+#include <QDebug>
+
+FileScanner::FileScanner(QObject *parent)
+ : QThread(parent)
+{
+ m_stop = 0;
+}
+
+FileScanner::~FileScanner()
+{
+ // nothing to do here
+}
+
+void FileScanner::stop()
+{
+ m_stop.ref();
+}
+
+void FileScanner::run()
+{
+ scan();
+}
+
+void FileScanner::scan()
+{
+ QStringList queue;
+ queue.append(m_url.path());
+ QSet<QString> loopProtect;
+ int count = 0;
+ while (queue.size() > 0 && !m_stop && count < 300)
+ {
+ QString path = queue.takeFirst();
+ QFileInfo u(path);
+ if (u.isSymLink())
+ {
+ path = u.symLinkTarget();
+ u = QFileInfo(path);
+ }
+ if (u.isDir())
+ {
+ if (!loopProtect.contains(path))
+ {
+ loopProtect.insert(path);
+ QDir dir(path);
+ QStringList entries = dir.entryList();
+ QStringList::const_iterator it = entries.constBegin();
+ for ( ; it != entries.constEnd(); ++it)
+ {
+ // ignore hidden files, system directories
+ if ((*it).startsWith("."))
+ continue;
+ queue.append(dir.absoluteFilePath(*it));
+ }
+ }
+ }
+ else
+ {
+ if (u.isFile() && u.isReadable())
+ {
+ // small optimization: if the file has a suffix, check if that
+ // is known as an image format before sending to loader
+ QString ext = u.suffix();
+ if (ext.isEmpty() ||
+ QImageReader::supportedImageFormats().contains(ext.toLocal8Bit()))
+ {
+ QUrl url2;
+ url2.setScheme("file");
+ url2.setPath(u.absoluteFilePath());
+ emit imageUrl(url2);
+ ++count;
+ }
+ }
+ }
+ QCoreApplication::processEvents();
+ QThread::yieldCurrentThread();
+ }
+}
diff --git a/demos/photobrowser3d/filescanner.h b/demos/photobrowser3d/filescanner.h
new file mode 100644
index 000000000..d9f15e9a9
--- /dev/null
+++ b/demos/photobrowser3d/filescanner.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILESCANNER_H
+#define FILESCANNER_H
+
+#include <QThread>
+#include <QUrl>
+#include <QDebug>
+
+class FileScanner : public QThread
+{
+ Q_OBJECT
+public:
+ explicit FileScanner(QObject *parent = 0);
+ ~FileScanner();
+
+ // INVARIANT: never get called when the thread is running
+ void setBaseUrl(const QUrl &url)
+ {
+ Q_ASSERT(!isRunning());
+ m_url = url;
+ }
+
+signals:
+ void imageUrl(const QUrl &url);
+
+public slots:
+ void stop();
+ void scan();
+
+protected:
+ void run();
+
+ QUrl m_url;
+ QAtomicInt m_stop;
+private:
+
+};
+
+#endif // FILESCANNER_H
diff --git a/demos/photobrowser3d/imagedisplay.cpp b/demos/photobrowser3d/imagedisplay.cpp
new file mode 100644
index 000000000..73782aeb1
--- /dev/null
+++ b/demos/photobrowser3d/imagedisplay.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "imagedisplay.h"
+#include "thumbnailableimage.h"
+#include "thumbnailnode.h"
+#include "thumbnaileffect.h"
+#include "qglbuilder.h"
+#include "qglcube.h"
+#include "imagemanager.h"
+#include "qatlas.h"
+#include "qglshaderprogrameffect.h"
+#include "qphotobrowser3dscene.h"
+#include "photobrowser3dview.h"
+
+#include <QApplication>
+#include <QChildEvent>
+#include <QUrl>
+#include <QImage>
+
+static inline QImage qMakeFrameImage()
+{
+ QImage frm(QSize(128, 128), QImage::Format_ARGB32);
+ frm.fill(qRgba(8, 8, 8, 255)); // dark grey frame
+ QPainter ptr;
+ ptr.begin(&frm);
+ QRect r(8, 8, 112, 112);
+ ptr.setBackgroundMode(Qt::TransparentMode);
+ ptr.fillRect(r, QColor(0, 30, 50, 64));
+ ptr.setPen(QColor("orange"));
+ ptr.drawText(frm.rect(), Qt::AlignCenter, "Loading...");
+ ptr.end();
+ return frm;
+}
+
+static inline void qAddPane(QSizeF size, QGeometryData *data)
+{
+ Q_ASSERT(data);
+ QSizeF f = size / 2.0f;
+ QVector2D a(-f.width(), -f.height());
+ QVector2D b(f.width(), -f.height());
+ QVector2D c(f.width(), f.height());
+ QVector2D d(-f.width(), f.height());
+ QVector2D ta(0.0f, 0.0f);
+ QVector2D tb(1.0f, 0.0f);
+ QVector2D tc(1.0f, 1.0f);
+ QVector2D td(0.0f, 1.0f);
+ int k = data->count();
+ data->appendVertex(a, b, c, d);
+ data->appendTexCoord(ta, tb, tc, td);
+ data->appendIndices(k, k+1, k+2);
+ data->appendIndices(k, k+2, k+3);
+}
+
+ImageDisplay::ImageDisplay(QObject *parent, QGLMaterialCollection *materials, qreal wallSize)
+ : QGLSceneNode(parent)
+ , m_wall(0)
+ , m_frames(0)
+ , m_currentWall(0)
+ , m_currentFrame(0)
+ , m_imageSetToDefault(false)
+ , m_count(0)
+ , m_size(wallSize)
+ , m_frameSize((m_size * 3.0f) / 4.0f)
+ , m_maxImages(500)
+ , m_frameLoadingMaterial(-1)
+{
+ // the real values will get poked in here by the atlas
+ m_atlasPlaceHolder.append(QVector2D(), QVector2D(), QVector2D(), QVector2D());
+
+ setObjectName("ImageDisplay");
+ setPalette(materials);
+
+ // the frames lie in Z = 0, the wall is set back and lies in
+ // the plane Z = (m_size / -4.0)
+
+ // build the wall
+ qAddPane(QSize(m_size, m_size), &m_wallGeometry);
+ m_wall = new QGLSceneNode(this);
+ m_wall->setObjectName("Wall");
+ m_wall->setPalette(materials);
+ m_currentWall = new QGLSceneNode(m_wall);
+ m_currentWall->setObjectName("wall 0");
+ m_currentWall->setGeometry(m_wallGeometry);
+ m_currentWall->setCount(m_wallGeometry.indexCount());
+ m_wall->setPosition(QVector3D(0.0f, 0.0f, m_size / -4.0));
+
+ // paint the wall
+ m_wall->setEffect(QGL::FlatReplaceTexture2D);
+ QGLMaterial *mat = new QGLMaterial();
+ QGLTexture2D *tex = new QGLTexture2D(mat);
+ tex->setImage(QImage(":/res/images/girder.png"));
+ mat->setTexture(tex);
+ mat->setObjectName("girder material");
+ m_wall->setMaterial(mat);
+
+ // build the frames
+ qAddPane(QSize(m_frameSize, m_frameSize), &m_frameGeometry);
+ m_frameGeometry.appendTexCoordArray(m_atlasPlaceHolder, QGL::TextureCoord1);
+ m_frames = new QGLSceneNode(this);
+ m_frames->setObjectName("Frames");
+ m_currentFrame = new ThumbnailNode(m_frames);
+ m_currentFrame->setObjectName("frame 0");
+ m_currentFrame->setGeometry(m_frameGeometry);
+ m_currentFrame->setCount(m_frameGeometry.indexCount());
+
+ // use the frames geometry to put the atlas data into
+ QAtlas *atlas = QAtlas::instance();
+ atlas->setGeometry(m_frameGeometry);
+
+ // generally the frames use the thumbnail material & effect
+ m_effect = new ThumbnailEffect;
+ m_frames->setUserEffect(m_effect);
+ m_frames->setEffectEnabled(true);
+ m_frames->setMaterial(atlas->material());
+
+ // unless they're loading, in which case use the "loading" image
+ m_frameImage = qMakeFrameImage();
+ mat = new QGLMaterial();
+ tex = new QGLTexture2D(mat);
+ tex->setHorizontalWrap(QGL::Clamp);
+ tex->setImage(m_frameImage);
+ mat->setTexture(tex);
+ mat->setObjectName("loading image material - default");
+ m_frameLoadingMaterial = materials->addMaterial(mat);
+ m_currentFrame->setMaterialIndex(m_frameLoadingMaterial);
+
+ // make the frames pickable
+ PhotoBrowser3DView *view = qobject_cast<PhotoBrowser3DView*>(parent);
+ view->scene()->mainNode()->addNode(m_frames);
+
+ m_imageSetToDefault = true;
+}
+
+ImageDisplay::~ImageDisplay()
+{
+ delete m_effect;
+}
+
+void ImageDisplay::addThumbnailNode(const QUrl &image)
+{
+ Q_ASSERT(QThread::currentThread() == thread());
+ ImageManager *manager = qobject_cast<ImageManager*>(sender());
+ if (!m_imageSetToDefault)
+ {
+ QVector3D p = m_currentFrame->position();
+ p.setX(p.x() - m_size);
+ int start = m_frameGeometry.indexCount();
+ qAddPane(QSize(m_frameSize, m_frameSize), &m_frameGeometry);
+ int count = m_frameGeometry.indexCount() - start;
+ m_frameGeometry.appendTexCoordArray(m_atlasPlaceHolder, QGL::TextureCoord1);
+ m_currentFrame = new ThumbnailNode(m_frames);
+ QString name = QLatin1String("frame %1");
+ name.arg(m_count);
+ m_currentFrame->setObjectName(name);
+ m_currentFrame->setPosition(p);
+ m_currentFrame->setStart(start);
+ m_currentFrame->setCount(count);
+ m_currentFrame->setGeometry(m_frameGeometry);
+ m_currentFrame->setMaterialIndex(m_frameLoadingMaterial);
+
+ QGLSceneNode *s = m_currentWall->clone(m_wall);
+ name = QLatin1String("wall %1");
+ name.arg(m_count);
+ s->setObjectName(name);
+ p = s->position();
+ p.setX(p.x() - m_size);
+ s->setPosition(p);
+ m_currentWall = s;
+ }
+ m_currentFrame->setUrl(image);
+ if (manager)
+ {
+ connect(m_currentFrame, SIGNAL(imageRequired(ThumbnailableImage)),
+ manager, SIGNAL(deployLoader(ThumbnailableImage)));
+ connect(manager, SIGNAL(imageReady(ThumbnailableImage)),
+ m_currentFrame, SLOT(setImage(ThumbnailableImage)));
+ }
+ PhotoBrowser3DView *view = qobject_cast<PhotoBrowser3DView*>(parent());
+ Q_ASSERT(view);
+ connect(m_currentFrame, SIGNAL(nodeChanged()), view, SLOT(update()));
+
+ m_imageSetToDefault = false;
+ emit framesChanged();
+ ++m_count;
+}
diff --git a/demos/photobrowser3d/imagedisplay.h b/demos/photobrowser3d/imagedisplay.h
new file mode 100644
index 000000000..8bd051168
--- /dev/null
+++ b/demos/photobrowser3d/imagedisplay.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IMAGEDISPLAY_H
+#define IMAGEDISPLAY_H
+
+#include "qglscenenode.h"
+#include "qglmaterialcollection.h"
+
+#include <QString>
+
+class QGLBuilder;
+class QGLTexture2D;
+class QGLPainter;
+class ThumbnailNode;
+
+class ImageDisplay : public QGLSceneNode
+{
+ Q_OBJECT
+public:
+ ImageDisplay(QObject *parent, QGLMaterialCollection *materials, qreal wallSize = 4.0);
+ ~ImageDisplay();
+ int maxImages() const { return m_maxImages; }
+ void setMaxImages(int max) { m_maxImages = max; }
+signals:
+ void framesChanged();
+public slots:
+ void addThumbnailNode(const QUrl &url);
+private:
+ QGLSceneNode *m_wall;
+ QGLSceneNode *m_frames;
+ QGLSceneNode *m_currentWall;
+ ThumbnailNode *m_currentFrame;
+ QGLAbstractEffect *m_effect;
+ bool m_imageSetToDefault;
+ int m_count;
+ qreal m_size;
+ qreal m_frameSize;
+ int m_maxImages;
+ QImage m_frameImage;
+ int m_frameLoadingMaterial;
+ QGeometryData m_frameGeometry;
+ QGeometryData m_wallGeometry;
+ QVector2DArray m_atlasPlaceHolder;
+};
+
+#endif // IMAGEDISPLAY_H
diff --git a/demos/photobrowser3d/imageloader.cpp b/demos/photobrowser3d/imageloader.cpp
new file mode 100644
index 000000000..912ae7209
--- /dev/null
+++ b/demos/photobrowser3d/imageloader.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "imageloader.h"
+#include "imagemanager.h"
+#include "bytereader.h"
+
+#include <QFileInfo>
+#include <QTime>
+#include <QDir>
+#include <QStringList>
+#include <QPixmap>
+#include <QPainter>
+#include <QBuffer>
+#include <QImageReader>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QTimer>
+
+ImageLoader::ImageLoader()
+{
+ m_stop = 0;
+}
+
+ImageLoader::~ImageLoader()
+{
+ // nothing to do here
+}
+
+ThumbnailableImage ImageLoader::image() const
+{
+ return m_image;
+}
+
+void ImageLoader::setImage(const ThumbnailableImage &image)
+{
+ m_image = image;
+ if (!m_stop && isRunning())
+ emit readRequired(image);
+}
+
+void ImageLoader::stop()
+{
+ m_stop.ref();
+ emit stopLoading();
+}
+
+void ImageLoader::queueInitialImage()
+{
+ emit readRequired(m_image);
+}
+
+void ImageLoader::unusedTimeout()
+{
+ emit unused();
+}
+
+void ImageLoader::run()
+{
+ ByteReader reader;
+ connect(this, SIGNAL(readRequired(ThumbnailableImage)),
+ &reader, SLOT(loadFile(ThumbnailableImage)));
+ connect(&reader, SIGNAL(imageLoaded(ThumbnailableImage)),
+ this, SIGNAL(imageLoaded(ThumbnailableImage)));
+
+ connect(this, SIGNAL(stopLoading()), &reader, SLOT(stop()));
+ connect(&reader, SIGNAL(stopped()), this, SLOT(quit()));
+
+ QTimer timer;
+ connect(&timer, SIGNAL(timeout()), this, SLOT(unusedTimeout()));
+ timer.start(2 * 60 * 1000);
+
+ if (!m_image.isNull())
+ QTimer::singleShot(0, this, SLOT(queueInitialImage()));
+
+ exec();
+}
diff --git a/demos/photobrowser3d/imageloader.h b/demos/photobrowser3d/imageloader.h
new file mode 100644
index 000000000..560436ede
--- /dev/null
+++ b/demos/photobrowser3d/imageloader.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef IMAGELOADER_H
+#define IMAGELOADER_H
+
+#include <QThread>
+#include <QUrl>
+#include <QMutex>
+#include <QAtomicInt>
+
+#include "thumbnailableimage.h"
+
+class ImageManager;
+class ByteReader;
+
+class ImageLoader : public QThread
+{
+ Q_OBJECT
+public:
+ ImageLoader();
+ ~ImageLoader();
+ ThumbnailableImage image() const;
+ void setImage(const ThumbnailableImage &image);
+signals:
+ void imageLoaded(const ThumbnailableImage &image);
+ void stopLoading();
+ void readRequired(const ThumbnailableImage &image);
+ void thumbnailRequired(const ThumbnailableImage &image);
+ void thumbnailDone(const ThumbnailableImage &image);
+ void unused();
+public slots:
+ void stop();
+protected:
+ void run();
+private slots:
+ void queueInitialImage();
+ void unusedTimeout();
+private:
+ ThumbnailableImage m_image;
+ QAtomicInt m_stop;
+ ByteReader *m_reader;
+};
+
+#endif // IMAGELOADER_H
diff --git a/demos/photobrowser3d/imagemanager.cpp b/demos/photobrowser3d/imagemanager.cpp
new file mode 100644
index 000000000..30e2148d4
--- /dev/null
+++ b/demos/photobrowser3d/imagemanager.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "imagemanager.h"
+#include "qatlas.h"
+#include "filescanner.h"
+#include "threadpool.h"
+
+#include <QTime>
+#include <QTimer>
+#include <QDir>
+
+ImageManager::ImageManager()
+{
+}
+
+ImageManager::~ImageManager()
+{
+}
+
+// INVARIANT: only ever called before the run() function is started
+// therefore no need for synchronized url
+void ImageManager::setImageBaseUrl(const QUrl &url)
+{
+ Q_ASSERT(!isRunning());
+ m_url = url;
+}
+
+/*!
+ Stop the running threads if any, then sit waiting in the event loop
+ for a quit call.
+*/
+void ImageManager::stop()
+{
+ emit stopAll();
+}
+
+void ImageManager::scanForFiles()
+{
+ // TODO: In a real app there would be a way to detect new files arriving
+ // and trigger a rescan to pick these new files up. Here we just scan
+ // once and then destroy the scanner, to save on resources.
+
+#ifndef QT_USE_TEST_IMAGES
+ // TODO: If the amount of files is large and the app is quit early the
+ // scanner could still be going when the threadpool quits. For now
+ // assume its ok...
+ FileScanner *scanner = new FileScanner;
+ scanner->setBaseUrl(m_url);
+ connect(scanner, SIGNAL(imageUrl(QUrl)), this, SIGNAL(imageUrl(QUrl)));
+ connect(scanner, SIGNAL(finished()), scanner, SLOT(deleteLater()));
+ connect(this, SIGNAL(stopAll()), scanner, SLOT(stop()));
+ scanner->start();
+#else
+ QDir testImages(":/pictures");
+ QStringList pics = testImages.entryList();
+ for (int i = 0; i < pics.size(); ++i)
+ {
+ QUrl url;
+ url.setScheme("file");
+ url.setPath(testImages.filePath(pics.at(i)));
+ emit imageUrl(url);
+ }
+ qDebug() << "== test images loaded ==";
+#endif
+}
+
+void ImageManager::quit()
+{
+ QThread::quit();
+}
+
+void ImageManager::run()
+{
+ if (m_url.scheme() != "file")
+ {
+ qWarning("URL scheme %s not yet supported", qPrintable(m_url.scheme()));
+ return;
+ }
+
+ // execute once in the event loop below
+ QTimer::singleShot(0, this, SLOT(scanForFiles()));
+
+#ifndef QT_NO_THREADED_FILE_LOAD
+ ThreadPool pool;
+
+ connect(this, SIGNAL(deployLoader(ThumbnailableImage)),
+ &pool, SLOT(deployLoader(ThumbnailableImage)));
+
+ connect(this, SIGNAL(stopAll()), &pool, SLOT(stop()));
+ connect(&pool, SIGNAL(stopped()), this, SLOT(quit()));
+#endif
+
+ exec();
+}
diff --git a/demos/photobrowser3d/imagemanager.h b/demos/photobrowser3d/imagemanager.h
new file mode 100644
index 000000000..51482b1cd
--- /dev/null
+++ b/demos/photobrowser3d/imagemanager.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef IMAGEMANAGER_H
+#define IMAGEMANAGER_H
+
+#include <QThread>
+#include <QUrl>
+#include <QImage>
+#include <QMutex>
+
+#include "thumbnailableimage.h"
+
+class Launcher;
+
+class ImageManager : public QThread
+{
+ Q_OBJECT
+public:
+ ImageManager();
+ ~ImageManager();
+ QUrl imageBaseUrl() const { return m_url; }
+ void setImageBaseUrl(const QUrl &url);
+public slots:
+ void stop();
+ void quit();
+signals:
+ void imageUrl(const QUrl &);
+ void imageReady(const ThumbnailableImage &);
+ void deployLoader(const ThumbnailableImage &);
+ void stopAll();
+protected:
+ void run();
+private slots:
+ void scanForFiles();
+private:
+ QUrl m_url;
+};
+
+#endif // IMAGEMANAGER_H
diff --git a/demos/photobrowser3d/images/P1000223.JPG b/demos/photobrowser3d/images/P1000223.JPG
new file mode 100644
index 000000000..48edfbc2d
--- /dev/null
+++ b/demos/photobrowser3d/images/P1000223.JPG
Binary files differ
diff --git a/demos/photobrowser3d/images/P1000228.JPG b/demos/photobrowser3d/images/P1000228.JPG
new file mode 100644
index 000000000..2797b6df5
--- /dev/null
+++ b/demos/photobrowser3d/images/P1000228.JPG
Binary files differ
diff --git a/demos/photobrowser3d/images/P1000441.JPG b/demos/photobrowser3d/images/P1000441.JPG
new file mode 100644
index 000000000..b4037b49e
--- /dev/null
+++ b/demos/photobrowser3d/images/P1000441.JPG
Binary files differ
diff --git a/demos/photobrowser3d/images/P1000472.JPG b/demos/photobrowser3d/images/P1000472.JPG
new file mode 100644
index 000000000..067afdd4a
--- /dev/null
+++ b/demos/photobrowser3d/images/P1000472.JPG
Binary files differ
diff --git a/demos/photobrowser3d/images/arrows-left.png b/demos/photobrowser3d/images/arrows-left.png
new file mode 100644
index 000000000..791f2c6b1
--- /dev/null
+++ b/demos/photobrowser3d/images/arrows-left.png
Binary files differ
diff --git a/demos/photobrowser3d/images/arrows.xcf b/demos/photobrowser3d/images/arrows.xcf
new file mode 100644
index 000000000..302bcd6eb
--- /dev/null
+++ b/demos/photobrowser3d/images/arrows.xcf
Binary files differ
diff --git a/demos/photobrowser3d/images/default_sky_base.xcf b/demos/photobrowser3d/images/default_sky_base.xcf
new file mode 100644
index 000000000..050812f7d
--- /dev/null
+++ b/demos/photobrowser3d/images/default_sky_base.xcf
Binary files differ
diff --git a/demos/photobrowser3d/images/default_sky_down.png b/demos/photobrowser3d/images/default_sky_down.png
new file mode 100644
index 000000000..531ba75e9
--- /dev/null
+++ b/demos/photobrowser3d/images/default_sky_down.png
Binary files differ
diff --git a/demos/photobrowser3d/images/default_sky_east.png b/demos/photobrowser3d/images/default_sky_east.png
new file mode 100644
index 000000000..09bfc3ad5
--- /dev/null
+++ b/demos/photobrowser3d/images/default_sky_east.png
Binary files differ
diff --git a/demos/photobrowser3d/images/default_sky_north.png b/demos/photobrowser3d/images/default_sky_north.png
new file mode 100644
index 000000000..b97aaa20a
--- /dev/null
+++ b/demos/photobrowser3d/images/default_sky_north.png
Binary files differ
diff --git a/demos/photobrowser3d/images/default_sky_south.png b/demos/photobrowser3d/images/default_sky_south.png
new file mode 100644
index 000000000..28db27816
--- /dev/null
+++ b/demos/photobrowser3d/images/default_sky_south.png
Binary files differ
diff --git a/demos/photobrowser3d/images/default_sky_up.png b/demos/photobrowser3d/images/default_sky_up.png
new file mode 100644
index 000000000..a56feddbf
--- /dev/null
+++ b/demos/photobrowser3d/images/default_sky_up.png
Binary files differ
diff --git a/demos/photobrowser3d/images/default_sky_west.png b/demos/photobrowser3d/images/default_sky_west.png
new file mode 100644
index 000000000..4d2746b0d
--- /dev/null
+++ b/demos/photobrowser3d/images/default_sky_west.png
Binary files differ
diff --git a/demos/photobrowser3d/images/girder.png b/demos/photobrowser3d/images/girder.png
new file mode 100644
index 000000000..f9b6c4dc6
--- /dev/null
+++ b/demos/photobrowser3d/images/girder.png
Binary files differ
diff --git a/demos/photobrowser3d/images/no-images-yet.png b/demos/photobrowser3d/images/no-images-yet.png
new file mode 100644
index 000000000..5d4f673ae
--- /dev/null
+++ b/demos/photobrowser3d/images/no-images-yet.png
Binary files differ
diff --git a/demos/photobrowser3d/images/no-images-yet.xcf b/demos/photobrowser3d/images/no-images-yet.xcf
new file mode 100644
index 000000000..f084d45e4
--- /dev/null
+++ b/demos/photobrowser3d/images/no-images-yet.xcf
Binary files differ
diff --git a/demos/photobrowser3d/images/sample_image.jpg b/demos/photobrowser3d/images/sample_image.jpg
new file mode 100644
index 000000000..2826f9251
--- /dev/null
+++ b/demos/photobrowser3d/images/sample_image.jpg
Binary files differ
diff --git a/demos/photobrowser3d/launcher.cpp b/demos/photobrowser3d/launcher.cpp
new file mode 100644
index 000000000..3005bb19c
--- /dev/null
+++ b/demos/photobrowser3d/launcher.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "launcher.h"
+#include "imageloader.h"
+#include "imagemanager.h"
+
+#include <QSemaphore>
+#include <QTime>
+#include <QFileInfo>
+#include <QDir>
+#include <QStringList>
+#include <QSet>
+#include <QDebug>
+
+Launcher::Launcher(ImageManager *manager)
+ : m_manager(manager)
+ , m_stop(false)
+{
+ Q_ASSERT(m_manager);
+}
+
+void Launcher::run()
+{
+ if (m_url.isEmpty())
+ {
+ qWarning("Launcher::run - empty URL!");
+ return;
+ }
+ if (m_url.scheme() != QLatin1String("file"))
+ {
+ qWarning("URL scheme %s not yet supported", qPrintable(m_url.scheme()));
+ return;
+ }
+ QStringList queue;
+ queue.append(m_url.path());
+ QSet<QString> loopProtect;
+ while (queue.size() > 0 && !m_stop)
+ {
+ QString path = queue.takeFirst();
+ QFileInfo u(path);
+ if (u.isSymLink())
+ path = u.symLinkTarget();
+ if (u.isDir())
+ {
+ if (!loopProtect.contains(path))
+ {
+ loopProtect.insert(path);
+ QDir dir(path);
+ QStringList entries = dir.entryList();
+ QStringList::const_iterator it = entries.constBegin();
+ for ( ; it != entries.constEnd(); ++it)
+ {
+ // ignore hidden files, system directories
+ if ((*it).startsWith(QLatin1Char('.')))
+ continue;
+ queue.append(dir.absoluteFilePath(*it));
+ }
+ }
+ }
+ else
+ {
+ if (u.isFile() && u.isReadable())
+ {
+ // do no checking here for file extensions etc - just
+ // forward any readable file found under the pictures
+ // directory to the QImage loader, and let it sort out
+ // if the thing can be loaded as an image.
+ QUrl url2;
+ url2.setScheme(QLatin1String("file"));
+ url2.setPath(u.absoluteFilePath());
+ m_manager->acquire();
+ emit imageUrl(url2);
+ }
+ }
+ }
+}
diff --git a/demos/photobrowser3d/main.cpp b/demos/photobrowser3d/main.cpp
new file mode 100644
index 000000000..748866bab
--- /dev/null
+++ b/demos/photobrowser3d/main.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QApplication>
+#include <QtCore/QThread>
+
+#include "photobrowser3dview.h"
+
+int main(int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(photobrowser3d);
+
+ QApplication app(argc, argv);
+
+ // for QSettings
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nokia.com");
+ QCoreApplication::setApplicationName("photobrowser3d");
+
+ int result = 0;
+ {
+ PhotoBrowser3DView view;
+
+ if (QApplication::arguments().contains("-maximize"))
+ view.showMaximized();
+ else if (QApplication::arguments().contains("-fullscreen"))
+ view.showFullScreen();
+ else
+ view.show();
+
+ result = app.exec();
+ }
+ return result;
+}
diff --git a/demos/photobrowser3d/pancontroller.cpp b/demos/photobrowser3d/pancontroller.cpp
new file mode 100644
index 000000000..e45b4abeb
--- /dev/null
+++ b/demos/photobrowser3d/pancontroller.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pancontroller.h"
+#include "qglview.h"
+#include "qglcamera.h"
+#include "photobrowser3dview.h"
+
+#include <qmath.h>
+
+#include <QtGlobal>
+#include <QTime>
+
+class PanControllerPrivate
+{
+public:
+ PanControllerPrivate()
+ : speed(0.0f)
+ , angle(0.0f)
+ , arrowDirection(Qt::NoArrow)
+ , view(0)
+ , maxSpeed(4.0f)
+ , defaultDistance(0.0f)
+ , panDistance(0.0f)
+ , panViewAngle(M_PI / 4.0f) // 45 degrees in radians
+ , animating(false)
+ , elapsed(0.0f)
+ {
+ panTime.start();
+ }
+
+ void calculateValues();
+
+ qreal speed;
+ qreal angle;
+ Qt::ArrowType arrowDirection;
+ QGLView *view;
+ QTime panTime;
+ qreal maxSpeed;
+ qreal defaultDistance;
+ qreal panDistance;
+ qreal panViewAngle;
+ bool animating;
+ qreal elapsed;
+};
+
+PanController::PanController(QObject *parent)
+ : QObject(parent)
+ , d(new PanControllerPrivate)
+{
+ QGLView *v = qobject_cast<QGLView*>(parent);
+ if (v)
+ d->view = v;
+}
+
+PanController::~PanController()
+{
+ delete d;
+}
+
+qreal PanController::defaultDistance() const
+{
+ return d->defaultDistance;
+}
+
+void PanController::setDefaultDistance(qreal dist)
+{
+ d->defaultDistance = dist;
+}
+
+qreal PanController::panDistance() const
+{
+ return d->panDistance;
+}
+
+void PanController::setPanDistance(qreal dist)
+{
+ d->panDistance = dist;
+}
+
+qreal PanController::panViewAngle() const
+{
+ return d->panViewAngle;
+}
+
+void PanController::setPanViewAngle(qreal angle)
+{
+ d->panViewAngle = angle;
+}
+
+void PanController::setMaxSpeed(qreal maxSpeed)
+{
+ d->maxSpeed = maxSpeed;
+}
+
+qreal PanController::maxSpeed() const
+{
+ return d->maxSpeed;
+}
+
+void PanController::setSpeed(qreal speed)
+{
+ qreal t = d->panTime.restart();
+ if (d->speed != speed)
+ {
+ d->speed = speed;
+ d->angle = speed * d->panViewAngle;
+ if (!qIsNull(d->speed))
+ d->animating = true;
+ d->elapsed += t;
+ d->calculateValues();
+ emit speedChanged();
+ }
+}
+
+qreal PanController::speed() const
+{
+ return d->speed;
+}
+
+void PanController::pan()
+{
+ if (d->animating)
+ {
+ qreal t = d->panTime.restart();
+ d->elapsed += t;
+ // dont recalculate every single time
+ // 30ms frame time == 33fps - more than enough
+ if (d->elapsed > 30)
+ d->calculateValues();
+
+ PhotoBrowser3DView *view = qobject_cast<PhotoBrowser3DView*>(parent());
+ Q_ASSERT(view);
+ view->update();
+ }
+}
+
+void PanControllerPrivate::calculateValues()
+{
+ if (view && animating)
+ {
+ QGLCamera *cam = view->camera();
+ Q_ASSERT(cam);
+
+ QVector3D c = cam->center();
+ QVector3D e = cam->eye();
+
+ if (qFuzzyIsNull(speed))
+ {
+ c.setX(e.x());
+ e.setZ(defaultDistance);
+ }
+ else
+ {
+ // as speed goes from 0 -> 1, eye moves closer to z=0 plane
+ e.setZ(defaultDistance - (speed * (defaultDistance - panDistance)));
+
+ // the view angle is a direct function of the speed see setSpeed() above
+ // and as view angle increases we look further along the x-axis
+ qreal opp = (e.z() - c.z()) * qTan(angle);
+
+ // velocity along the x axis is controlled by speed (a value from 0 -> 1
+ // which is a modifier for the maxSpeed, a constant). the velocity gives
+ // us the incremental change in x for this unit time
+ qreal dx = (speed * maxSpeed * elapsed);
+
+ if (arrowDirection == Qt::LeftArrow)
+ {
+ e.setX(e.x() - dx);
+ c.setX(e.x() - opp);
+ }
+ else if (arrowDirection == Qt::RightArrow)
+ {
+ e.setX(e.x() + dx);
+ c.setX(e.x() + opp);
+ }
+ }
+ cam->setEye(e);
+ cam->setCenter(c);
+ }
+ elapsed = 0;
+ if (qIsNull(speed))
+ animating = false;
+}
+
+Qt::ArrowType PanController::direction() const
+{
+ return d->arrowDirection;
+}
+
+void PanController::setDirection(Qt::ArrowType arrow)
+{
+ Q_ASSERT(arrow == Qt::LeftArrow || arrow == Qt::RightArrow);
+ d->arrowDirection = arrow;
+}
+
+QGLView *PanController::view() const
+{
+ return d->view;
+}
+
+void PanController::setView(QGLView *view)
+{
+ d->view = view;
+}
+
diff --git a/demos/photobrowser3d/pancontroller.h b/demos/photobrowser3d/pancontroller.h
new file mode 100644
index 000000000..c0354b618
--- /dev/null
+++ b/demos/photobrowser3d/pancontroller.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PANCONTROLLER_H
+#define PANCONTROLLER_H
+
+#include <QObject>
+#include <Qt>
+
+class PanControllerPrivate;
+class QGLView;
+
+class PanController : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal speed READ speed WRITE setSpeed NOTIFY speedChanged)
+public:
+ explicit PanController(QObject *parent = 0);
+ ~PanController();
+
+ qreal defaultDistance() const;
+ void setDefaultDistance(qreal d);
+
+ qreal panDistance() const;
+ void setPanDistance(qreal d);
+
+ qreal panViewAngle() const;
+ void setPanViewAngle(qreal angle);
+
+ qreal maxSpeed() const;
+ void setMaxSpeed(qreal maxSpeed);
+
+ qreal speed() const;
+ void setSpeed(qreal speed);
+
+ Qt::ArrowType direction() const;
+ void setDirection(Qt::ArrowType arrow);
+
+ QGLView *view() const;
+ void setView(QGLView *view);
+
+ void pan();
+
+signals:
+ void speedChanged();
+
+private:
+ PanControllerPrivate *d;
+};
+
+#endif // PANCONTROLLER_H
diff --git a/demos/photobrowser3d/photobrowser3d.pro b/demos/photobrowser3d/photobrowser3d.pro
new file mode 100644
index 000000000..b5c695bca
--- /dev/null
+++ b/demos/photobrowser3d/photobrowser3d.pro
@@ -0,0 +1,62 @@
+TEMPLATE = app
+TARGET = photobrowser3d
+CONFIG += qt warn_on qt3d
+SOURCES += main.cpp\
+ photobrowser3dview.cpp \
+ imagedisplay.cpp \
+ skybox.cpp \
+ imagemanager.cpp \
+ imageloader.cpp \
+ qfocusadaptor.cpp \
+ thumbnailableimage.cpp \
+ qatlas.cpp \
+ thumbnailnode.cpp \
+ thumbnaileffect.cpp \
+ filescanner.cpp \
+ bytereader.cpp \
+ threadpool.cpp \
+ buttons.cpp \
+ qphotobrowser3dscene.cpp \
+ pancontroller.cpp
+
+HEADERS += photobrowser3dview.h \
+ imagedisplay.h \
+ skybox.h \
+ imagemanager.h \
+ imageloader.h \
+ qfocusadaptor.h \
+ thumbnailableimage.h \
+ qatlas.h \
+ thumbnailnode.h \
+ thumbnaileffect.h \
+ filescanner.h \
+ bytereader.h \
+ threadpool.h \
+ buttons.h \
+ qphotobrowser3dscene.h \
+ pancontroller.h
+
+# Uncomment this line to force all file loading is done in the gui thread
+# instead of a background thread - useful for debugging.
+# DEFINES += QT_NO_THREADED_FILE_LOAD
+
+# Uncomment this to use test images instead of scanning the file-system for
+# pictures. The test images are stored in in-memory resources "files".
+# DEFINES += QT_USE_TEST_IMAGES
+
+RESOURCES += \
+ photobrowser3d.qrc
+
+DESTDIR = ../../bin
+
+OTHER_FILES += \
+ shaders/replace_texture.fsh \
+ shaders/replace_texture.vsh
+
+symbian {
+ symbian-abld|symbian-sbsv2 {
+ # ro-section in photobrowser3d can exceed default allocated space, so move rw-section a little further
+ QMAKE_LFLAGS.ARMCC += --rw-base 0x800000
+ QMAKE_LFLAGS.GCCE += -Tdata 0xC00000
+ }
+}
diff --git a/demos/photobrowser3d/photobrowser3d.qrc b/demos/photobrowser3d/photobrowser3d.qrc
new file mode 100644
index 000000000..351c9faf3
--- /dev/null
+++ b/demos/photobrowser3d/photobrowser3d.qrc
@@ -0,0 +1,24 @@
+<RCC>
+ <qresource prefix="/res">
+ <file>images/sample_image.jpg</file>
+ <file alias="down.png">images/default_sky_down.png</file>
+ <file alias="west.png">images/default_sky_east.png</file>
+ <file alias="north.png">images/default_sky_north.png</file>
+ <file alias="south.png">images/default_sky_south.png</file>
+ <file alias="up.png">images/default_sky_up.png</file>
+ <file alias="east.png">images/default_sky_west.png</file>
+ <file>images/girder.png</file>
+ </qresource>
+ <qresource prefix="/shaders">
+ <file alias="replace_texture.fsh">shaders/replace_texture.fsh</file>
+ <file alias="replace_texture.vsh">shaders/replace_texture.vsh</file>
+ </qresource>
+ <qresource prefix="/pictures">
+ <file alias="im1.jpg">images/P1000223.JPG</file>
+ <file alias="im2.jpg">images/P1000228.JPG</file>
+ <file alias="im3.jpg">images/P1000472.JPG</file>
+ </qresource>
+ <qresource prefix="/controls">
+ <file alias="arrows-left.png">images/arrows-left.png</file>
+ </qresource>
+</RCC>
diff --git a/demos/photobrowser3d/photobrowser3dview.cpp b/demos/photobrowser3d/photobrowser3dview.cpp
new file mode 100644
index 000000000..f73f9a19c
--- /dev/null
+++ b/demos/photobrowser3d/photobrowser3dview.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "photobrowser3dview.h"
+#include "imagemanager.h"
+#include "imagedisplay.h"
+#include "skybox.h"
+#include "qglpicknode.h"
+#include "qfocusadaptor.h"
+#include "thumbnailableimage.h"
+#include "qatlas.h"
+#include "filescanner.h"
+#include "buttons.h"
+#include "qphotobrowser3dscene.h"
+#include "pancontroller.h"
+#include "thumbnailnode.h"
+
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QWheelEvent>
+#include <QDir>
+#include <QTimer>
+#include <QTime>
+#include <QStateMachine>
+#include <QState>
+#include <QFinalState>
+#include <QSignalTransition>
+#include <QPropertyAnimation>
+
+PhotoBrowser3DView::PhotoBrowser3DView()
+ : QGLView()
+ , m_scene(0)
+ , m_display(0)
+ , m_images(0)
+ , m_buttons(0)
+ , m_skybox(0)
+ , m_palette(new QGLMaterialCollection(this))
+ , m_state(0)
+ , m_app(0)
+ , m_zoomed(0)
+ , m_browse(0)
+ , m_pan(0)
+ , m_fa(0)
+ , m_pc(0)
+ , m_pickableDirty(true)
+ , m_done(false)
+ , m_closing(false)
+{
+ setOption(QGLView::ObjectPicking, true);
+ // setOption(QGLView::ShowPicking, true);
+ //setOption(QGLView::CameraNavigation, false);
+
+ qRegisterMetaType<ThumbnailableImage>("ThumbnailableImage");
+
+ QString path = ":/res";
+ int ix = qApp->arguments().indexOf("--skybox");
+ if (ix != -1)
+ {
+ if (qApp->arguments().size() > ix+1)
+ path = qApp->arguments().at(ix+1);
+ else
+ qWarning("Expected path/to/skybox/files after \"--skybox\" switch\n");
+ }
+
+ m_displaySize = 4.0;
+ m_scene = new QPhotoBrowser3DScene(this);
+ m_buttons = new Buttons(this, m_palette);
+ m_scene->mainNode()->addNode(m_buttons);
+ m_scene->setPickable(true);
+ m_skybox = new SkyBox(this, path);
+ m_display = new ImageDisplay(this, m_palette, m_displaySize);
+
+ setupStates();
+
+ // make sure this only gets created in the GUI thread
+ QAtlas::instance();
+
+ QTimer::singleShot(0, this, SLOT(initialise()));
+}
+
+PhotoBrowser3DView::~PhotoBrowser3DView()
+{
+ // nothing to be done here
+}
+
+void PhotoBrowser3DView::setupStates()
+{
+ m_state = new QStateMachine(this);
+ m_app = new QState;
+ m_zoomed = new QState(m_app);
+ m_browse = new QState(m_app);
+ m_pan = new QState(m_app);
+ m_app->setInitialState(m_browse);
+ m_state->addState(m_app);
+ QFinalState *end_state = new QFinalState;
+ m_app->addTransition(this, SIGNAL(done()), end_state);
+ m_state->addState(end_state);
+ connect(m_state, SIGNAL(finished()), this, SLOT(close()));
+
+ m_fa = new QFocusAdaptor(this);
+ m_browse->assignProperty(m_fa, "progress", 0.0);
+ m_zoomed->assignProperty(m_fa, "progress", 1.0);
+
+ m_pc = new PanController(this);
+ m_pc->setMaxSpeed(m_displaySize / 1000.0f);
+ m_browse->assignProperty(m_pc, "speed", 0.0);
+ m_pan->assignProperty(m_pc, "speed", 1.0);
+
+ m_state->setObjectName("StateMachine");
+ m_app->setObjectName("Application");
+ m_zoomed->setObjectName("Zoomed");
+ m_browse->setObjectName("Browse");
+ m_pan->setObjectName("Pan");
+ end_state->setObjectName("EndState");
+
+ QSignalTransition *transition = m_browse->addTransition(this, SIGNAL(zoom()), m_zoomed);
+ QPropertyAnimation *a = new QPropertyAnimation(m_fa, "progress");
+ a->setDuration(500);
+ a->setEasingCurve(QEasingCurve::OutQuad);
+ transition->addAnimation(a);
+
+ transition = m_zoomed->addTransition(this, SIGNAL(zoom()), m_browse);
+ a = new QPropertyAnimation(m_fa, "progress");
+ a->setDuration(500);
+ a->setEasingCurve(QEasingCurve::InQuad);
+ transition->addAnimation(a);
+
+ transition = m_browse->addTransition(this, SIGNAL(pan()), m_pan);
+ a = new QPropertyAnimation(m_pc, "speed");
+ a->setDuration(500);
+ a->setEasingCurve(QEasingCurve::OutQuad);
+ transition->addAnimation(a);
+
+ transition = m_pan->addTransition(this, SIGNAL(pan()), m_browse);
+ a = new QPropertyAnimation(m_pc, "speed");
+ a->setDuration(500);
+ a->setEasingCurve(QEasingCurve::InQuad);
+ transition->addAnimation(a);
+
+ m_state->setInitialState(m_app);
+ m_state->start();
+}
+
+void PhotoBrowser3DView::initialise()
+{
+ QString path = QDir::home().absoluteFilePath("Pictures");
+ int ix = qApp->arguments().indexOf("--pictures");
+ if (ix != -1)
+ {
+ if (qApp->arguments().size() > ix+1)
+ path = qApp->arguments().at(ix+1);
+ else
+ qWarning("Expected /path/to/image/files after \"--pictures\" switch\n");
+ }
+
+ QUrl url;
+ url.setScheme("file");
+ url.setPath(path);
+
+ QFileInfo fi(path);
+ if (!fi.exists() || !fi.isDir())
+ {
+ qWarning("No pictures directory found at %s\n"
+ "using test images", qPrintable(path));
+
+ url.setPath(":/pictures");
+ }
+
+#ifdef QT_NO_THREADED_FILE_LOAD
+ nonThreadedFileLoad(url);
+#else
+ initialiseImageManager(url);
+#endif
+}
+
+void PhotoBrowser3DView::initialiseImageManager(const QUrl &url)
+{
+ m_images = new ImageManager;
+
+ connect(m_images, SIGNAL(imageUrl(QUrl)), m_display, SLOT(addThumbnailNode(QUrl)));
+ connect(m_images, SIGNAL(finished()), this, SLOT(waitForExit()));
+
+ connect(m_display, SIGNAL(framesChanged()), this, SLOT(pickableDirty()));
+ connect(m_display, SIGNAL(framesChanged()), this, SLOT(update()));
+
+ m_images->setImageBaseUrl(url);
+ QThread::Priority p = QThread::idealThreadCount() < 2 ?
+ QThread::IdlePriority : QThread::NormalPriority;
+ m_images->start(p);
+}
+
+void PhotoBrowser3DView::nonThreadedFileLoad(const QUrl &url)
+{
+#if defined(QT_USE_TEST_IMAGES)
+ Q_UNUSED(url);
+ QDir testImages(":/pictures");
+ QStringList pics = testImages.entryList();
+ for (int i = 0; i < pics.size(); ++i)
+ {
+ QUrl url;
+ url.setScheme("file");
+ url.setPath(testImages.filePath(pics.at(i)));
+ m_display->addThumbnailNode(url);
+ }
+ pickableDirty();
+ qDumpScene(m_display);
+#else
+ FileScanner *scanner = new FileScanner(this);
+ scanner->setBaseUrl(url);
+ QTimer::singleShot(0, scanner, SLOT(scan()));
+ connect(scanner, SIGNAL(imageUrl(QUrl)), m_display, SLOT(addThumbnailNode(QUrl)));
+#endif
+}
+
+void PhotoBrowser3DView::wheelEvent(QWheelEvent *e)
+{
+ e->accept();
+ QVector3D viewVec = camera()->eye() - camera()->center();
+ qreal zoomMag = viewVec.length();
+ qreal inc = float(e->delta()) / 50.0f;
+ if (!qFuzzyIsNull(inc))
+ {
+ zoomMag += inc;
+ if (zoomMag < 2.0f)
+ zoomMag = 2.0f;
+ QRay3D viewLine(camera()->center(), viewVec.normalized());
+ camera()->setEye(viewLine.point(zoomMag));
+ update();
+ }
+}
+
+void PhotoBrowser3DView::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Q)
+ {
+ m_done = true;
+ emit done();
+ }
+ else if (e->key() == Qt::Key_Right)
+ {
+ m_pc->setDirection(Qt::RightArrow);
+ emit pan();
+ }
+ else if (e->key() == Qt::Key_Left)
+ {
+ m_pc->setDirection(Qt::LeftArrow);
+ emit pan();
+ }
+ else if (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)
+ {
+ QVector3D viewVec = camera()->eye() - camera()->center();
+ qreal zoomMag = viewVec.length();
+ zoomMag += (e->key() == Qt::Key_Up) ? -0.5f : 0.5f;
+ if (zoomMag < 5.0f)
+ zoomMag = 5.0f;
+ QRay3D viewLine(camera()->center(), viewVec.normalized());
+ camera()->setEye(viewLine.point(zoomMag));
+ update();
+ }
+ else
+ {
+ QGLView::keyPressEvent(e);
+ }
+}
+
+void PhotoBrowser3DView::waitForExit()
+{
+ QThread::yieldCurrentThread();
+ m_images->wait();
+ m_images->deleteLater();
+ m_images = 0;
+ if (m_closing)
+ {
+ if (!m_done)
+ {
+ emit done();
+ m_done = true;
+ }
+ }
+}
+
+void PhotoBrowser3DView::closeEvent(QCloseEvent *e)
+{
+ if (m_images)
+ {
+ e->ignore();
+ m_images->stop();
+
+ // this was a request to close the main window, so we are closing up shop
+ // set this flag to indicate that when the image manager stops done event
+ // should be signalled to the state machine, resulting in close
+ m_closing = true;
+ fprintf(stderr, "Closing down........");
+ }
+ else
+ {
+ fprintf(stderr, " done\n");
+ e->accept();
+ }
+}
+
+void PhotoBrowser3DView::mousePressEvent(QMouseEvent *e)
+{
+ Q_UNUSED(e);
+ registerPickableNodes();
+ QGLView::mousePressEvent(e);
+}
+
+void PhotoBrowser3DView::initializeGL(QGLPainter *painter)
+{
+ Q_UNUSED(painter);
+ QAtlas::instance()->initialize(painter);
+ camera()->setEye(QVector3D(0.0f, 0.0f, 4.0f * m_displaySize));
+ registerPickableNodes();
+ qreal q = camera()->eye().z();
+ qreal r = qBound(camera()->nearPlane(), q / 2.0f, camera()->nearPlane() * 3.0f);
+ m_pc->setDefaultDistance(q);
+ m_pc->setPanDistance(r);
+}
+
+void PhotoBrowser3DView::earlyPaintGL(QGLPainter *painter)
+{
+ Q_UNUSED(painter);
+
+ if (!painter->isPicking())
+ {
+ QAtlas::instance()->paint(painter);
+ }
+
+ if (!m_done)
+ m_pc->pan();
+
+ painter->setClearColor(Qt::blue);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void PhotoBrowser3DView::paintGL(QGLPainter *painter)
+{
+ if (!m_done)
+ {
+ glEnable(GL_BLEND);
+ m_skybox->draw(painter);
+ m_display->draw(painter);
+ m_buttons->draw(painter);
+ }
+}
+
+void PhotoBrowser3DView::resizeGL(int w, int h)
+{
+ Q_UNUSED(w);
+ Q_UNUSED(h);
+ m_buttons->clearPositions();
+ m_updateRequired = true;
+}
+
+void PhotoBrowser3DView::zoomImage()
+{
+ QGLPickNode *pn = qobject_cast<QGLPickNode*>(sender());
+ Q_ASSERT(pn);
+ QGLSceneNode *n = pn->target();
+ m_fa->setTarget(n);
+ emit zoom();
+}
+
+void PhotoBrowser3DView::goPan()
+{
+ QGLPickNode *pn = qobject_cast<QGLPickNode*>(sender());
+ Q_ASSERT(pn);
+ QGLSceneNode *n = pn->target();
+ m_pc->setDirection(n->objectName() == "Left Button" ? Qt::LeftArrow : Qt::RightArrow);
+ emit pan();
+}
+
+void PhotoBrowser3DView::pickableDirty()
+{
+ m_pickableDirty = true;
+}
+
+void PhotoBrowser3DView::registerPickableNodes()
+{
+ if (m_pickableDirty)
+ {
+ m_scene->generatePickNodes();
+ QList<QGLPickNode*> pickList = m_scene->pickNodes();
+ QList<QGLPickNode*>::const_iterator it = pickList.constBegin();
+ for ( ; it != pickList.constEnd(); ++it)
+ {
+ QGLPickNode *pn = *it;
+ pn->disconnect(this);
+ ThumbnailNode *node = qobject_cast<ThumbnailNode*>(pn->target());
+ if (node)
+ QObject::connect(pn, SIGNAL(clicked()), this, SLOT(zoomImage()));
+ else
+ QObject::connect(pn, SIGNAL(clicked()), this, SLOT(goPan()));
+ registerObject(pn->id(), pn);
+ }
+ m_pickableDirty = false;
+ }
+}
diff --git a/demos/photobrowser3d/photobrowser3dview.h b/demos/photobrowser3d/photobrowser3dview.h
new file mode 100644
index 000000000..97d484e71
--- /dev/null
+++ b/demos/photobrowser3d/photobrowser3dview.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PHOTOBROWSER3DVIEW_H
+#define PHOTOBROWSER3DVIEW_H
+
+#include "qglview.h"
+
+class ImageDisplay;
+class SkyBox;
+class QGLMaterialCollection;
+class QGLSceneNode;
+class ImageManager;
+class QState;
+class QStateMachine;
+class QFocusAdaptor;
+class QAtlas;
+class Buttons;
+class QPhotoBrowser3DScene;
+class PanController;
+
+class PhotoBrowser3DView : public QGLView
+{
+ Q_OBJECT
+public:
+ PhotoBrowser3DView();
+ ~PhotoBrowser3DView();
+ void initializeGL(QGLPainter *);
+ QPhotoBrowser3DScene *scene() { return m_scene; }
+signals:
+ void done();
+ void zoom();
+ void pan();
+protected:
+ void earlyPaintGL(QGLPainter *);
+ void paintGL(QGLPainter *);
+ void resizeGL(int w, int h);
+ void wheelEvent(QWheelEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void closeEvent(QCloseEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+private slots:
+ void initialise();
+ void zoomImage();
+ void pickableDirty();
+ void waitForExit();
+ void goPan();
+private:
+ void registerPickableNodes();
+ void setupStates();
+ void nonThreadedFileLoad(const QUrl &url);
+ void initialiseImageManager(const QUrl &url);
+
+ QPhotoBrowser3DScene *m_scene;
+ ImageDisplay *m_display;
+ ImageManager *m_images;
+ Buttons *m_buttons;
+ SkyBox *m_skybox;
+ QGLMaterialCollection *m_palette;
+ QStateMachine *m_state;
+ QState *m_app;
+ QState *m_zoomed;
+ QState *m_browse;
+ QState *m_pan;
+ QFocusAdaptor *m_fa;
+ PanController *m_pc;
+ bool m_pickableDirty;
+ qreal m_displaySize;
+ bool m_done;
+ bool m_closing;
+ bool m_updateRequired;
+};
+
+#endif // PHOTOBROWSER3DVIEW_H
diff --git a/demos/photobrowser3d/qatlas.cpp b/demos/photobrowser3d/qatlas.cpp
new file mode 100644
index 000000000..7973a0c0c
--- /dev/null
+++ b/demos/photobrowser3d/qatlas.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qatlas.h"
+#include "qareaallocator.h"
+#include "qgltexture2d.h"
+#include "qglpainter.h"
+#include "qgeometrydata.h"
+#include "qglmaterial.h"
+#include "qglpainter.h"
+#include "qglframebufferobjectsurface.h"
+#include "qglbuilder.h"
+
+#include <QImage>
+#include <QThread>
+#include <QGLFramebufferObject>
+#include <QGLFramebufferObjectFormat>
+#include <QCoreApplication>
+
+#ifndef GL_MULTISAMPLE
+#define GL_MULTISAMPLE 0x809D
+#endif
+
+QAtlas::QAtlas()
+ : m_size(1024, 1024)
+ , m_data(0)
+ , m_renderTarget(0)
+ , m_allocator(new QSimpleAreaAllocator(m_size))
+ , m_tex(0)
+ , m_material(new QGLMaterial)
+ , m_initialized(false)
+ , m_count(0)
+{
+}
+
+QAtlas::~QAtlas()
+{
+ delete m_data;
+ delete m_renderTarget;
+ delete m_allocator;
+}
+
+void QAtlas::initialize(QGLPainter *painter)
+{
+ Q_UNUSED(painter);
+ if (!m_initialized)
+ {
+ m_data = new QGLFramebufferObject(m_size);
+ m_renderTarget = new QGLFramebufferObjectSurface(m_data);
+ m_tex = QGLTexture2D::fromTextureId(m_data->texture(), m_size);
+ m_material->setTexture(m_tex, 1);
+ m_material->setObjectName("Atlas material");
+ m_initialized = true;
+ }
+}
+
+void QAtlas::paint(QGLPainter *painter)
+{
+ Q_ASSERT(QThread::currentThread() == qApp->thread());
+
+ if (m_allocationQueue.isEmpty() || painter->isPicking())
+ return;
+
+ glDisable(GL_DEPTH_TEST);
+
+ painter->pushSurface(m_renderTarget);
+ painter->setStandardEffect(QGL::FlatReplaceTexture2D);
+ painter->projectionMatrix().push();
+ painter->modelViewMatrix().push();
+ QRect rect = painter->currentSurface()->viewportRect();
+ QMatrix4x4 proj;
+ proj.ortho(rect);
+ painter->projectionMatrix() = proj;
+ painter->modelViewMatrix().setToIdentity();
+
+ painter->update();
+
+ QAtlasEntry entry = m_allocationQueue.takeFirst();
+
+ QRect a = entry.rect;
+ QImage image = entry.image;
+
+ if (a.left() == 0 && a.top() == 0) // first one - paint fill color
+ {
+ painter->setClearColor(Qt::red);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+
+ QGLTexture2D t;
+ t.setImage(image);
+ t.bind();
+ QVector3D va(a.left(), a.bottom()+1, 0);
+ QVector3D vb(a.right()+1, a.bottom()+1, 0);
+ QVector3D vc(a.right()+1, a.top(), 0);
+ QVector3D vd(a.left(), a.top(), 0);
+ QVector2D ta(0.0f, 0.0f);
+ QVector2D tb(1.0f, 0.0f);
+ QVector2D tc(1.0f, 1.0f);
+ QVector2D td(0.0f, 1.0f);
+ QGeometryData quad;
+ quad.setBufferStrategy(QGeometryData::KeepClientData);
+ quad.appendVertex(va, vb, vc, vd);
+ quad.appendTexCoord(ta, tb, tc, td);
+ quad.appendIndices(0, 1, 2);
+ quad.appendIndices(0, 2, 3);
+ quad.draw(painter, 0, 6);
+
+ painter->popSurface();
+
+ glEnable(GL_DEPTH_TEST);
+}
+
+QRect QAtlas::allocate(const QSize &size, const QImage &image, const QGL::IndexArray &indices)
+{
+ Q_ASSERT(QThread::currentThread() == qApp->thread());
+
+ QRect a = m_allocator->allocate(size);
+ if (a.isEmpty())
+ {
+ qWarning("QAtlas::allocate: overflowed");
+ return a;
+ }
+
+ m_allocationQueue.append(QAtlasEntry(image, a));
+ ++m_count;
+
+ QRectF af(a);
+ QSizeF szf(m_size);
+ float l = af.left() / szf.width();
+ float r = af.right() / szf.width();
+ float t = 1.0f - (af.top() / szf.height());
+ float b = 1.0f - (af.bottom() / szf.height());
+ m_geometry.texCoord(indices.at(0), QGL::TextureCoord1) = QVector2D(l, b);
+ m_geometry.texCoord(indices.at(1), QGL::TextureCoord1) = QVector2D(r, b);
+ m_geometry.texCoord(indices.at(2), QGL::TextureCoord1) = QVector2D(r, t);
+ m_geometry.texCoord(indices.at(5), QGL::TextureCoord1) = QVector2D(l, t);
+ return a;
+}
+
+void QAtlas::release(QRect frame)
+{
+ m_allocator->release(frame);
+}
+
+Q_GLOBAL_STATIC(QAtlas, atlasInstance);
+
+QAtlas *QAtlas::instance()
+{
+ return atlasInstance();
+}
diff --git a/demos/photobrowser3d/qatlas.h b/demos/photobrowser3d/qatlas.h
new file mode 100644
index 000000000..555b7e55c
--- /dev/null
+++ b/demos/photobrowser3d/qatlas.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QATLAS_H
+#define QATLAS_H
+
+#include <QSize>
+
+#include "qarray.h"
+#include "qgeometrydata.h"
+
+class QAreaAllocator;
+class QGLTexture2D;
+class QGLMaterial;
+class QGeometryData;
+class QGLFramebufferObject;
+class QGLFramebufferObjectSurface;
+
+struct QAtlasEntry
+{
+ QAtlasEntry(QImage i, QRect r) : image(i), rect(r) {}
+ QImage image;
+ QRect rect;
+};
+
+class QAtlas
+{
+public:
+ QAtlas();
+ ~QAtlas();
+
+ QAreaAllocator *allocator() const { return m_allocator; }
+ void setAllocator(QAreaAllocator *allocator) { m_allocator = allocator; }
+
+ QRect allocate(const QSize &size, const QImage &image, const QGL::IndexArray &indices);
+
+ void initialize(QGLPainter *painter);
+ void paint(QGLPainter *painter);
+
+ void release(QRect frame);
+
+ void setGeometry(QGeometryData geometry) { m_geometry = geometry; }
+ QGeometryData geometry() { return m_geometry; }
+
+ QGLMaterial *material() { return m_material; }
+
+ QList<QAtlasEntry> allocationQueue() const { return m_allocationQueue; }
+
+ static QAtlas *instance();
+
+private:
+ QSize m_size;
+ QGLFramebufferObject *m_data;
+ QGLFramebufferObjectSurface *m_renderTarget;
+ QAreaAllocator *m_allocator;
+ QGLTexture2D *m_tex;
+ QGLMaterial *m_material;
+ QGeometryData m_geometry;
+ bool m_initialized;
+ QList<QAtlasEntry> m_allocationQueue;
+ int m_count;
+};
+
+#endif // QATLAS_H
diff --git a/demos/photobrowser3d/qfocusadaptor.cpp b/demos/photobrowser3d/qfocusadaptor.cpp
new file mode 100644
index 000000000..cf96f3a01
--- /dev/null
+++ b/demos/photobrowser3d/qfocusadaptor.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfocusadaptor.h"
+#include "qglscenenode.h"
+#include "qglview.h"
+#include "qglcamera.h"
+#include "thumbnailnode.h"
+
+class QFocusAdaptorPrivate
+{
+public:
+ QFocusAdaptorPrivate()
+ : progress(0.0)
+ , reset(true)
+ , target(0)
+ , view(0)
+ {}
+ qreal progress;
+ QVector3D targetEye;
+ QVector3D targetCenter;
+ QVector3D sourceEye;
+ QVector3D sourceCenter;
+ bool reset;
+ QGLSceneNode *target;
+ QGLView *view;
+};
+
+QFocusAdaptor::QFocusAdaptor(QObject *parent)
+ : QObject(parent)
+ , d(new QFocusAdaptorPrivate)
+{
+ QGLView *v = qobject_cast<QGLView*>(parent);
+ if (v)
+ d->view = v;
+}
+
+QFocusAdaptor::~QFocusAdaptor()
+{
+ delete d;
+}
+
+qreal QFocusAdaptor::progress() const
+{
+ return d->progress;
+}
+
+void QFocusAdaptor::setProgress(qreal progress)
+{
+ if (d->progress != progress)
+ {
+ d->progress = progress;
+ calculateValues();
+ emit progressChanged();
+ }
+}
+
+QGLView *QFocusAdaptor::view() const
+{
+ return d->view;
+}
+
+void QFocusAdaptor::setView(QGLView *view)
+{
+ d->view = view;
+ d->reset = true;
+}
+
+QGLSceneNode *QFocusAdaptor::target() const
+{
+ return d->target;
+}
+
+void QFocusAdaptor::setTarget(QGLSceneNode *target)
+{
+ if (d->target != target)
+ {
+ d->target = target;
+ d->reset = true;
+ }
+}
+
+void QFocusAdaptor::calculateValues()
+{
+ if (d->target && d->view)
+ {
+ QGLCamera *cam = d->view->camera();
+ Q_ASSERT(cam);
+ if (d->reset)
+ {
+ QGeometryData data = d->target->geometry();
+ if (data.count() == 0 || d->target->count() == 0)
+ {
+ qWarning("Could not setup focus animation");
+ return;
+ }
+ // assume that the first triangle referenced by this node is the one
+ // you want to focus on - works for simple rects and like cases
+ QGL::IndexArray ixs = data.indices();
+ QVector3D a = data.vertexAt(ixs.at(d->target->start()));
+ QVector3D b = data.vertexAt(ixs.at(d->target->start() + 1));
+ QVector3D c = data.vertexAt(ixs.at(d->target->start() + 2));
+
+ // assumes that first triangle is facing the camera
+ QVector3D toCam = QVector3D::normal(a, b, c);
+
+ // wont work very well if the target is not axis-aligned
+ // find the distance q for the eye to be away from this object
+ // in order that it is a tight fit in the viewport
+ QGeometryData g = d->target->geometry();
+ QGL::IndexArray inxs = g.indices();
+ QBox3D box;
+ for (int i = d->target->start(); i < (d->target->start() + d->target->count()); ++i)
+ box.unite(g.vertexAt(inxs.at(i)));
+ QVector3D sz = box.size();
+
+ qreal nearDist = cam->nearPlane();
+
+ QSizeF v = cam->viewSize();
+
+ qreal vh = d->view->rect().height();
+ qreal vw = d->view->rect().width();
+ if (!qFuzzyIsNull(vw - vh))
+ {
+ qreal asp = vh / vw;
+ if (vh > vw)
+ v.setHeight(v.height() * asp);
+ else
+ v.setWidth(v.width() / asp);
+ }
+
+ qreal qh = (nearDist * sz.y()) / v.height();
+ qreal qw = (nearDist * sz.x()) / v.width();
+
+ qreal q = qMax(qh, qw);
+
+ d->sourceCenter = cam->center();
+ d->sourceEye = cam->eye();
+
+ d->targetCenter = d->target->position();
+ d->targetEye = d->targetCenter + (toCam * q);
+
+ d->reset = false;
+ }
+ cam->setCenter(d->sourceCenter + ((d->targetCenter - d->sourceCenter) * d->progress));
+ cam->setEye(d->sourceEye + ((d->targetEye - d->sourceEye) * d->progress));
+ }
+}
diff --git a/demos/photobrowser3d/qfocusadaptor.h b/demos/photobrowser3d/qfocusadaptor.h
new file mode 100644
index 000000000..a8307e74b
--- /dev/null
+++ b/demos/photobrowser3d/qfocusadaptor.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QFOCUSADAPTOR_H
+#define QFOCUSADAPTOR_H
+
+#include <QObject>
+
+class QGLView;
+class QGLSceneNode;
+class QFocusAdaptorPrivate;
+
+class QFocusAdaptor : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
+public:
+ explicit QFocusAdaptor(QObject *parent = 0);
+ ~QFocusAdaptor();
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ QGLView *view() const;
+ void setView(QGLView *view);
+
+ QGLSceneNode *target() const;
+ void setTarget(QGLSceneNode *target);
+
+signals:
+ void progressChanged();
+
+public slots:
+
+private:
+ void calculateValues();
+
+ QFocusAdaptorPrivate *d;
+};
+
+#endif // QFOCUSADAPTOR_H
diff --git a/demos/photobrowser3d/qphotobrowser3dscene.cpp b/demos/photobrowser3d/qphotobrowser3dscene.cpp
new file mode 100644
index 000000000..d1d70d6f4
--- /dev/null
+++ b/demos/photobrowser3d/qphotobrowser3dscene.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qphotobrowser3dscene.h"
+#include "qglscenenode.h"
+
+QPhotoBrowser3DScene::QPhotoBrowser3DScene(QObject *parent)
+ : QGLAbstractScene(parent)
+ , m_rootNode(new QGLSceneNode(this))
+{
+}
+
+QList<QObject *> QPhotoBrowser3DScene::objects() const
+{
+ QList<QGLSceneNode *> children = m_rootNode->allChildren();
+ QList<QObject *> objects;
+ for (int index = 0; index < children.size(); ++index)
+ objects.append(children.at(index));
+ return objects;
+}
diff --git a/demos/photobrowser3d/qphotobrowser3dscene.h b/demos/photobrowser3d/qphotobrowser3dscene.h
new file mode 100644
index 000000000..bc70265f3
--- /dev/null
+++ b/demos/photobrowser3d/qphotobrowser3dscene.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFRAMESSCENE_H
+#define QFRAMESSCENE_H
+
+#include "qglabstractscene.h"
+
+class QGLSceneNode;
+
+class QPhotoBrowser3DScene : public QGLAbstractScene
+{
+ Q_OBJECT
+public:
+ explicit QPhotoBrowser3DScene(QObject *parent = 0);
+ virtual QList<QObject *> objects() const;
+ QGLSceneNode *mainNode() const { return m_rootNode; }
+private:
+ QGLSceneNode *m_rootNode;
+};
+
+#endif // QFRAMESSCENE_H
diff --git a/demos/photobrowser3d/shaders/replace_texture.fsh b/demos/photobrowser3d/shaders/replace_texture.fsh
new file mode 100644
index 000000000..2c296dc78
--- /dev/null
+++ b/demos/photobrowser3d/shaders/replace_texture.fsh
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This is equivilent to GL_REPLACE
+varying highp vec4 qt_TexCoord0;
+uniform bool picking;
+uniform mediump vec4 color;
+uniform sampler2D texture;
+
+void main(void)
+{
+ if (picking)
+ gl_FragColor = color;
+ else
+ gl_FragColor = texture2D(texture, qt_TexCoord0.st);
+}
diff --git a/demos/photobrowser3d/shaders/replace_texture.vsh b/demos/photobrowser3d/shaders/replace_texture.vsh
new file mode 100644
index 000000000..57d43af28
--- /dev/null
+++ b/demos/photobrowser3d/shaders/replace_texture.vsh
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+attribute highp vec4 vertex;
+attribute highp vec4 texcoord;
+attribute highp vec4 thumbcoord;
+
+uniform highp mat4 matrix;
+uniform bool thumb;
+
+varying highp vec4 qt_TexCoord0;
+
+void main(void)
+{
+ if (thumb)
+ qt_TexCoord0 = thumbcoord;
+ else
+ qt_TexCoord0 = texcoord;
+ gl_Position = matrix * vertex;
+}
diff --git a/demos/photobrowser3d/skybox.cpp b/demos/photobrowser3d/skybox.cpp
new file mode 100644
index 000000000..f4d11fbfa
--- /dev/null
+++ b/demos/photobrowser3d/skybox.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "skybox.h"
+#include "qglbuilder.h"
+#include "qglcube.h"
+#include "qglpainter.h"
+#include "qglview.h"
+
+#include <QDir>
+#include <QFileInfo>
+
+SkyBox::SkyBox(QGLView *view, const QString &imagePath)
+ : m_scene(0)
+ , m_view(view)
+ , m_camera(new QGLCamera(this))
+{
+ m_camera->setEye(QVector3D());
+ m_camera->setNearPlane(0.3f);
+ m_camera->setViewSize(QSizeF(0.3f, 0.3f));
+
+ QGLBuilder builder;
+ builder.newSection(QGL::Faceted);
+ QVector3D blb(-1.0, -1.0, -1.0);
+ QVector3D blf(-1.0, -1.0, 1.0);
+ QVector3D tlf(-1.0, 1.0, 1.0);
+ QVector3D tlb(-1.0, 1.0, -1.0);
+ QVector3D brb(1.0, -1.0, -1.0);
+ QVector3D brf(1.0, -1.0, 1.0);
+ QVector3D trf(1.0, 1.0, 1.0);
+ QVector3D trb(1.0, 1.0, -1.0);
+ QVector2D bl(0.0f, 0.0f);
+ QVector2D br(1.0f, 0.0f);
+ QVector2D tr(1.0f, 1.0f);
+ QVector2D tl(0.0f, 1.0f);
+ {
+ QGeometryData q; // left
+ builder.currentNode()->setObjectName("left");
+ q.appendVertex(blf, blb, tlb, tlf);
+ q.appendTexCoord(bl, br, tr, tl);
+ builder.addQuads(q);
+ m_faces[0] = builder.currentNode();
+ m_faces[0]->setMaterial(new QGLMaterial);
+ }
+ {
+ builder.newNode(); // top
+ builder.currentNode()->setObjectName("top");
+ QGeometryData q;
+ q.appendVertex(trf, tlf, tlb, trb);
+ q.appendTexCoord(bl, br, tr, tl);
+ builder.addQuads(q);
+ m_faces[1] = builder.currentNode();
+ m_faces[1]->setMaterial(new QGLMaterial);
+ }
+ {
+ builder.newNode(); // right
+ builder.currentNode()->setObjectName("right");
+ QGeometryData q;
+ q.appendVertex(brb, brf, trf, trb);
+ q.appendTexCoord(bl, br, tr, tl);
+ builder.addQuads(q);
+ m_faces[2] = builder.currentNode();
+ m_faces[2]->setMaterial(new QGLMaterial);
+ }
+ {
+ builder.newNode(); // bottom
+ builder.currentNode()->setObjectName("bottom");
+ QGeometryData q;
+ q.appendVertex(brb, blb, blf, brf);
+ q.appendTexCoord(bl, br, tr, tl);
+ builder.addQuads(q);
+ m_faces[3] = builder.currentNode();
+ m_faces[3]->setMaterial(new QGLMaterial);
+ }
+ {
+ builder.newNode(); // front
+ builder.currentNode()->setObjectName("front");
+ QGeometryData q;
+ q.appendVertex(brf, blf, tlf, trf);
+ q.appendTexCoord(bl, br, tr, tl);
+ builder.addQuads(q);
+ m_faces[4] = builder.currentNode();
+ m_faces[4]->setMaterial(new QGLMaterial);
+ }
+ {
+ builder.newNode(); // back
+ builder.currentNode()->setObjectName("back");
+ QGeometryData q;
+ q.appendVertex(blb, brb, trb, tlb);
+ q.appendTexCoord(bl, br, tr, tl);
+ builder.addQuads(q);
+ m_faces[5] = builder.currentNode();
+ m_faces[5]->setMaterial(new QGLMaterial);
+ }
+ m_scene = builder.finalizedSceneNode();
+ m_scene->setObjectName("SkyboxList");
+ m_scene->setEffect(QGL::FlatReplaceTexture2D);
+ m_scene->setEffectEnabled(true);
+ m_scene->setParent(this);
+
+ QString resourceBase = QLatin1String(":/");
+ setImagePath(imagePath.isEmpty() ? resourceBase : imagePath);
+}
+
+
+void SkyBox::setImagePath(const QString &imagePath)
+{
+ static QStringList expected2;
+ static QStringList expected;
+
+ if (expected.isEmpty())
+ expected << QLatin1String("east") << QLatin1String("up") << QLatin1String("west")
+ << QLatin1String("down") << QLatin1String("south") << QLatin1String("north");
+ if (expected2.isEmpty())
+ expected2 << QLatin1String("right") << QLatin1String("top") << QLatin1String("left")
+ << QLatin1String("bottom") << QLatin1String("front") << QLatin1String("back");
+ if (imagePath != m_imagePath)
+ {
+ m_imagePath = imagePath;
+ QStringList notFound = expected;
+ QFileInfo info(m_imagePath);
+ if (info.exists() && info.isDir())
+ {
+ QDir imDir(imagePath);
+ QFileInfoList files = imDir.entryInfoList(QDir::Files);
+ QFileInfoList::const_iterator it = files.constBegin();
+ for ( ; it != files.constEnd() && notFound.size() > 0; ++it)
+ {
+ QFileInfo ent = *it;
+ QString tok = ent.baseName().toLower();
+ int ix = 0;
+ for ( ; ix < 6; ++ix)
+ if (tok.contains(expected.at(ix)))
+ break;
+ if (ix == 6)
+ {
+ ix = 0;
+ for ( ; ix < 6; ++ix)
+ if (tok.contains(expected2.at(ix)))
+ break;
+ }
+ if (ix != 6)
+ {
+ notFound.removeOne(expected.at(ix));
+ QUrl url;
+ url.setScheme("file");
+ url.setPath(ent.absoluteFilePath());
+ m_faces[ix]->material()->setTextureUrl(url);
+ m_faces[ix]->material()->texture()->setHorizontalWrap(QGL::ClampToEdge);
+ m_faces[ix]->material()->texture()->setVerticalWrap(QGL::ClampToEdge);
+ }
+ }
+ if (notFound.size() > 2)
+ {
+ qWarning("Could not load textures for");
+ for (int i = 0; i < notFound.size(); ++i)
+ qWarning("\t%s", qPrintable(notFound.at(i)));
+ }
+ }
+ else
+ {
+ qWarning("SkyBox::setImagePath: Not an existing directory %s",
+ qPrintable(m_imagePath));
+ }
+ }
+}
+
+void SkyBox::draw(QGLPainter *painter) const
+{
+ painter->modelViewMatrix().push();
+ painter->modelViewMatrix().setToIdentity();
+
+ QGLCamera *cam = m_view->camera();
+ m_camera->setCenter(-cam->eye());
+ painter->setCamera(m_camera);
+
+ glDisable(GL_DEPTH_TEST);
+
+ m_scene->draw(painter);
+
+ glEnable(GL_DEPTH_TEST);
+
+ painter->setCamera(cam);
+ painter->modelViewMatrix().pop();
+}
diff --git a/demos/photobrowser3d/skybox.h b/demos/photobrowser3d/skybox.h
new file mode 100644
index 000000000..26ce9c26a
--- /dev/null
+++ b/demos/photobrowser3d/skybox.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SKYBOX_H
+#define SKYBOX_H
+
+#include <QString>
+#include <QObject>
+
+class QGLBuilder;
+class QGLSceneNode;
+class QGLPainter;
+class QGLView;
+class QGLCamera;
+
+class SkyBox : public QObject
+{
+ Q_OBJECT
+public:
+ SkyBox(QGLView *view, const QString &imagePath = QString());
+ QString imagePath() const { return m_imagePath; }
+ void setImagePath(const QString &imagePath);
+ void draw(QGLPainter *painter) const;
+private:
+ QGLSceneNode *m_scene;
+ QString m_imagePath;
+ QGLSceneNode *m_faces[6];
+ QGLView *m_view;
+ QGLCamera *m_camera;
+};
+
+#endif // SKYBOX_H
diff --git a/demos/photobrowser3d/threadpool.cpp b/demos/photobrowser3d/threadpool.cpp
new file mode 100644
index 000000000..a14a82690
--- /dev/null
+++ b/demos/photobrowser3d/threadpool.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "threadpool.h"
+#include "imageloader.h"
+#include "imagemanager.h"
+
+#include <QSemaphore>
+
+ThreadPool::ThreadPool()
+{
+ m_threadPoolSize = QThread::idealThreadCount();
+ if (m_threadPoolSize < 2)
+ m_threadPoolSize = 2;
+ m_stop = 0;
+}
+
+ThreadPool::~ThreadPool()
+{
+ Q_ASSERT(m_allWorkers.size() == 0);
+}
+
+void ThreadPool::deployLoader(const ThumbnailableImage &image)
+{
+ // INVARIANT: this critical section is only ever executed from its
+ // own thread via queued signals - thus access to it is serialized
+ Q_ASSERT(QThread::currentThread() == thread());
+
+ if (m_stop)
+ return;
+
+ ImageManager *manager = qobject_cast<ImageManager*>(sender());
+ Q_ASSERT(manager);
+
+ ImageLoader *loader = 0;
+ if (m_freeWorkers.size() > 0)
+ loader = m_freeWorkers.takeFirst();
+
+ if (loader)
+ {
+ loader->setImage(image);
+ }
+ else
+ {
+ if (m_allWorkers.size() < m_threadPoolSize)
+ {
+ loader = new ImageLoader;
+ m_allWorkers.append(loader);
+ loader->setImage(image);
+ connect(loader, SIGNAL(imageLoaded(ThumbnailableImage)), manager,
+ SIGNAL(imageReady(ThumbnailableImage)));
+ connect(loader, SIGNAL(imageLoaded(ThumbnailableImage)), this,
+ SLOT(retrieveLoader()));
+ connect(loader, SIGNAL(finished()), this, SLOT(closeLoader()));
+ connect(this, SIGNAL(stopAll()), loader, SLOT(stop()));
+ loader->start();
+ }
+ else
+ {
+ m_workList.append(image);
+ }
+ }
+}
+
+void ThreadPool::retrieveLoader()
+{
+ ImageLoader *loader = qobject_cast<ImageLoader*>(sender());
+ Q_ASSERT(loader);
+ if (!m_stop)
+ {
+ if (!m_workList.isEmpty())
+ loader->setImage(m_workList.takeFirst());
+ else
+ m_freeWorkers.append(loader);
+ }
+}
+
+void ThreadPool::stop()
+{
+ m_stop.ref();
+ emit stopAll();
+}
+
+void ThreadPool::closeLoader()
+{
+ ImageLoader *loader = qobject_cast<ImageLoader*>(sender());
+ Q_ASSERT(loader);
+ m_allWorkers.removeOne(loader);
+ loader->deleteLater();
+ if (m_allWorkers.isEmpty() && m_stop)
+ {
+ emit stopped();
+ }
+}
diff --git a/demos/photobrowser3d/threadpool.h b/demos/photobrowser3d/threadpool.h
new file mode 100644
index 000000000..6d52d2503
--- /dev/null
+++ b/demos/photobrowser3d/threadpool.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LOADINGJOB_H
+#define LOADINGJOB_H
+
+#include <QObject>
+#include <QAtomicInt>
+#include <QList>
+#include <QUrl>
+
+#include "thumbnailableimage.h"
+
+class ImageLoader;
+
+class ThreadPool : public QObject
+{
+ Q_OBJECT
+public:
+ ThreadPool();
+ ~ThreadPool();
+
+signals:
+ void stopped();
+ void stopAll();
+
+public slots:
+ void deployLoader(const ThumbnailableImage &url);
+ void stop();
+
+private slots:
+ void retrieveLoader();
+ void closeLoader();
+
+private:
+ QList<ImageLoader*> m_freeWorkers;
+ QList<ImageLoader*> m_allWorkers;
+ QList<ThumbnailableImage> m_workList;
+ QAtomicInt m_stop;
+ int m_threadPoolSize;
+};
+
+#endif // LOADINGJOB_H
diff --git a/demos/photobrowser3d/thumbnailableimage.cpp b/demos/photobrowser3d/thumbnailableimage.cpp
new file mode 100644
index 000000000..95e842e0f
--- /dev/null
+++ b/demos/photobrowser3d/thumbnailableimage.cpp
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "thumbnailableimage.h"
+#include "qareaallocator.h"
+#include "qgltexture2d.h"
+#include "qglmaterial.h"
+#include "qatlas.h"
+
+#include <QUrl>
+
+class ThumbnailableImagePrivate
+{
+public:
+ ThumbnailableImagePrivate();
+ ~ThumbnailableImagePrivate();
+
+ ThumbnailableImagePrivate *clone() const
+ {
+ ThumbnailableImagePrivate *temp = new ThumbnailableImagePrivate;
+ temp->thumbnailed = thumbnailed;
+ temp->pending = pending;
+ temp->url = url;
+ temp->data = data;
+ temp->tex = tex;
+ temp->mat = mat;
+ temp->frame = frame;
+ temp->scale = scale;
+ temp->indices = indices;
+ return temp;
+ }
+
+ QBasicAtomicInt ref;
+
+ bool thumbnailed;
+ bool pending;
+ QUrl url;
+ QImage data;
+ QGLTexture2D *tex;
+ QGLMaterial *mat;
+ QRect frame;
+ qreal scale;
+ QGL::IndexArray indices;
+};
+
+ThumbnailableImagePrivate::ThumbnailableImagePrivate()
+ : thumbnailed(false)
+ , pending(false)
+ , tex(0)
+ , mat(0)
+ , scale(15.0f)
+{
+ ref = 0;
+}
+
+ThumbnailableImagePrivate::~ThumbnailableImagePrivate()
+{
+}
+
+ThumbnailableImage::ThumbnailableImage()
+ : d(0)
+{
+}
+
+/*!
+ Construct ThumbnailableImage as a copy of \a other
+*/
+ThumbnailableImage::ThumbnailableImage(const ThumbnailableImage &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Destroys this ThumbnailableImage recovering any resources.
+*/
+ThumbnailableImage::~ThumbnailableImage()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Assigns this ThumbnailableImage to be a copy of \a other.
+*/
+ThumbnailableImage &ThumbnailableImage::operator=(const ThumbnailableImage &other)
+{
+ if (d != other.d)
+ {
+ if (d && !d->ref.deref())
+ delete d;
+ d = other.d;
+ if (d)
+ d->ref.ref();
+ }
+ return *this;
+}
+
+void ThumbnailableImage::setThumbnailed(bool enable)
+{
+ detach();
+ if (enable != d->thumbnailed && !d->data.isNull())
+ {
+ if (enable)
+ {
+ if (d->frame.isNull())
+ {
+ Q_ASSERT(!d->data.isNull());
+ QSize sz = (QSizeF(d->data.size()) / d->scale).toSize();
+ QAtlas *atlas = QAtlas::instance();
+ d->frame = atlas->allocate(sz, d->data, d->indices);
+ d->pending = true;
+ }
+ }
+ if (!d->pending)
+ d->thumbnailed = enable;
+ }
+}
+
+bool ThumbnailableImage::isThumbnailed() const
+{
+ bool result = false;
+ if (d)
+ {
+ if (d->pending)
+ {
+ QList<QAtlasEntry> queue = QAtlas::instance()->allocationQueue();
+ int i = 0;
+ for ( ; i < queue.count(); ++i)
+ if (d->frame == queue.at(i).rect)
+ break;
+ if (i == queue.count())
+ {
+ d->pending = false;
+ d->thumbnailed = true;
+ }
+ }
+ result = d->thumbnailed;
+ }
+ return result;
+}
+
+QImage ThumbnailableImage::data() const
+{
+ QImage result;
+ if (d)
+ result = d->data;
+ return result;
+}
+
+void ThumbnailableImage::setData(QImage data)
+{
+ detach();
+ d->data = data;
+}
+
+QUrl ThumbnailableImage::url() const
+{
+ QUrl result;
+ if (d)
+ result = d->url;
+ return result;
+}
+
+void ThumbnailableImage::setUrl(const QUrl &url)
+{
+ detach();
+ d->url = url;
+}
+
+QRectF ThumbnailableImage::frame() const
+{
+ QRectF result;
+ if (d)
+ result = d->frame;
+ return result;
+}
+
+qreal ThumbnailableImage::scale() const
+{
+ qreal result = 0.0f;
+ if (d)
+ result = d->scale;
+ return result;
+}
+
+void ThumbnailableImage::minimize()
+{
+ if (!d)
+ return;
+ detach();
+ if (!isMinimized())
+ {
+ if (d->thumbnailed)
+ {
+ // If thumbnailed, I don't really need the full size image
+ d->data = QImage();
+ }
+ else
+ {
+ // If not thumbnailed, I don't need the atlas resources
+ QAtlas *atlas = QAtlas::instance();
+ atlas->release(d->frame);
+ d->frame = QRect();
+ }
+ }
+}
+
+bool ThumbnailableImage::isMinimized() const
+{
+ bool result = true;
+ if (d)
+ result = (d->thumbnailed) ? (d->data.isNull()) : (d->frame.isNull());
+ return result;
+}
+
+void ThumbnailableImage::setIndices(const QGL::IndexArray &indices)
+{
+ detach();
+ d->indices = indices;
+}
+
+QGL::IndexArray ThumbnailableImage::indices() const
+{
+ QGL::IndexArray result;
+ if (d)
+ result = d->indices;
+ return result;
+}
+
+/*!
+ \internal
+ You know what this is for. No user serviceable parts below here.
+*/
+void ThumbnailableImage::detach()
+{
+ if (!d) // lazy creation of data block
+ {
+ d = new ThumbnailableImagePrivate;
+ d->ref.ref();
+ }
+ else
+ {
+ if (d->ref > 1) // being shared, must detach
+ {
+ ThumbnailableImagePrivate *temp = d->clone();
+ d->ref.deref();
+ d = temp;
+ d->ref.ref();
+ }
+ }
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const ThumbnailableImage &image)
+{
+ dbg << "ThumbnailableImage" << image.url() << "size:" << image.data().size() <<
+ "minimized:" << image.isMinimized() << "-- thumbnailed:" << image.isThumbnailed()
+ << "-- null:" << image.isNull() << "-- image loaded:" << (!image.data().isNull())
+ << "-- index count:" << image.indices().count();
+ return dbg;
+}
+#endif
diff --git a/demos/photobrowser3d/thumbnailableimage.h b/demos/photobrowser3d/thumbnailableimage.h
new file mode 100644
index 000000000..06d940e92
--- /dev/null
+++ b/demos/photobrowser3d/thumbnailableimage.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef THUMBNAILABLEIMAGE_H
+#define THUMBNAILABLEIMAGE_H
+
+#include <QRectF>
+#include <QMetaType>
+
+#include "qarray.h"
+#include "qgeometrydata.h"
+
+class QImage;
+class ThumbnailableImagePrivate;
+class QGLPainter;
+
+class ThumbnailableImage
+{
+public:
+ ThumbnailableImage();
+ ThumbnailableImage(const ThumbnailableImage&);
+ ~ThumbnailableImage();
+
+ ThumbnailableImage &operator=(const ThumbnailableImage &);
+
+ void setThumbnailed(bool enable);
+ bool isThumbnailed() const;
+
+ QImage data() const;
+ void setData(QImage data);
+
+ QUrl url() const;
+ void setUrl(const QUrl &url);
+
+ QRectF frame() const;
+ qreal scale() const;
+
+ void minimize();
+ bool isMinimized() const;
+
+ QGL::IndexArray indices() const;
+ void setIndices(const QGL::IndexArray &indices);
+
+ bool isNull() const { return d == 0; }
+
+ ThumbnailableImagePrivate *priv() const { return d; } /// debug = remove me
+
+private:
+ void detach();
+
+ ThumbnailableImagePrivate *d;
+};
+
+Q_DECLARE_METATYPE(ThumbnailableImage);
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const ThumbnailableImage &image);
+#endif
+
+#endif // THUMBNAILABLEIMAGE_H
diff --git a/demos/photobrowser3d/thumbnaileffect.cpp b/demos/photobrowser3d/thumbnaileffect.cpp
new file mode 100644
index 000000000..9a98b7427
--- /dev/null
+++ b/demos/photobrowser3d/thumbnaileffect.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "thumbnaileffect.h"
+
+#include <QtOpenGL/qglshaderprogram.h>
+
+class ThumbnailEffectPrivate
+{
+public:
+ ThumbnailEffectPrivate()
+ : program(0)
+ , matrixUniform(-1)
+ , thumbnailUniform(-1)
+ , thumbnail(false)
+ , thumbnailUpdateRequired(false)
+ {
+ }
+ ~ThumbnailEffectPrivate() { delete program; }
+
+ QGLShaderProgram *program;
+ int matrixUniform;
+ int thumbnailUniform;
+ int colorUniform;
+ int pickingUniform;
+ // true if we render a thumbnail, false do the large size
+ bool thumbnail;
+ bool thumbnailUpdateRequired;
+};
+
+/*!
+ Constructs a new flat texture effect.
+*/
+ThumbnailEffect::ThumbnailEffect()
+ : d(new ThumbnailEffectPrivate)
+{
+}
+
+/*!
+ Destroys this flat texture effect.
+*/
+ThumbnailEffect::~ThumbnailEffect()
+{
+ delete d;
+}
+
+/*!
+ \reimp
+*/
+QList<QGL::VertexAttribute> ThumbnailEffect::requiredFields() const
+{
+ QList<QGL::VertexAttribute> fields;
+ fields += QGL::Position;
+ fields += QGL::TextureCoord0;
+ fields += QGL::TextureCoord1;
+ return fields;
+}
+
+/*!
+ \reimp
+*/
+void ThumbnailEffect::setActive(QGLPainter *painter, bool flag)
+{
+ Q_UNUSED(painter);
+ if (!d->program) {
+ if (!flag)
+ return;
+ d->program = new QGLShaderProgram();
+ d->program->addShaderFromSourceFile(QGLShader::Vertex, ":/shaders/replace_texture.vsh");
+ d->program->addShaderFromSourceFile(QGLShader::Fragment, ":/shaders/replace_texture.fsh");
+ d->program->bindAttributeLocation("vertex", QGL::Position);
+ d->program->bindAttributeLocation("texcoord", QGL::TextureCoord0);
+ d->program->bindAttributeLocation("thumbcoord", QGL::TextureCoord1);
+ if (!d->program->link()) {
+ qWarning("ThumbnailEffect::setActive(): could not link shader d->program");
+ delete d->program;
+ d->program = 0;
+ return;
+ }
+ d->matrixUniform = d->program->uniformLocation("matrix");
+ d->thumbnailUniform = d->program->uniformLocation("thumb");
+ d->colorUniform = d->program->uniformLocation("color");
+ d->pickingUniform = d->program->uniformLocation("picking");
+ d->program->bind();
+ d->program->setUniformValue("texture", 0);
+ d->program->enableAttributeArray(QGL::Position);
+ d->program->enableAttributeArray(QGL::TextureCoord0);
+ d->program->enableAttributeArray(QGL::TextureCoord1);
+ } else if (flag) {
+ d->matrixUniform = d->program->uniformLocation("matrix");
+ d->program->bind();
+ d->program->setUniformValue("texture", 0);
+ d->program->enableAttributeArray(QGL::Position);
+ d->program->enableAttributeArray(QGL::TextureCoord0);
+ d->program->enableAttributeArray(QGL::TextureCoord1);
+ } else {
+ d->program->disableAttributeArray(QGL::Position);
+ d->program->disableAttributeArray(QGL::TextureCoord0);
+ d->program->disableAttributeArray(QGL::TextureCoord1);
+ d->program->release();
+ }
+}
+
+/*!
+ \reimp
+*/
+void ThumbnailEffect::update
+ (QGLPainter *painter, QGLPainter::Updates updates)
+{
+ Q_ASSERT(d->program);
+ if ((updates & QGLPainter::UpdateMatrices) != 0)
+ {
+ d->program->setUniformValue(d->matrixUniform,
+ painter->combinedMatrix());
+ }
+ if ((updates & QGLPainter::UpdateColor) != 0) {
+ d->program->setUniformValue(d->pickingUniform, painter->isPicking());
+ if (painter->isPicking())
+ d->program->setUniformValue(d->colorUniform, painter->pickColor());
+ else
+ d->program->setUniformValue(d->colorUniform, Qt::green);
+ }
+ if (d->thumbnailUpdateRequired)
+ {
+ d->program->setUniformValue(d->thumbnailUniform, d->thumbnail);
+ d->thumbnailUpdateRequired = false;
+ }
+}
+
+bool ThumbnailEffect::supportsPicking() const
+{
+ return true;
+}
+
+
+void ThumbnailEffect::setThumbnail(bool enable)
+{
+ if (d->thumbnail != enable)
+ {
+ d->thumbnailUpdateRequired = true;
+ d->thumbnail = enable;
+ }
+}
+
+bool ThumbnailEffect::thumbnail() const
+{
+ return d->thumbnail;
+}
diff --git a/demos/photobrowser3d/thumbnaileffect.h b/demos/photobrowser3d/thumbnaileffect.h
new file mode 100644
index 000000000..330e7d04d
--- /dev/null
+++ b/demos/photobrowser3d/thumbnaileffect.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLFLATTEXTUREEFFECT_H
+#define QGLFLATTEXTUREEFFECT_H
+
+#include "qglabstracteffect.h"
+#include <QtCore/qscopedpointer.h>
+
+class ThumbnailEffectPrivate;
+
+class ThumbnailEffect : public QGLAbstractEffect
+{
+public:
+ ThumbnailEffect();
+ virtual ~ThumbnailEffect();
+
+ QList<QGL::VertexAttribute> requiredFields() const;
+ void setActive(QGLPainter *painter, bool flag);
+ void update(QGLPainter *painter, QGLPainter::Updates updates);
+ bool supportsPicking() const;
+
+ void setThumbnail(bool enable);
+ bool thumbnail() const;
+
+ QString name() const { return QLatin1String("ThumbnailEffect"); }
+
+private:
+ ThumbnailEffectPrivate *d;
+};
+
+#endif
diff --git a/demos/photobrowser3d/thumbnailnode.cpp b/demos/photobrowser3d/thumbnailnode.cpp
new file mode 100644
index 000000000..78ad38d44
--- /dev/null
+++ b/demos/photobrowser3d/thumbnailnode.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "thumbnailnode.h"
+#include "qglpainter.h"
+#include "thumbnaileffect.h"
+#include "imagemanager.h"
+#include "qatlas.h"
+#include "qglrendersequencer.h"
+#include "qglpicknode.h"
+#include "qlogicalvertex.h"
+
+#include <QMatrix4x4>
+#include <QTimer>
+
+ThumbnailNode::ThumbnailNode(QObject *parent)
+ : QGLSceneNode(parent)
+ , m_thresholdSquared(20.0f * 20.0f)
+ , m_defaultMaterial(-1)
+ , m_loading(false)
+ , m_full(0)
+ , m_manager(0)
+ , m_lastDistance(ThumbnailNode::Unknown)
+{
+ setPalette(new QGLMaterialCollection(this));
+}
+
+ThumbnailNode::~ThumbnailNode()
+{
+ delete m_full;
+}
+
+void ThumbnailNode::setUrl(const QUrl &url)
+{
+ m_url = url;
+ m_image = ThumbnailableImage();
+ m_image.setUrl(m_url);
+ QGL::IndexArray inxs = geometry().indices();
+ m_image.setIndices(inxs.mid(start(), count()));
+}
+
+void ThumbnailNode::setupLoading()
+{
+ if (!m_loading && !m_url.isEmpty() && m_image.data().isNull())
+ {
+ m_loading = true;
+#ifdef QT_NO_THREADED_FILE_LOAD
+ ThumbnailableImage image;
+ image.setUrl(m_url);
+ QImage im(m_url.toLocalFile());
+ if (im.isNull())
+ qDebug() << "ThumbnailNode::setupLoading: could not load image:"
+ << m_url.toLocalFile();
+ if (im.size().width() > 1024 || im.size().height() > 768)
+ im = im.scaled(QSize(1024, 768), Qt::KeepAspectRatio,
+ Qt::SmoothTransformation);
+ image.setData(im);
+ setImage(image);
+#else
+ if (m_manager)
+ // reconnect the signal we disconnnected in setImage() below
+ connect(m_manager, SIGNAL(imageReady(ThumbnailableImage)),
+ this, SLOT(setImage(ThumbnailableImage)));
+ emit imageRequired(m_image);
+ setMaterialIndex(m_defaultMaterial);
+#endif
+ }
+}
+
+void ThumbnailNode::createFullNode()
+{
+ m_full = new QGLSceneNode;
+ m_full->setPosition(position());
+ m_full->setGeometry(geometry());
+ m_full->setStart(start());
+ m_full->setCount(count());
+ m_full->setPalette(palette());
+ m_full->setMaterialIndex(m_defaultMaterial);
+}
+
+void ThumbnailNode::destroyFullNode()
+{
+ if (!m_full)
+ return;
+ QGLMaterial *mat = m_full->material();
+ if (m_full->materialIndex() != m_defaultMaterial)
+ m_full->palette()->removeMaterial(mat);
+ delete m_full;
+ m_full = 0;
+}
+
+void ThumbnailNode::loadFullImage()
+{
+ if (!m_full)
+ createFullNode();
+ Q_CHECK_PTR(m_full);
+ // if we have a valid image, and the full node still has the
+ // default material, switch to a new material which displays
+ // the full size image
+ if (!m_image.data().isNull() &&
+ m_full->materialIndex() == m_defaultMaterial)
+ {
+ QGLMaterial *mat = new QGLMaterial;
+ QGLTexture2D *tex = new QGLTexture2D;
+ tex->setImage(m_image.data());
+ mat->setTexture(tex);
+ mat->setObjectName(m_image.url().path());
+ int ix = palette()->addMaterial(mat);
+ m_full->setMaterialIndex(ix);
+ mat->setParent(m_full);
+ }
+}
+
+void ThumbnailNode::drawGeometry(QGLPainter *painter)
+{
+ QGLSceneNode::drawGeometry(painter);
+}
+
+void ThumbnailNode::draw(QGLPainter *painter)
+{
+ QGLSceneNode *p = qobject_cast<QGLSceneNode*>(parent());
+ Q_ASSERT_X(p && p->userEffect() && (!hasEffect()),
+ "ThumbnailNode::draw", "Should only inherit parents ThumbnailEffect");
+
+ ThumbnailEffect *effect = static_cast<ThumbnailEffect*>(p->userEffect());
+ Q_ASSERT_X(effect && effect->name() == QLatin1String("ThumbnailEffect"),
+ "ThumbnailNode::draw", "Can only be drawn with custom ThumbnailEffect");
+
+ if (m_defaultMaterial == -1)
+ m_defaultMaterial = materialIndex();
+
+ QMatrix4x4 m = painter->modelViewMatrix().top();
+ QVector3D pos = m.map(position());
+ qreal magSquared = pos.lengthSquared();
+
+ Distance distance = Unknown;
+
+ if (magSquared > (4.0f * m_thresholdSquared))
+ distance = VeryFar;
+ else if (magSquared > (2.0f * m_thresholdSquared))
+ distance = Far;
+ else if (magSquared > m_thresholdSquared)
+ distance = Middle;
+ else
+ distance = Near;
+
+ if (true) // distance != m_lastDistance)
+ {
+ m_lastDistance = distance;
+ m_image.setThumbnailed(m_lastDistance > Near);
+ switch (distance)
+ {
+ case Unknown:
+ case Near:
+ setupLoading();
+ loadFullImage();
+ break;
+ case Middle:
+ setupLoading();
+ loadFullImage();
+ break;
+ case Far:
+ setupLoading();
+ break;
+ case VeryFar:
+ destroyFullNode();
+ break;
+ }
+ }
+
+ effect->setThumbnail(m_image.isThumbnailed());
+ if (m_image.isThumbnailed() || !m_full)
+ {
+ QGLSceneNode::draw(painter);
+ }
+ else
+ {
+ if (m_image.data().isNull())
+ m_full->setMaterialIndex(m_defaultMaterial);
+ if (pickNode() && painter->isPicking())
+ painter->setObjectPickId(pickNode()->id());
+ m_full->draw(painter);
+ }
+
+}
+
+void ThumbnailNode::setImage(const ThumbnailableImage &image)
+{
+ Q_ASSERT(QThread::currentThread() == thread());
+ Q_ASSERT(!image.isNull());
+
+ // the manager will be (potentially) loading a number of images, but
+ // we only want our one, so just check this is our order
+ if (m_url != image.url())
+ return;
+
+ // ok we got the right one, stop listening to the manager
+ if (sender())
+ {
+ m_manager = sender();
+ m_manager->disconnect(this, SLOT(setImage(ThumbnailableImage)));
+ }
+
+ // ok maybe we got what we asked for but in the meantime we decided
+ // we did not want it anymore
+ if (!m_loading)
+ return;
+
+ // the indices we are about to set will index this thumbnail image
+ // into the image that its atlas is based on via the texture coords
+ // that the atlas is using - those texture coords must be in the
+ // same geometry that this node is referencing, so that they will
+ // arrive at the vertex shader at the same time - ie they are all
+ // matched in the data arrays in the geometry object
+ //Q_ASSERT(QAtlas::instance()->geometry() == geometry());
+
+ m_image = image;
+ Q_ASSERT(!m_image.data().isNull());
+
+ // configure the placeholder for the actual image size
+ // this makes a photo of 1024 x 768 display on approx 3.0 x 2.8 pane
+ // add salt to taste
+ //QSizeF f = QSizeF(m_image.data().size()) / 600.0f;
+ QSizeF f = QSizeF(m_image.data().size());
+ f.scale(1.6, 1.2, Qt::KeepAspectRatio);
+ QVector3D a(-f.width(), -f.height(), 0.0f);
+ QVector3D b(f.width(), -f.height(), 0.0f);
+ QVector3D c(f.width(), f.height(), 0.0f);
+ QVector3D d(-f.width(), f.height(), 0.0f);
+ int k = start();
+ Q_ASSERT(count() == 6);
+ QGeometryData g = geometry();
+ QGL::IndexArray inxs = g.indices();
+ g.vertex(inxs.at(k)) = a;
+ g.vertex(inxs.at(k+1)) = b;
+ g.vertex(inxs.at(k+2)) = c;
+ g.vertex(inxs.at(k+5)) = d;
+
+ setMaterialIndex(-1);
+ m_loading = false;
+
+ emit nodeChanged();
+}
diff --git a/demos/photobrowser3d/thumbnailnode.h b/demos/photobrowser3d/thumbnailnode.h
new file mode 100644
index 000000000..467c05517
--- /dev/null
+++ b/demos/photobrowser3d/thumbnailnode.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtQuick3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef THUMBNAILNODE_H
+#define THUMBNAILNODE_H
+
+#include "qglscenenode.h"
+#include "thumbnailableimage.h"
+
+#include <QtCore/qmath.h>
+#include <QUrl>
+
+class ThumbnailNode : public QGLSceneNode
+{
+ Q_OBJECT
+public:
+ enum Distance
+ {
+ Unknown,
+ Near,
+ Middle,
+ Far,
+ VeryFar
+ };
+
+ explicit ThumbnailNode(QObject *parent = 0);
+ ~ThumbnailNode();
+ QUrl url() const { return m_url; }
+ void setUrl(const QUrl &url);
+ void setThreshold(qreal threshold) { m_thresholdSquared = threshold * threshold; }
+ qreal threshold() const { return qSqrt(m_thresholdSquared); }
+ void draw(QGLPainter *painter);
+ void drawGeometry(QGLPainter *painter);
+ ThumbnailableImage image() const { return m_image; }
+signals:
+ void imageRequired(const ThumbnailableImage &);
+ void nodeChanged();
+public slots:
+ void setImage(const ThumbnailableImage &image);
+private:
+ void createFullNode();
+ void destroyFullNode();
+ void setupLoading();
+ void setupThumbnailing();
+ void loadFullImage();
+
+ ThumbnailableImage m_image;
+ qreal m_thresholdSquared;
+ int m_defaultMaterial;
+ QUrl m_url;
+ bool m_loading;
+ QGLSceneNode *m_full;
+ QSizeF m_max;
+ QObject *m_manager;
+ Distance m_lastDistance;
+};
+
+#endif // THUMBNAILNODE_H