diff options
Diffstat (limited to 'demos/photobrowser3d')
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 Binary files differnew file mode 100644 index 000000000..48edfbc2d --- /dev/null +++ b/demos/photobrowser3d/images/P1000223.JPG diff --git a/demos/photobrowser3d/images/P1000228.JPG b/demos/photobrowser3d/images/P1000228.JPG Binary files differnew file mode 100644 index 000000000..2797b6df5 --- /dev/null +++ b/demos/photobrowser3d/images/P1000228.JPG diff --git a/demos/photobrowser3d/images/P1000441.JPG b/demos/photobrowser3d/images/P1000441.JPG Binary files differnew file mode 100644 index 000000000..b4037b49e --- /dev/null +++ b/demos/photobrowser3d/images/P1000441.JPG diff --git a/demos/photobrowser3d/images/P1000472.JPG b/demos/photobrowser3d/images/P1000472.JPG Binary files differnew file mode 100644 index 000000000..067afdd4a --- /dev/null +++ b/demos/photobrowser3d/images/P1000472.JPG diff --git a/demos/photobrowser3d/images/arrows-left.png b/demos/photobrowser3d/images/arrows-left.png Binary files differnew file mode 100644 index 000000000..791f2c6b1 --- /dev/null +++ b/demos/photobrowser3d/images/arrows-left.png diff --git a/demos/photobrowser3d/images/arrows.xcf b/demos/photobrowser3d/images/arrows.xcf Binary files differnew file mode 100644 index 000000000..302bcd6eb --- /dev/null +++ b/demos/photobrowser3d/images/arrows.xcf diff --git a/demos/photobrowser3d/images/default_sky_base.xcf b/demos/photobrowser3d/images/default_sky_base.xcf Binary files differnew file mode 100644 index 000000000..050812f7d --- /dev/null +++ b/demos/photobrowser3d/images/default_sky_base.xcf diff --git a/demos/photobrowser3d/images/default_sky_down.png b/demos/photobrowser3d/images/default_sky_down.png Binary files differnew file mode 100644 index 000000000..531ba75e9 --- /dev/null +++ b/demos/photobrowser3d/images/default_sky_down.png diff --git a/demos/photobrowser3d/images/default_sky_east.png b/demos/photobrowser3d/images/default_sky_east.png Binary files differnew file mode 100644 index 000000000..09bfc3ad5 --- /dev/null +++ b/demos/photobrowser3d/images/default_sky_east.png diff --git a/demos/photobrowser3d/images/default_sky_north.png b/demos/photobrowser3d/images/default_sky_north.png Binary files differnew file mode 100644 index 000000000..b97aaa20a --- /dev/null +++ b/demos/photobrowser3d/images/default_sky_north.png diff --git a/demos/photobrowser3d/images/default_sky_south.png b/demos/photobrowser3d/images/default_sky_south.png Binary files differnew file mode 100644 index 000000000..28db27816 --- /dev/null +++ b/demos/photobrowser3d/images/default_sky_south.png diff --git a/demos/photobrowser3d/images/default_sky_up.png b/demos/photobrowser3d/images/default_sky_up.png Binary files differnew file mode 100644 index 000000000..a56feddbf --- /dev/null +++ b/demos/photobrowser3d/images/default_sky_up.png diff --git a/demos/photobrowser3d/images/default_sky_west.png b/demos/photobrowser3d/images/default_sky_west.png Binary files differnew file mode 100644 index 000000000..4d2746b0d --- /dev/null +++ b/demos/photobrowser3d/images/default_sky_west.png diff --git a/demos/photobrowser3d/images/girder.png b/demos/photobrowser3d/images/girder.png Binary files differnew file mode 100644 index 000000000..f9b6c4dc6 --- /dev/null +++ b/demos/photobrowser3d/images/girder.png diff --git a/demos/photobrowser3d/images/no-images-yet.png b/demos/photobrowser3d/images/no-images-yet.png Binary files differnew file mode 100644 index 000000000..5d4f673ae --- /dev/null +++ b/demos/photobrowser3d/images/no-images-yet.png diff --git a/demos/photobrowser3d/images/no-images-yet.xcf b/demos/photobrowser3d/images/no-images-yet.xcf Binary files differnew file mode 100644 index 000000000..f084d45e4 --- /dev/null +++ b/demos/photobrowser3d/images/no-images-yet.xcf diff --git a/demos/photobrowser3d/images/sample_image.jpg b/demos/photobrowser3d/images/sample_image.jpg Binary files differnew file mode 100644 index 000000000..2826f9251 --- /dev/null +++ b/demos/photobrowser3d/images/sample_image.jpg 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 |