summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/imageformats/imageformats.pro2
-rw-r--r--src/plugins/imageformats/tga/main.cpp89
-rw-r--r--src/plugins/imageformats/tga/qtgafile.cpp237
-rw-r--r--src/plugins/imageformats/tga/qtgafile.h146
-rw-r--r--src/plugins/imageformats/tga/qtgahandler.cpp123
-rw-r--r--src/plugins/imageformats/tga/qtgahandler.h74
-rw-r--r--src/plugins/imageformats/tga/tga.pro10
-rw-r--r--src/plugins/plugins.pro3
-rw-r--r--src/plugins/qpluginbase.pri25
-rw-r--r--src/plugins/qt_targets.pri4
-rw-r--r--src/plugins/sceneformats/3ds/3ds.pro28
-rw-r--r--src/plugins/sceneformats/3ds/README.txt55
-rw-r--r--src/plugins/sceneformats/3ds/main.cpp70
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsloader.cpp333
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsloader.h81
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsmesh.cpp755
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsmesh.h95
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsscene.cpp117
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsscene.h82
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsscenehandler.cpp249
-rw-r--r--src/plugins/sceneformats/3ds/qgl3dsscenehandler.h99
-rw-r--r--src/plugins/sceneformats/assimp/README.txt12
-rw-r--r--src/plugins/sceneformats/assimp/ailoaderiostream.cpp121
-rw-r--r--src/plugins/sceneformats/assimp/ailoaderiostream.h67
-rw-r--r--src/plugins/sceneformats/assimp/ailoaderiosystem.cpp156
-rw-r--r--src/plugins/sceneformats/assimp/ailoaderiosystem.h67
-rw-r--r--src/plugins/sceneformats/assimp/assimp.pro32
-rw-r--r--src/plugins/sceneformats/assimp/main.cpp100
-rw-r--r--src/plugins/sceneformats/assimp/qailoader.cpp540
-rw-r--r--src/plugins/sceneformats/assimp/qailoader.h89
-rw-r--r--src/plugins/sceneformats/assimp/qaimesh.cpp143
-rw-r--r--src/plugins/sceneformats/assimp/qaimesh.h67
-rw-r--r--src/plugins/sceneformats/assimp/qaiscene.cpp112
-rw-r--r--src/plugins/sceneformats/assimp/qaiscene.h77
-rw-r--r--src/plugins/sceneformats/assimp/qaiscenehandler.cpp286
-rw-r--r--src/plugins/sceneformats/assimp/qaiscenehandler.h108
-rw-r--r--src/plugins/sceneformats/bezier/bezier.pro12
-rw-r--r--src/plugins/sceneformats/bezier/main.cpp70
-rw-r--r--src/plugins/sceneformats/bezier/qglbezierscene.cpp71
-rw-r--r--src/plugins/sceneformats/bezier/qglbezierscene.h66
-rw-r--r--src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp191
-rw-r--r--src/plugins/sceneformats/bezier/qglbezierscenehandler.h57
-rw-r--r--src/plugins/sceneformats/obj/main.cpp78
-rw-r--r--src/plugins/sceneformats/obj/obj.pro12
-rw-r--r--src/plugins/sceneformats/obj/qglobjscene.cpp74
-rw-r--r--src/plugins/sceneformats/obj/qglobjscene.h74
-rw-r--r--src/plugins/sceneformats/obj/qglobjscenehandler.cpp463
-rw-r--r--src/plugins/sceneformats/obj/qglobjscenehandler.h75
-rw-r--r--src/plugins/sceneformats/sceneformats.pro7
-rw-r--r--src/plugins/scenegraph/scenegraph.pro2
-rw-r--r--src/plugins/scenegraph/stereo/main.cpp70
-rw-r--r--src/plugins/scenegraph/stereo/qsgstereocontext.cpp358
-rw-r--r--src/plugins/scenegraph/stereo/qsgstereocontext.h83
-rw-r--r--src/plugins/scenegraph/stereo/stereo.pro15
54 files changed, 6432 insertions, 0 deletions
diff --git a/src/plugins/imageformats/imageformats.pro b/src/plugins/imageformats/imageformats.pro
new file mode 100644
index 000000000..c0ea5d84c
--- /dev/null
+++ b/src/plugins/imageformats/imageformats.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = tga
diff --git a/src/plugins/imageformats/tga/main.cpp b/src/plugins/imageformats/tga/main.cpp
new file mode 100644
index 000000000..f3873ee82
--- /dev/null
+++ b/src/plugins/imageformats/tga/main.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include <qimageiohandler.h>
+#include <qdebug.h>
+
+#include "qtgahandler.h"
+
+QT_BEGIN_NAMESPACE
+
+class QTgaPlugin : public QImageIOPlugin
+{
+public:
+ Capabilities capabilities(QIODevice * device, const QByteArray & format) const;
+ QImageIOHandler * create(QIODevice * device, const QByteArray & format = QByteArray()) const;
+ QStringList keys() const;
+};
+
+QImageIOPlugin::Capabilities QTgaPlugin::capabilities(QIODevice *device, const QByteArray &format) const
+{
+ if (format == "tga" || format == "TGA")
+ return Capabilities(CanRead);
+ if (!format.isEmpty())
+ return 0;
+ if (!device->isOpen())
+ return 0;
+
+ Capabilities cap;
+ if (device->isReadable() && QTgaHandler::canRead(device))
+ cap |= CanRead;
+ return cap;
+}
+
+QImageIOHandler* QTgaPlugin::create(QIODevice *device, const QByteArray &format) const
+{
+ QImageIOHandler *tgaHandler = new QTgaHandler();
+ tgaHandler->setDevice(device);
+ tgaHandler->setFormat(format);
+ return tgaHandler;
+}
+
+QStringList QTgaPlugin::keys() const
+{
+ return QStringList() << QLatin1String("tga") << QLatin1String("TGA");
+}
+
+Q_EXPORT_STATIC_PLUGIN(QTgaPlugin)
+Q_EXPORT_PLUGIN2(qtga, QTgaPlugin)
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/imageformats/tga/qtgafile.cpp b/src/plugins/imageformats/tga/qtgafile.cpp
new file mode 100644
index 000000000..f5f45c71f
--- /dev/null
+++ b/src/plugins/imageformats/tga/qtgafile.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** 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 "qtgafile.h"
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdatetime.h>
+
+struct TgaReader
+{
+ virtual ~TgaReader() {}
+ virtual QRgb operator()(QIODevice *s) const = 0;
+};
+
+struct Tga16Reader : public TgaReader
+{
+ ~Tga16Reader() {}
+ QRgb operator()(QIODevice *s) const
+ {
+ char ch1, ch2;
+ if (s->getChar(&ch1) && s->getChar(&ch2)) {
+ quint16 d = (int(ch1) & 0xFF) | ((int(ch2) & 0xFF) << 8);
+ QRgb result = (d & 0x8000) ? 0xFF000000 : 0x00000000;
+ result |= (d & 0x7C00 << 6) | (d & 0x03E0 << 3) | (d & 0x001F);
+ return result;
+ } else {
+ return 0;
+ }
+ }
+};
+
+struct Tga24Reader : public TgaReader
+{
+ QRgb operator()(QIODevice *s) const
+ {
+ char r, g, b;
+ if (s->getChar(&b) && s->getChar(&g) && s->getChar(&r))
+ return qRgb(uchar(r), uchar(g), uchar(b));
+ else
+ return 0;
+ }
+};
+
+struct Tga32Reader : public TgaReader
+{
+ QRgb operator()(QIODevice *s) const
+ {
+ char r, g, b, a;
+ if (s->getChar(&b) && s->getChar(&g) && s->getChar(&r) && s->getChar(&a))
+ return qRgba(uchar(r), uchar(g), uchar(b), uchar(a));
+ else
+ return 0;
+ }
+};
+
+/*!
+ \class QTgaFile
+ \since 4.8
+ \internal
+
+ File data container for a TrueVision Graphics format file.
+
+ Format is as described here:
+ http://local.wasp.uwa.edu.au/~pbourke/dataformats/tga/
+ http://netghost.narod.ru/gff2/graphics/summary/tga.htm
+
+ Usage is:
+ \code
+ QTgaFile tga(myFile);
+ QImage tgaImage;
+ if (tga.isValid())
+ tgaImage = tga.readImage();
+ \endcode
+
+ The class is designed to handle sequential and non-sequential
+ sources, so during construction the mHeader is read. Then during
+ the readImage() call the rest of the data is read.
+
+ After passing myFile to the constructor, if the QIODevice *myFile
+ is read, or has seek() called, the results are undefined - so don't
+ do that.
+*/
+
+/*!
+ Construct a new QTgaFile object getting data from \a device.
+
+ The object does not take ownership of the \a device, but until the
+ object is destroyed do not do any non-const operations, eg seek or
+ read on the device.
+*/
+QTgaFile::QTgaFile(QIODevice *device)
+ : mDevice(device)
+{
+ ::memset(mHeader, 0, HeaderSize);
+ if (!mDevice->isReadable())
+ {
+ mErrorMessage = QObject::tr("Could not read image data");
+ return;
+ }
+ if (mDevice->isSequential())
+ {
+ mErrorMessage = QObject::tr("Sequential device (eg socket) for image read not supported");
+ return;
+ }
+ if (!mDevice->seek(0))
+ {
+ mErrorMessage = QObject::tr("Seek file/device for image read failed");
+ return;
+ }
+ int bytes = device->read((char*)mHeader, HeaderSize);
+ if (bytes != HeaderSize)
+ {
+ mErrorMessage = QObject::tr("Image mHeader read failed");
+ return;
+ }
+ if (mHeader[ImageType] != 2)
+ {
+ // TODO: should support other image types
+ mErrorMessage = QObject::tr("Image type not supported");
+ return;
+ }
+}
+
+/*!
+ \internal
+ Destroy the device, recovering any resources.
+*/
+QTgaFile::~QTgaFile()
+{
+}
+
+/*!
+ \internal
+ Reads an image file from the QTgaFile's device, and returns it.
+
+ This method seeks to the absolute position of the image data in the file,
+ so no assumptions are made about where the devices read pointer is when this
+ method is called. For this reason only random access devices are supported.
+
+ If the constructor completed successfully, such that isValid() returns true,
+ then this method is likely to succeed, unless the file is somehow corrupted.
+
+ In the case that the read fails, the QImage returned will be null, such that
+ QImage::isNull() will be true.
+*/
+QImage QTgaFile::readImage()
+{
+ if (!isValid())
+ return QImage();
+
+ int offset = mHeader[IdLength]; // Mostly always zero
+
+ // Even in TrueColor files a color pallette may be present
+ if (mHeader[ColorMapType] == 1)
+ offset += littleEndianInt(&mHeader[CMapLength]) * littleEndianInt(&mHeader[CMapDepth]);
+
+ mDevice->seek(HeaderSize + offset);
+
+ char dummy;
+ for (int i = 0; i < offset; ++i)
+ mDevice->getChar(&dummy);
+
+ int bitsPerPixel = mHeader[PixelDepth];
+ int imageWidth = width();
+ int imageHeight = height();
+
+ unsigned char desc = mHeader[ImageDescriptor];
+ //unsigned char xCorner = desc & 0x10; // 0 = left, 1 = right
+ unsigned char yCorner = desc & 0x20; // 0 = lower, 1 = upper
+
+ QImage im(imageWidth, imageHeight, QImage::Format_ARGB32);
+ TgaReader *reader = 0;
+ if (bitsPerPixel == 16)
+ reader = new Tga16Reader();
+ else if (bitsPerPixel == 24)
+ reader = new Tga24Reader();
+ else if (bitsPerPixel == 32)
+ reader = new Tga32Reader();
+ TgaReader &read = *reader;
+
+ // For now only deal with yCorner, since no one uses xCorner == 1
+ // Also this is upside down, since Qt has the origin flipped
+ if (yCorner)
+ {
+ for (int y = 0; y < imageHeight; ++y)
+ for (int x = 0; x < imageWidth; ++x)
+ im.setPixel(x, y, read(mDevice));
+ }
+ else
+ {
+ for (int y = imageHeight - 1; y >= 0; --y)
+ for (int x = 0; x < imageWidth; ++x)
+ im.setPixel(x, y, read(mDevice));
+ }
+
+ // TODO: add processing of TGA extension information - ie TGA 2.0 files
+ return im;
+}
diff --git a/src/plugins/imageformats/tga/qtgafile.h b/src/plugins/imageformats/tga/qtgafile.h
new file mode 100644
index 000000000..ec78f73c2
--- /dev/null
+++ b/src/plugins/imageformats/tga/qtgafile.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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 QTGAFILE_H
+#define QTGAFILE_H
+
+#include <QtGui/qcolor.h>
+#include <QtGui/qimage.h>
+
+class QIODevice;
+
+class QTgaFile
+{
+public:
+ enum Compression {
+ NoCompression = 0,
+ RleCompression = 1
+ };
+
+ enum HeaderOffset {
+ IdLength = 0, /* 00h Size of Image ID field */
+ ColorMapType = 1, /* 01h Color map type */
+ ImageType = 2, /* 02h Image type code */
+ CMapStart = 3, /* 03h Color map origin */
+ CMapLength = 5, /* 05h Color map length */
+ CMapDepth = 7, /* 07h Depth of color map entries */
+ XOffset = 8, /* 08h X origin of image */
+ YOffset = 10, /* 0Ah Y origin of image */
+ Width = 12, /* 0Ch Width of image */
+ Height = 14, /* 0Eh Height of image */
+ PixelDepth = 16, /* 10h Image pixel size */
+ ImageDescriptor = 17, /* 11h Image descriptor byte */
+ HeaderSize = 18
+ };
+
+ QTgaFile(QIODevice *);
+ ~QTgaFile();
+
+ inline bool isValid() const;
+ inline QString errorMessage() const;
+ QImage readImage();
+ inline int xOffset() const;
+ inline int yOffset() const;
+ inline int width() const;
+ inline int height() const;
+ inline QSize size() const;
+ inline Compression compression() const;
+
+private:
+ static inline quint16 littleEndianInt(const unsigned char *d);
+
+ QString mErrorMessage;
+ unsigned char mHeader[HeaderSize];
+ QIODevice *mDevice;
+};
+
+inline bool QTgaFile::isValid() const
+{
+ return mErrorMessage.isEmpty();
+}
+
+inline QString QTgaFile::errorMessage() const
+{
+ return mErrorMessage;
+}
+
+/*!
+ \internal
+ Returns the integer encoded in the two little endian bytes at \a d.
+*/
+inline quint16 QTgaFile::littleEndianInt(const unsigned char *d)
+{
+ return d[0] + d[1] * 256;
+}
+
+inline int QTgaFile::xOffset() const
+{
+ return littleEndianInt(&mHeader[XOffset]);
+}
+
+inline int QTgaFile::yOffset() const
+{
+ return littleEndianInt(&mHeader[YOffset]);
+}
+
+inline int QTgaFile::width() const
+{
+ return littleEndianInt(&mHeader[Width]);
+}
+
+inline int QTgaFile::height() const
+{
+ return littleEndianInt(&mHeader[Height]);
+}
+
+inline QSize QTgaFile::size() const
+{
+ return QSize(width(), height());
+}
+
+inline QTgaFile::Compression QTgaFile::compression() const
+{
+ // TODO: for now, only handle type 2 files, with no color table
+ // and no compression
+ return NoCompression;
+}
+
+#endif // QTGAFILE_H
diff --git a/src/plugins/imageformats/tga/qtgahandler.cpp b/src/plugins/imageformats/tga/qtgahandler.cpp
new file mode 100644
index 000000000..90dcd4321
--- /dev/null
+++ b/src/plugins/imageformats/tga/qtgahandler.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** 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 "qtgahandler.h"
+#include "qtgafile.h"
+
+#include <qvariant.h>
+#include <qdebug.h>
+#include <qimage.h>
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+QTgaHandler::QTgaHandler()
+ : QImageIOHandler()
+ , tga(0)
+{
+}
+
+QTgaHandler::~QTgaHandler()
+{
+ delete tga;
+}
+
+bool QTgaHandler::canRead() const
+{
+ if (!tga)
+ tga = new QTgaFile(device());
+ if (tga->isValid())
+ {
+ setFormat("tga");
+ return true;
+ }
+ return false;
+}
+
+bool QTgaHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QTgaHandler::canRead() called with no device");
+ return false;
+ }
+ QTgaFile tga(device);
+ return tga.isValid();
+}
+
+bool QTgaHandler::read(QImage *image)
+{
+ if (!canRead())
+ return false;
+ *image = tga->readImage();
+ return !image->isNull();
+}
+
+QByteArray QTgaHandler::name() const
+{
+ return "tga";
+}
+
+QVariant QTgaHandler::option(ImageOption option) const
+{
+ if (option == Size && canRead()) {
+ return tga->size();
+ } else if (option == CompressionRatio) {
+ return tga->compression();
+ } else if (option == ImageFormat) {
+ return QImage::Format_ARGB32;
+ }
+ return QVariant();
+}
+
+void QTgaHandler::setOption(ImageOption option, const QVariant &value)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(value);
+}
+
+bool QTgaHandler::supportsOption(ImageOption option) const
+{
+ return option == CompressionRatio
+ || option == Size
+ || option == ImageFormat;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/tga/qtgahandler.h b/src/plugins/imageformats/tga/qtgahandler.h
new file mode 100644
index 000000000..d66dd17a0
--- /dev/null
+++ b/src/plugins/imageformats/tga/qtgahandler.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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 QTGAHANDLER_H
+#define QTGAHANDLER_H
+
+#include <QtGui/qimageiohandler.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTgaFile;
+
+class QTgaHandler : public QImageIOHandler
+{
+public:
+ QTgaHandler();
+ ~QTgaHandler();
+
+ bool canRead() const;
+ bool read(QImage *image);
+
+ QByteArray name() const;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const;
+ void setOption(ImageOption option, const QVariant &value);
+ bool supportsOption(ImageOption option) const;
+
+private:
+ mutable QTgaFile *tga;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTGAHANDLER_H
diff --git a/src/plugins/imageformats/tga/tga.pro b/src/plugins/imageformats/tga/tga.pro
new file mode 100644
index 000000000..209756e23
--- /dev/null
+++ b/src/plugins/imageformats/tga/tga.pro
@@ -0,0 +1,10 @@
+TARGET = qtga
+include(../../qpluginbase.pri)
+HEADERS += qtgahandler.h \
+ qtgafile.h
+SOURCES += main.cpp \
+ qtgahandler.cpp \
+ qtgafile.cpp
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats
+target.path += $$[QT_INSTALL_PLUGINS]/imageformats
+INSTALLS += target
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
new file mode 100644
index 000000000..cdf851ff3
--- /dev/null
+++ b/src/plugins/plugins.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = sceneformats imageformats
+scenegraph:SUBDIRS += scenegraph
diff --git a/src/plugins/qpluginbase.pri b/src/plugins/qpluginbase.pri
new file mode 100644
index 000000000..64e6e132b
--- /dev/null
+++ b/src/plugins/qpluginbase.pri
@@ -0,0 +1,25 @@
+TEMPLATE = lib
+isEmpty(QT_MAJOR_VERSION) {
+ VERSION=4.7.0
+} else {
+ VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION}
+}
+CONFIG += qt plugin
+
+win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release
+TARGET = $$qtLibraryTarget($$TARGET)
+contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
+
+include(qt_targets.pri)
+
+wince*:LIBS += $$QMAKE_LIBS_GUI
+
+symbian: {
+ TARGET.EPOCALLOWDLLDATA=1
+ contains(QT_EDITION, OpenSource) {
+ TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData
+ } else {
+ TARGET.CAPABILITY = All -Tcb
+ }
+ TARGET = $${TARGET}$${QT_LIBINFIX}
+}
diff --git a/src/plugins/qt_targets.pri b/src/plugins/qt_targets.pri
new file mode 100644
index 000000000..8c9a8dd0a
--- /dev/null
+++ b/src/plugins/qt_targets.pri
@@ -0,0 +1,4 @@
+QMAKE_TARGET_COMPANY = Nokia Corporation and/or its subsidiary(-ies)
+QMAKE_TARGET_PRODUCT = Qt4
+QMAKE_TARGET_DESCRIPTION = C++ application development framework.
+QMAKE_TARGET_COPYRIGHT = Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
diff --git a/src/plugins/sceneformats/3ds/3ds.pro b/src/plugins/sceneformats/3ds/3ds.pro
new file mode 100644
index 000000000..8cd4338dd
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/3ds.pro
@@ -0,0 +1,28 @@
+TARGET = qscene3ds
+include(../../qpluginbase.pri)
+HEADERS += qgl3dsloader.h \
+ qgl3dsscene.h \
+ qgl3dsscenehandler.h \
+ qgl3dsmesh.h
+SOURCES += main.cpp \
+ qgl3dsloader.cpp \
+ qgl3dsscene.cpp \
+ qgl3dsscenehandler.cpp \
+ qgl3dsmesh.cpp
+CONFIG += qt3d
+system_3ds {
+ !isEmpty(QMAKE_INCDIR_3DS):INCLUDEPATH += $$QMAKE_INCDIR_3DS
+ !isEmpty(QMAKE_LIBDIR_3DS):LIBS += -L$$QMAKE_LIBDIR_3DS
+
+ !isEmpty(QMAKE_LIBS_3DS):LIBS += -l$$QMAKE_LIBS_3DS
+ else {
+ win32:LIBS += -llib3ds-1_3
+ else:LIBS += -l3ds
+ }
+} else {
+ include(../../../../3rdparty/lib3ds/lib3ds.pri)
+}
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/sceneformats
+target.path += $$[QT_INSTALL_PLUGINS]/sceneformats
+INSTALLS += target
diff --git a/src/plugins/sceneformats/3ds/README.txt b/src/plugins/sceneformats/3ds/README.txt
new file mode 100644
index 000000000..1fa00084b
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/README.txt
@@ -0,0 +1,55 @@
+This implementation of 3D studio max file import relies on the library
+lib3ds available from http://lib3ds.org/. A copy of this library is
+included with Qt/3D, or you can download and build your own version
+as described below.
+
+To enable building and use of the plugin, pass CONFIG+=system_3ds to qmake
+
+Currently version 1.3 is required. Do not use version 2.0 or later as it is incompatible.
+
+For Linux systems typically 1.3 can be obtained by installing a binary package, eg lib3ds-dev
+
+When compiling from source on Unix a simple ./configure, make, make install seems to work fine
+on both linux and mac osx.
+
+On windows with Visual Studio the lib3ds library can be compiled as follows.
+
+1) Download the zipped source of 1.3 and expand it, cd into the directory created.
+
+2) Edit the file msvc8\lib3ds.rc
+ -#include "winres.h"
+ +#include "WinResrc.h"
+
+3) Locate the vcbuild.exe on the windows system:
+
+ // this is needed for VS9
+ C:\path\to\vcbuild.exe /upgrade msvc8\lib3ds.vcproj
+ C:\path\to\vcbuild.exe msvc8\lib3ds.vcproj
+
+4) Release and debug versions of the library files will be created. Install by:
+
+ xcopy msvc8\release\* C:\path\to\bin
+ xcopy msvc8\debug\* C:\path\to\bin
+
+To avoid having to install the lib3ds.org library/dll/headers in a path where the compiler
+will locate them, pass the following arguments to qmake:
+ QMAKE_LIBDIR_3DS=C:\build\lib3ds\msvc8\release
+ QMAKE_INCDIR_3DS=C:\build\lib3ds
+
+If the library is called something different to lib3ds-1_3 on windows or lib3ds.1.3.so on
+Unix, for example to use the debug library on windows pass this argument to qmake:
+ QMAKE_LIBS_3DS=lib3ds-1_3d
+
+There is a handy 3dsplay utility in the lib3ds distribution - its not needed for Qt3D but is
+convenient for debugging models.
+
+To build the 3dsplay utility - a command line 3ds viewer that uses GLUT and OpenGL - after
+building and installing lib3ds as above, from the build directory use:
+Linux: gcc -o 3dsplay -lGL -lglut -l3ds examples/3dsplay.c
+MacOSX: gcc -FOpenGL -FGLUT -framework OpenGL -framework GLUT -l3ds -o 3dsplay examples/3dsplay.c
+
+To get image loading support to enable textures, this works on MacSOX:
+First install SDL: http://www.libsdl.org/download-1.2.php
+And SDL_image: http://www.libsdl.org/projects/SDL_image/
+ gcc -c -DUSE_SDL -o examples/3dsplay.o -I/Library/Frameworks/SDL.framework/Headers -I/Library/Frameworks/SDL_image.framework/Headers examples/3dsplay.c
+ gcc -framework SDL_image -framework SDL -framework OpenGL -framework GLUT -l3ds -o 3dsplay examples/3dsplay.o
diff --git a/src/plugins/sceneformats/3ds/main.cpp b/src/plugins/sceneformats/3ds/main.cpp
new file mode 100644
index 000000000..6bd311270
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/main.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "qglsceneformatplugin.h"
+#include "qgl3dsscenehandler.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGL3dsScenePlugin : public QGLSceneFormatPlugin
+{
+public:
+ QStringList keys() const;
+ virtual QGLSceneFormatHandler *create(QIODevice *device, const QUrl& url, const QString &format) const;
+};
+
+QStringList QGL3dsScenePlugin::keys() const
+{
+ return QStringList() << QLatin1String("3ds") << QLatin1String("application/x-3ds") << QLatin1String("image/x-3ds");
+}
+
+QGLSceneFormatHandler *QGL3dsScenePlugin::create(QIODevice *device, const QUrl& url, const QString &format) const
+{
+ Q_UNUSED(device);
+ Q_UNUSED(url);
+ Q_UNUSED(format);
+ return new QGL3dsSceneHandler;
+}
+
+Q_EXPORT_STATIC_PLUGIN(QGL3dsScenePlugin)
+Q_EXPORT_PLUGIN2(qscene3ds, QGL3dsScenePlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/3ds/qgl3dsloader.cpp b/src/plugins/sceneformats/3ds/qgl3dsloader.cpp
new file mode 100644
index 000000000..34cefa336
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsloader.cpp
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** 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 "qgl3dsloader.h"
+#include "qglmaterial.h"
+#include "qglmaterialcollection.h"
+#include "qglpainter.h"
+#include "qgltexture2d.h"
+#include "qgl3dsscene.h"
+#include "qglscenenode.h"
+#include "qgl3dsmesh.h"
+
+#include <lib3ds/mesh.h>
+#include <lib3ds/file.h>
+#include <lib3ds/node.h>
+#include <lib3ds/material.h>
+#include <lib3ds/matrix.h>
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qfileinfo.h>
+
+QGL3dsLoader::QGL3dsLoader(Lib3dsFile *file, QGL3dsSceneHandler* sh)
+ : m_file(file)
+ , m_rootNode(new QGLSceneNode())
+ , m_scene(sh)
+ , m_hasTextures(false)
+{
+ m_rootNode->setPalette(new QGLMaterialCollection(m_rootNode));
+ m_rootNode->setObjectName(QString::fromLocal8Bit(file->name));
+ setUrl(sh->url());
+}
+
+QGL3dsLoader::~QGL3dsLoader()
+{
+ // nothing to do here - m_rootNode is taken ownership of by caller of
+ // rootNode() method
+}
+
+/*!
+ Sets the location for resolving resource paths to \a url.
+
+ Only URL's with a "file" scheme are supported.
+*/
+void QGL3dsLoader::setUrl(const QUrl &url)
+{
+ // TODO - handling of network URLs
+ if (url.scheme() == QLatin1String("file"))
+ m_url = url;
+ else
+ qWarning("QGL3dsLoader::setUrl(%s): ignored, only file urls supported",
+ url.encodedPath().constData());
+}
+
+void QGL3dsLoader::loadMesh(Lib3dsMesh *mesh)
+{
+#ifndef QT_NO_DEBUG_STREAM
+ if (mesh->points == 0 && (m_scene->options() & QGL::ShowWarnings))
+ qDebug() << "Mesh" << mesh->name << "has zero vertex count";
+ else if (mesh->faces == 0 && (m_scene->options() & QGL::ShowWarnings))
+ qDebug() << "Mesh" << mesh->name << "has zero face count";
+#endif
+ QGL3dsMesh m(mesh, m_rootNode->palette());
+ QString name = QString::fromLatin1(mesh->name);
+ QGL::ModelOptions o = m_scene->meshOptions(name);
+ if (o == 0)
+ o = m_scene->options();
+ m.setOptions(o);
+ QGLSceneNode *node;
+ if (mesh->faces == 0 || mesh->points == 0)
+ {
+ node = new QGLSceneNode(m_rootNode);
+ node->setObjectName(name);
+ m_meshes.insert(name, node);
+ return;
+ }
+ m.initialize();
+ if (!m_hasTextures)
+ m_hasTextures = m.hasTexture();
+ if (!m_hasLitMaterials)
+ m_hasLitMaterials = !m.hasTexture();
+ node = m.finalizedSceneNode();
+ m_meshes.insert(name, node);
+ m_rootNode->addNode(node);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+static const char *node_type_names[] = {
+ "LIB3DS_UNKNOWN_NODE",
+ "LIB3DS_AMBIENT_NODE",
+ "LIB3DS_OBJECT_NODE",
+ "LIB3DS_CAMERA_NODE",
+ "LIB3DS_TARGET_NODE",
+ "LIB3DS_LIGHT_NODE",
+ "LIB3DS_SPOT_NODE"
+};
+#endif
+
+inline static QMatrix4x4 getNodeMatrix(Lib3dsNode *node)
+{
+ QMatrix4x4 nodeMatrix;
+ for (int col = 0; col < 4; ++col)
+ for (int row = 0; row < 4; ++row)
+ nodeMatrix(row, col) = node->matrix[col][row];
+ nodeMatrix.optimize();
+ Lib3dsObjectData *d = &node->data.object;
+ if (!qFuzzyIsNull(d->pivot[0]) || !qFuzzyIsNull(d->pivot[1]) || !qFuzzyIsNull(d->pivot[2]))
+ nodeMatrix.translate(-d->pivot[0], -d->pivot[1], -d->pivot[2]);
+ return nodeMatrix;
+}
+
+void QGL3dsLoader::loadNodes(Lib3dsNode *nodeList, QGLSceneNode *parentNode)
+{
+ Lib3dsNode *node;
+ for (node = nodeList; node != NULL; node = node->next)
+ {
+ if (node->type == LIB3DS_OBJECT_NODE)
+ {
+ Lib3dsObjectData *d = &node->data.object;
+ QString meshName = QString::fromLatin1(d->morph);
+ if (meshName.isEmpty())
+ meshName = QString::fromLatin1(d->instance);
+ if (meshName.isEmpty())
+ meshName = QString::fromLatin1(node->name);
+ if (!meshName.isEmpty() && m_meshes.contains(meshName))
+ {
+ QGLSceneNode *mesh = m_meshes[meshName];
+ QMatrix4x4 mat = getNodeMatrix(node);
+ mat = mat * mesh->localTransform();
+ mesh->setLocalTransform(mat);
+ }
+ else
+ {
+ QGLSceneNode *sceneNode = new QGLSceneNode(parentNode);
+ sceneNode->setPalette(parentNode->palette());
+ sceneNode->setLocalTransform(getNodeMatrix(node));
+ //sceneNode->userTransform().setToIdentity(); //DP: set matrix to identity so it is initialised in a useful way at least.
+ QString nodeName(QString::fromLatin1(node->name));
+ if (nodeName == QLatin1String("$$$DUMMY"))
+ {
+ nodeName = QString::fromLatin1(node->data.object.instance);
+ sceneNode->setObjectName(nodeName);
+ loadNodes(node->childs, sceneNode);
+ }
+ }
+ }
+#ifndef QT_NO_DEBUG_STREAM
+ else
+ {
+ qDebug() << "Node" << node->name << "of type" << node_type_names[node->type] << "not currently supported";
+ }
+#endif
+ }
+}
+
+/*!
+ \internal
+ Loads all the geometry, materials, and texture associations from the assigned
+ file, and returns the root node of the resulting scene graph.
+
+ The caller must take ownership of the root node returned, and delete it
+ when its no longer required.
+*/
+QGLSceneNode *QGL3dsLoader::loadMeshes()
+{
+ Q_CHECK_PTR(m_file);
+ Lib3dsMaterial *mat;
+ for (mat = m_file->materials; mat != NULL; mat = mat->next)
+ loadMaterial(mat);
+ Lib3dsMesh * mesh;
+ for (mesh = m_file->meshes; mesh != NULL; mesh = mesh->next)
+ loadMesh(mesh);
+ QGL::MeshOptionMap optList = m_scene->meshOptions();
+ QStringList optionedMeshes = optList.keys();
+ QStringList gotMeshes = m_meshes.keys();
+ for (int i = 0; i < gotMeshes.size(); ++i)
+ optionedMeshes.removeAll(gotMeshes.at(i));
+ for (int i = 0; i < optionedMeshes.size(); ++i)
+ qWarning("Option specified, but mesh %s not found",
+ qPrintable(optionedMeshes.at(i)));
+ m_rootNode->palette()->removeUnusedMaterials();
+ loadNodes(m_file->nodes, m_rootNode);
+ m_rootNode->setEffect(m_hasTextures ? QGL::LitModulateTexture2D : QGL::LitMaterial);
+ return m_rootNode;
+}
+
+/*!
+ \internal
+ Search for a resource based on the given \a path.
+
+ If the URL for the currently loading mesh has a scheme other than
+ "file" then a URL with the path relative to that URL is returned.
+
+ If the URL for the currently loading mesh has a "file" scheme, then
+ first a case-sensitive search is done of all of the current directory,
+ and the :/ resource directory, and the directory of the current mesh
+ file.
+
+ If the file is not found in any of those locations then they are
+ searched again case-insensitively. If the file is found, then a
+ URL based on the absolute file path of the matching file is returned.
+
+ Otherwise an empty string is returned.
+*/
+QUrl QGL3dsLoader::ensureResource(const QString &path)
+{
+ QUrl res;
+ if (m_url.scheme() == QLatin1String("file"))
+ {
+ res = m_url.resolved(path);
+ if (QFile::exists(res.path())) // shortcut common case
+ return res;
+ QStringList paths;
+ paths << QLatin1String(".") << QLatin1String(":/"); // current directory and aliased/root resource file
+ if (!m_url.isEmpty())
+ {
+ QFileInfo fi(m_url.path());
+ paths.prepend(fi.absoluteDir().absolutePath());
+ }
+ bool caseInsensitive = false;
+ do {
+ QStringList::const_iterator it(paths.begin());
+ for ( ; it != paths.end(); ++it)
+ {
+ QDir resDir(*it);
+ QStringList fileList = resDir.entryList(QDir::Files);
+ if (caseInsensitive)
+ {
+ QStringList::const_iterator fit(fileList.begin());
+ for ( ; fit != fileList.end(); ++fit)
+ {
+ if (fit->toLower() == path.toLower())
+ {
+ res.setScheme(QLatin1String("file"));
+ res.setPath(resDir.absoluteFilePath(*fit));
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (fileList.contains(path))
+ {
+ //return resDir.absoluteFilePath(path);
+ res.setScheme(QLatin1String("file"));
+ res.setPath(resDir.absoluteFilePath(path));
+ break;
+ }
+ }
+ }
+ if (caseInsensitive)
+ break;
+ caseInsensitive = true;
+ } while (true);
+ }
+ else
+ {
+ // non-file url
+ res = m_url.resolved(path);
+ }
+ return res;
+}
+
+/*!
+ Load a material
+*/
+void QGL3dsLoader::loadMaterial(Lib3dsMaterial *mat3ds)
+{
+ QGLMaterialCollection *palette = m_rootNode->palette();
+ QGLMaterial *mat = new QGLMaterial();
+ Lib3dsRgba &amb = mat3ds->ambient;
+ Lib3dsRgba &dif = mat3ds->diffuse;
+ Lib3dsRgba &spc = mat3ds->specular;
+ mat->setAmbientColor(QColor::fromRgbF(amb[0], amb[1], amb[2], amb[3]));
+ mat->setDiffuseColor(QColor::fromRgbF(dif[0], dif[1], dif[2], dif[3]));
+ mat->setSpecularColor(QColor::fromRgbF(spc[0], spc[1], spc[2], spc[3]));
+ mat->setShininess(128 * mat3ds->shininess);
+ mat->setObjectName(QString::fromLatin1(mat3ds->name));
+ palette->addMaterial(mat);
+ if (mat3ds->texture1_map.name[0])
+ {
+ QString txName(QString::fromLatin1(mat3ds->texture1_map.name));
+ QUrl url = ensureResource(txName);
+ if (url.isEmpty())
+ {
+ if (m_scene->options() & QGL::ShowWarnings)
+ qWarning("Could not load texture: %s", mat3ds->texture1_map.name);
+ }
+ else
+ {
+ mat->setTextureUrl(url);
+ }
+ }
+}
diff --git a/src/plugins/sceneformats/3ds/qgl3dsloader.h b/src/plugins/sceneformats/3ds/qgl3dsloader.h
new file mode 100644
index 000000000..edfe1b34b
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsloader.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 QGL3DSLOADER_H
+#define QGL3DSLOADER_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmap.h>
+
+class Lib3dsFile;
+class Lib3dsMesh;
+class Lib3dsMaterial;
+class Lib3dsNode;
+class QGL3dsMesh;
+class QGLSceneNode;
+class QGL3dsSceneHandler;
+
+class QGL3dsLoader
+{
+public:
+ QGL3dsLoader(Lib3dsFile *file, QGL3dsSceneHandler* sh);
+ ~QGL3dsLoader();
+ QGLSceneNode *loadMeshes();
+
+private:
+ void loadMesh(Lib3dsMesh *);
+ void loadNodes(Lib3dsNode *, QGLSceneNode *);
+ void loadMaterial(Lib3dsMaterial *);
+ QUrl ensureResource(const QString &);
+ void setUrl(const QUrl &url);
+
+ Lib3dsFile *m_file;
+ QGLSceneNode *m_rootNode;
+ QGL3dsSceneHandler *m_scene;
+ QList<QGLSceneNode *> m_nodes;
+ QMap<QString, QGLSceneNode *> m_meshes;
+ QUrl m_url;
+ bool m_hasTextures;
+ bool m_hasLitMaterials;
+};
+
+#endif // QGL3DSLOADER_H
diff --git a/src/plugins/sceneformats/3ds/qgl3dsmesh.cpp b/src/plugins/sceneformats/3ds/qgl3dsmesh.cpp
new file mode 100644
index 000000000..6cc5db244
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsmesh.cpp
@@ -0,0 +1,755 @@
+/****************************************************************************
+**
+** 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 "qgl3dsmesh.h"
+#include "qglmaterialcollection.h"
+#include "qglsection_p.h"
+#include "qarray.h"
+#include "qvector_utils_p.h"
+
+#include <lib3ds/mesh.h>
+#include <lib3ds/material.h>
+#include <lib3ds/vector.h>
+#include <lib3ds/types.h>
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qmath.h>
+
+// Faceted meshes look terrible when they have more than a small number
+// of faces. Usually if large meshes are faceted its some kind of error
+// in the model, or in importing of the model by lib3ds. Force on
+// smoothing when greater than this many faces are detected.
+#define FACETED_THRESHOLD 1000
+
+// Two faces that have an angle between their plane vectors with a cosine
+// less than this are judged to form a sharp (acute) angle.
+// -ve cosine (less than 0.0f) means 90 degrees or sharper like the sides
+// of a rectangular prism so this is a good value.
+#define ACUTE -0.0001f
+
+// Two vectors that have an angle between them with a cosine less than this
+// value are judged to be approximately the inverse of each other, for the
+// purposes of determining whether a normal has been inverted or not
+#define INVERSE -0.20f
+
+// Only try to correct normals if this many neighbour faces contribute to
+// the assessment. 2 or 3 are good values. 4 or greater is the same as
+// defining DO_NORMAL_CORRECT false
+#define AVG_CNT 2
+
+// make a QVector3D from a Lib3dsVector - by a hard cast. Its required
+// that QVector3D behave like a POD type - float[3] - for all of the
+// OpenGL stuff
+static inline QVector3D &l2v(Lib3dsVector &vec)
+{
+ return reinterpret_cast<QVector3D&>(vec);
+}
+
+// is this a null 3ds vector - same as QVector3D::isNull()
+static inline bool qIsNull(const Lib3dsVector &vec)
+{
+ return (qIsNull(vec[0]) && qIsNull(vec[1]) && qIsNull(vec[2]));
+}
+
+static inline bool qFskCompare(const Lib3dsVector &a, const Lib3dsVector &b)
+{
+ return (qFskCompare(a[0], b[0]) && qFskCompare(a[1], b[1]) && qFskCompare(a[2], b[2]));
+}
+
+// find the normalized plane vector, that is a unit vector perpendicular
+// to the plane of the face. this is the same thing as the default normal
+static inline void planeVec(Lib3dsFace *face, Lib3dsPoint *pointList, Lib3dsVector result)
+{
+ Lib3dsVector &l3a = pointList[face->points[0]].pos;
+ Lib3dsVector &l3b = pointList[face->points[1]].pos;
+ Lib3dsVector &l3c = pointList[face->points[2]].pos;
+ lib3ds_vector_normal(result, l3a, l3b, l3c);
+}
+
+struct ModulateRecord
+{
+ bool disabled;
+ bool keyFresh;
+ int facesProcessed;
+ int numModulated;
+ Lib3dsDword altKey;
+ Lib3dsDword key;
+};
+
+QGL3dsMesh::QGL3dsMesh(Lib3dsMesh *mesh, QGLMaterialCollection *materials)
+ : QGLBuilder(materials)
+ , m_mesh(mesh)
+ , m_texFlip(false)
+ , m_hasZeroSmoothing(false)
+ , m_faceMap(0)
+{
+}
+
+QGL3dsMesh::~QGL3dsMesh()
+{
+ delete[] m_faceMap;
+}
+
+void QGL3dsMesh::processNodeForMaterial(int matIx, QGLSceneNode *node)
+{
+ QGLSceneNode *s = sceneNode();
+ QString baseName = s->objectName();
+ node->setMaterialIndex(matIx);
+ node->setObjectName(baseName + QLatin1String("::") +
+ ((matIx == -1)
+ ? QLatin1String("No_Material")
+ : s->palette()->materialName(matIx)));
+ checkTextures(matIx);
+ generateVertices();
+ s->palette()->markMaterialAsUsed(matIx);
+}
+
+void QGL3dsMesh::initAdjacencyMap()
+{
+ Lib3dsFace *face;
+ m_faceMap = new FacePtr[m_mesh->faces * 3];
+ qMemSet(m_faceMap, 0, sizeof(m_faceMap));
+ for (Lib3dsDword f = 0; f < m_mesh->faces; ++f)
+ {
+ face = &m_mesh->faceL[f];
+ planeVec(face, m_mesh->pointL, face->normal);
+ m_mesh->faceL[f].user.p = &m_faceMap[f*3];
+ }
+}
+
+void QGL3dsMesh::initialize()
+{
+ QGLSceneNode *s = sceneNode();
+ s->setObjectName(QString::fromLatin1(m_mesh->name));
+ if ((m_options & QGL::ForceSmooth) && (m_options & QGL::ForceFaceted))
+ {
+ if (m_options & QGL::ShowWarnings)
+ qWarning("Both smooth and faceted forced on for %s: forcing smooth\n",
+ m_mesh->name);
+ m_options &= ~QGL::ForceFaceted;
+ }
+ initAdjacencyMap();
+ if (m_options & (QGL::CorrectNormals | QGL::CorrectAcute))
+ modulateMesh();
+ analyzeMesh();
+
+ if (m_smoothingGroups == 0)
+ {
+ bool forceSmooth = (m_options & QGL::ForceSmooth);
+ if (!forceSmooth && m_mesh->faces > FACETED_THRESHOLD)
+ {
+ if (m_options & QGL::ShowWarnings)
+ fprintf(stderr, "Mesh %s has %d faces (threshold is %d):"
+ "forcing smooth render", m_mesh->name, m_mesh->faces,
+ FACETED_THRESHOLD);
+ forceSmooth = true;
+ }
+ if (forceSmooth)
+ {
+ for (Lib3dsDword f = 0; f < m_mesh->faces; ++f)
+ m_mesh->faceL[f].smoothing = 1;
+ analyzeMesh();
+ }
+ }
+
+ bool mixedTexturedAndPlain = m_plainMaterials.count() > 0 &&
+ m_textureMaterials.count() > 0;
+
+ s->setLocalTransform(meshMatrix());
+
+ // start a new section and node
+ newSection(m_smoothingGroups ? QGL::Smooth : QGL::Faceted);
+ QGLSceneNode *node = currentNode();
+
+ // process all the plain materials first, then textured to avoid effect swapping
+ QList<int> matList = m_plainMaterials.toList();
+ if (mixedTexturedAndPlain)
+ {
+ node->setEffect(QGL::LitMaterial);
+ node->setObjectName(s->objectName() + QLatin1String("::Materials"));
+ //qDebug() << ">>> mixed:" << node;
+ pushNode();
+ //qDebug() << " pushed - current now:" << currentNode();
+ }
+ else
+ {
+ s->setEffect(m_textureMaterials.count() > 0 ? QGL::LitModulateTexture2D : QGL::LitMaterial);
+ }
+ //qDebug() << "processing:" << matList.count() << "materials";
+ while (matList.count() > 0)
+ {
+ int matIx = matList.takeFirst();
+ processNodeForMaterial(matIx, node);
+ if (matList.count() > 0)
+ node = newNode();
+ }
+ matList = m_textureMaterials.toList();
+ if (mixedTexturedAndPlain)
+ {
+ //qDebug() << "<<< mixed:" << currentNode();
+ popNode();
+ //qDebug() << " popped - current now:" << currentNode();
+ node = currentNode();
+ node->setEffect(QGL::LitModulateTexture2D);
+ node->setObjectName(s->objectName() + QLatin1String("::Textures"));
+ }
+ while (matList.count() > 0)
+ {
+ int matIx = matList.takeFirst();
+ processNodeForMaterial(matIx, node);
+ if (matList.count() > 0)
+ node = newNode();
+ }
+}
+
+// Build a linked list, in a QArray: the first N*2 entries correspond
+// to the N vertices: for each n'th vertex, n*2 is the face number,
+// n*2+1is the index of the next entry for that vertex, or -1 if there
+// is no next entry.
+//
+// While on the job find the smoothing keys and store in allKeys.
+//
+// And zero out the user data pointer for each face, and calculate the
+// smoothing group count.
+QArray<int> QGL3dsMesh::mapFacesToVerts(Lib3dsDword *allKeys)
+{
+ Lib3dsFace *face;
+ QArray<int> vlist(m_mesh->points * 2, -1);
+ int nx = 2 * m_mesh->points;
+ m_smoothingGroupCount = 0;
+ for (Lib3dsDword f = 0; f < m_mesh->faces; ++f)
+ {
+ face = &m_mesh->faceL[f];
+ if (face->smoothing)
+ {
+ if (!(face->smoothing & *allKeys))
+ {
+ *allKeys |= face->smoothing;
+ m_smoothingGroupCount += 1;
+ }
+ }
+ for (int i = 0; i < 3; ++i)
+ {
+ int v = face->points[i];
+ int ptr = v*2;
+ int prv = -1;
+ if (vlist[ptr] != -1)
+ {
+ prv = ptr;
+ while (vlist[ptr+1] != -1)
+ {
+ ptr = vlist[ptr+1];
+ prv = ptr;
+ }
+ ptr = nx;
+ vlist.extend(2);
+ nx += 2;
+ }
+ vlist[ptr] = f;
+ vlist[ptr+1] = -1;
+ if (prv != -1)
+ vlist[prv+1] = ptr;
+ }
+ }
+ return vlist;
+}
+
+void QGL3dsMesh::addToAdjacencyMap(Lib3dsFace *face, Lib3dsFace *neighbour)
+{
+ Q_ASSERT(face);
+ Q_ASSERT(face->user.p);
+ Q_ASSERT(neighbour);
+ FacePtr *h = static_cast<FacePtr*>(face->user.p);
+ while (*h != 0)
+ ++h;
+ *h = neighbour;
+}
+
+// add to each face a linked list of its <= 3 neighbouring faces
+// and also ensure each face knows is own normal. Rather than doing
+// lots of small allocs, just assume every face has 3 neighbours
+// and allocate the list nodes in one big lump - the m_faceMap.
+// use the user data pointer in the lib3ds face struct to point
+// to the first node in the list.
+void QGL3dsMesh::buildAdjacencyMap(const QArray<int> &vlist)
+{
+ Lib3dsFace *face;
+ Lib3dsFace *nbr;
+ for (Lib3dsDword f = 0; f < m_mesh->faces; ++f)
+ {
+ // for each edge (where an edge is a pair of verts) find ones
+ // adjacent, ie both verts in edge have same face (which is
+ // not this face).
+ face = &m_mesh->faceL[f];
+ for (int i = 0; i < 3; ++i)
+ {
+ Q_ASSERT(face->points[i] < m_mesh->points);
+ int vi = 2 * face->points[i];
+ int neighbouri = -1;
+ while (true)
+ {
+ neighbouri = vlist[vi];
+ if (neighbouri != (int)f)
+ {
+ Q_ASSERT(face->points[(i + 1) % 3] < m_mesh->points);
+ int vj = 2 * face->points[(i + 1) % 3];
+ int neighbourj = -1;
+ while (true)
+ {
+ neighbourj = vlist[vj];
+ if (neighbourj == neighbouri)
+ {
+ nbr = &m_mesh->faceL[neighbouri];
+ // only add as neighbour if at least one smoothing group
+ // is shared - still have to test again below for each group
+ if (nbr->smoothing & face->smoothing)
+ addToAdjacencyMap(face, nbr);
+ break;
+ }
+ if (vlist[vj+1] == -1)
+ break;
+ vj = vlist[vj+1];
+ }
+ }
+ if (vlist[vi+1] == -1)
+ break;
+ else
+ vi = vlist[vi+1];
+ }
+ }
+ }
+}
+
+static inline void incOrWarn(ModulateRecord *mod)
+{
+ if (mod->altKey != 0x80000000)
+ {
+ mod->altKey <<= 1;
+ }
+ else
+ {
+ qWarning("Overflowed smoothing keys - modulation disabled.");
+ mod->disabled = true;
+ }
+}
+
+static inline void nextUnusedKey(ModulateRecord *mod, const Lib3dsDword &allKeys)
+{
+ if (!mod->disabled)
+ {
+ if (mod->altKey != 0)
+ incOrWarn(mod);
+ else
+ {
+ mod->altKey = 1; // initialize
+ }
+ while ((mod->altKey & allKeys) && !mod->disabled)
+ {
+ incOrWarn(mod);
+ }
+ mod->keyFresh = true;
+ }
+}
+
+static int numCorrected = 0;
+static int numWindingCorrected = 0;
+
+static inline void doNormalCorrect(Lib3dsFace *face)
+{
+ QGL3dsMesh::FacePtr *n = reinterpret_cast<QGL3dsMesh::FacePtr*>(face->user.p);
+ int acnt = 0;
+ Lib3dsVector avgn = { 0 };
+ for (; *n; ++n)
+ {
+ if ((*n)->smoothing & face->smoothing)
+ {
+ lib3ds_vector_add(avgn, avgn, (*n)->normal);
+ ++acnt;
+ }
+ }
+ if (acnt >= AVG_CNT)
+ {
+ lib3ds_vector_normalize(avgn);
+ float na = lib3ds_vector_dot(face->normal, avgn);
+ if (na < INVERSE)
+ {
+ //fprintf(stderr, "corrected: %p - %d, %d, %d", face,
+ // face->points[0], face->points[1], face->points[2]);
+ //lib3ds_vector_dump(face->normal);
+ lib3ds_vector_neg(face->normal);
+ numWindingCorrected++;
+ qSwap(face->points[1], face->points[2]);
+ }
+ }
+}
+
+static inline void modFace(Lib3dsFace *face, ModulateRecord *mod)
+{
+ ++mod->numModulated;
+ face->smoothing &= ~mod->key; // remove old key
+ face->smoothing |= mod->altKey; // add in new key
+ ::strncpy(face->material, "bright-red", 60); //debug
+}
+
+static inline void doModulate(Lib3dsFace *face, ModulateRecord *mod)
+{
+ QGL3dsMesh::FacePtr *n = reinterpret_cast<QGL3dsMesh::FacePtr*>(face->user.p);
+ ++mod->facesProcessed;
+ for ( ; *n; ++n)
+ {
+ QGL3dsMesh::FacePtr neighbour = *n;
+ if (neighbour->smoothing & face->smoothing)
+ {
+ if (lib3ds_vector_dot(face->normal, neighbour->normal) < ACUTE)
+ {
+ fprintf(stderr, "Modulated due to ACUTE\n");
+ modFace(neighbour, mod);
+ mod->keyFresh = false;
+ }
+ }
+ }
+}
+
+bool operator<(const QVector3D &a, const QVector3D &b)
+{
+ if (qFskCompare(a.x(), b.x()))
+ {
+ if (qFskCompare(a.y(), b.y()))
+ {
+ if (qFskCompare(a.z(), b.z()))
+ {
+ return false; // they're equal a is not less than b
+ }
+ else
+ {
+ return a.z() < b.z();
+ }
+ }
+ else
+ {
+ return a.y() < b.y();
+ }
+ }
+ else
+ {
+ return a.x() < b.x();
+ }
+}
+
+// Go thru each smoothing group - we don't care about the zero group since
+// they're already faceted. In each group process all connected faces
+// starting the queue off with a seed face (the first face in the group).
+// Set the alternate group to be the first unused smoothing group key.
+//
+// To process a face: add the face to the processed set; for each adjacent
+// face if its in this same smoothing group, add it to the queue.
+//
+// Modulate smoothing mode: if an adjacent face is at an acute angle to this
+// face, move it to the alternate group. Note that the alternate groups are
+// not further iterated since they are not in "each smoothing group"
+// (the allKeys variable).
+//
+// When the queue is empty, go to the next smoothing group in the mesh.
+
+// Normal repair mode: if a face normal is flipped in error, ie a mistake
+// in model building (typically points specified in the wrong order)
+// this can be detected and repaired. The normal is flipped if the inverse
+// of the normal is at an acute angle to the average of neighbour normals.
+// If detected the normals is corrected and the winding is also checked to
+// see if it needs to be corrected also.
+void QGL3dsMesh::modulateMesh()
+{
+ if (!(m_options & (QGL::CorrectNormals | QGL::CorrectAcute)))
+ return;
+ FacePtr face;
+ Lib3dsDword allKeys = 0;
+ QArray<int> vlist = mapFacesToVerts(&allKeys);
+ buildAdjacencyMap(vlist);
+ QSet<FacePtr> processed;
+ ModulateRecord mod;
+ qMemSet(&mod, 0, sizeof(struct ModulateRecord));
+ mod.key = 1;
+ while ((mod.key < allKeys) && !mod.disabled && mod.key)
+ {
+ if (!(allKeys & mod.key))
+ {
+ ++mod.key;
+ continue;
+ }
+ QArray<FacePtr> queue;
+ Lib3dsDword fptr = 0;
+ int head = 0;
+ while (true)
+ {
+ if (head >= queue.size()) // seed another island of faces
+ {
+ if (!mod.keyFresh && head > 0) // if not first time thru, did we use last key?
+ allKeys = allKeys | mod.altKey;
+ FacePtr qf = 0;
+ for ( ; fptr < m_mesh->faces; ++fptr)
+ {
+ qf = &m_mesh->faceL[fptr];
+ if ((mod.key & qf->smoothing) && !processed.contains(qf))
+ break;
+ }
+ if (fptr == m_mesh->faces)
+ break;
+ queue.append(qf);
+ if (!mod.keyFresh)
+ {
+ nextUnusedKey(&mod, allKeys);
+ if (mod.disabled)
+ break;
+ }
+ }
+ face = queue.at(head++);
+ processed.insert(face);
+ doNormalCorrect(face);
+ doModulate(face, &mod);
+ FacePtr *n = reinterpret_cast<FacePtr*>(face->user.p);
+ for ( ; *n; ++n)
+ if ((mod.key & (*n)->smoothing) && !processed.contains(*n))
+ queue.append(*n);
+ }
+ }
+ if ((m_options & QGL::CorrectNormals) && (m_options & QGL::ShowWarnings))
+ qDebug() << "CorrectNormals mode:" << numCorrected << "normals corrected.";
+ if ((m_options & QGL::CorrectAcute) && (m_options & QGL::ShowWarnings))
+ qDebug() << "CorrectAcute mode:" << mod.numModulated << "normals corrected";
+}
+
+int QGL3dsMesh::cachedMaterialLookup(const char *material)
+{
+ static bool initialized = false;
+ static int lastLookup = -1;
+ static char lastName[512];
+ if (!initialized)
+ {
+ ::memset(lastName, 0, 512);
+ initialized = true;
+ }
+ if (qstrncmp(lastName, material, 510) != 0)
+ {
+ lastLookup = sceneNode()->palette()->indexOf(QString::fromLatin1(material));
+ qstrncpy(lastName, material, 510);
+ }
+ return lastLookup;
+}
+
+/*!
+ \internal
+ Find material indexes and smoothing groups used in this mesh. If any
+ face has no material assigned then a -1 index will be listed.
+ Also figures out how complex the mesh is, by finding the count of
+ smoothing groups for the material with the greatest number of groups.
+ If the mesh is faceted (no smoothing) but has greater than FACETED_THRESHOLD
+ faces then smoothing is forced on and the mesh rescanned.
+
+*/
+void QGL3dsMesh::analyzeMesh()
+{
+ QGLMaterialCollection *pal = sceneNode()->palette();
+ Lib3dsFace *face;
+ Lib3dsDword allKeys = 0;
+ m_smoothingGroupCount = 0;
+ m_hasZeroSmoothing = false;
+ m_plainMaterials.clear();
+ m_textureMaterials.clear();
+ for (Lib3dsDword f = 0; f < m_mesh->faces; ++f)
+ {
+ face = &m_mesh->faceL[f];
+ int matIx = cachedMaterialLookup(face->material);
+#ifndef QT_NO_DEBUG_STREAM
+ if (matIx == -1 && strlen(face->material) != 0 && (m_options & QGL::ShowWarnings))
+ qDebug("Bad .3ds file: no material %s! (Referenced in mesh %s)\n",
+ face->material, m_mesh->name);
+#endif
+ if (face->smoothing)
+ {
+ if ((face->smoothing & allKeys) != face->smoothing)
+ {
+ Lib3dsDword key = 1;
+ while (key)
+ {
+ if ((key & face->smoothing) && !(allKeys & key))
+ {
+ allKeys = allKeys | key;
+ m_smoothingGroupCount += 1;
+ }
+ key <<= 1;
+ }
+ }
+ }
+ else
+ {
+ m_hasZeroSmoothing = true;
+ }
+ if (!m_plainMaterials.contains(matIx) && !m_textureMaterials.contains(matIx))
+ {
+ QGLMaterial *mat = pal->material(matIx);
+ if (mat && mat->texture())
+ m_textureMaterials.insert(matIx);
+ else
+ m_plainMaterials.insert(matIx);
+ }
+ }
+ m_smoothingGroups = allKeys;
+}
+
+/*!
+ \internal
+ Check the meshes textures and update the record of whether this mesh
+ has textures or not. In debug mode issue a warning if the textures are
+ corrupt (number of texels and vertices not equal).
+*/
+void QGL3dsMesh::checkTextures(int material)
+{
+ QGLMaterial *mat = sceneNode()->palette()->material(material);
+ QGLTexture2D *tex = (mat ? mat->texture() : 0);
+ m_hasTextures = false;
+ if (tex)
+ {
+ m_hasTextures = true;
+#ifndef QT_NO_DEBUG_STREAM
+ if (m_mesh->points != m_mesh->texels)
+ qWarning("Mesh %s has unequal number of texels (%d) and vertices (%d)",
+ m_mesh->name, m_mesh->texels, m_mesh->points);
+#endif
+ // all texture coordinates from 3ds have to be flipped because
+ // 3ds uses the correct coordinate system, whilst qt uses
+ // upside-down coordinates
+ m_texFlip = (tex->bindOptions() & QGLContext::InvertedYBindOption) == 0;
+ }
+}
+
+/*!
+ \internal
+ Returns any local transformation matrix for the mesh.
+*/
+QMatrix4x4 QGL3dsMesh::meshMatrix() const
+{
+ Lib3dsMatrix &m = m_mesh->matrix; // typedef for float[4][4]
+ QMatrix4x4 mat;
+ for (int col = 0; col < 4; ++col)
+ for (int row = 0; row < 4; ++row) {
+ float e = m[col][row];
+ if (qFuzzyIsNull(e))
+ mat(row, col) = 0.0f;
+ else
+ mat(row, col) = e;
+ }
+ mat.optimize(); // setup to use optimizations
+ if (mat.isIdentity())
+ return mat;
+ // The reverse transform is what we apply to model-view in order
+ // to draw the underlying geometry
+ bool invertible = true;
+ mat = mat.inverted(&invertible);
+ if (invertible)
+ return mat;
+ if (m_options & QGL::ShowWarnings)
+ qWarning("Could not invert matrix for mesh %s", m_mesh->name);
+ return QMatrix4x4();
+}
+
+/*!
+ \internal
+ Generate the vertices for the faces based on their smoothing keys and
+ the current nodes material.
+*/
+void QGL3dsMesh::generateVertices()
+{
+ int matIx = currentNode()->materialIndex();
+ int keyCount = m_smoothingGroupCount;
+ if (m_hasZeroSmoothing)
+ ++keyCount;
+ QString baseName = currentNode()->objectName();
+ Lib3dsDword key = 0;
+ while (key <= m_smoothingGroups)
+ {
+ if ((key & m_smoothingGroups) || ((key == 0) && m_hasZeroSmoothing))
+ {
+ if (key == 0)
+ currentSection()->setSmoothing(QGL::Faceted);
+ keyCount -= 1;
+ currentNode()->setMaterialIndex(matIx);
+ currentNode()->setObjectName(baseName + QLatin1String("::") + QString::number(key));
+ QGeometryData tri;
+ int cur = 0;
+ for (Lib3dsDword f = 0; f < m_mesh->faces; ++f)
+ {
+ Lib3dsFace *face = &m_mesh->faceL[f];
+ int faceMat = cachedMaterialLookup(face->material);
+ if (faceMat == matIx &&
+ ((key & face->smoothing) || (key == 0 && face->smoothing == 0)))
+ {
+ QVector3D norm = l2v(face->normal);
+ for (int i = 0; i < 3; ++i)
+ {
+ int a = face->points[i];
+ Lib3dsVector &l3a = m_mesh->pointL[a].pos;
+ tri.appendVertex(l2v(l3a));
+ tri.appendNormal(norm);
+ if (m_hasTextures)
+ {
+ Lib3dsTexel &t0 = m_mesh->texelL[a];
+ tri.appendTexCoord(QVector2D(t0[0], m_texFlip ? 1.0f - t0[1] : t0[1]));
+ }
+ if (m_options & QGL::NativeIndices)
+ currentSection()->appendSmooth(tri.logicalVertexAt(cur++), a);
+ }
+ }
+ }
+ if (m_options & QGL::NativeIndices)
+ currentNode()->setCount(cur);
+ else
+ addTriangles(tri);
+ if (keyCount > 0)
+ newSection(QGL::Smooth);
+ else
+ break;
+ }
+ if (key == 0)
+ key = 1;
+ else
+ key <<= 1;
+ }
+}
diff --git a/src/plugins/sceneformats/3ds/qgl3dsmesh.h b/src/plugins/sceneformats/3ds/qgl3dsmesh.h
new file mode 100644
index 000000000..6bbd47d1c
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsmesh.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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 QGL3DSMESH_H
+#define QGL3DSMESH_H
+
+#include "qglbuilder.h"
+#include "qgl3dsscenehandler.h"
+
+#include <lib3ds/types.h>
+#include <lib3ds/mesh.h>
+
+class QGLMaterialCollection;
+class QGL3dsLoader;
+class Lib3dsMesh;
+class ModulateRecord;
+
+class QGL3dsMesh : public QGLBuilder
+{
+public:
+ explicit QGL3dsMesh(Lib3dsMesh *mesh, QGLMaterialCollection *materials);
+ virtual ~QGL3dsMesh();
+ void initialize();
+ void setOptions(QGL::ModelOptions options) { m_options = options; }
+ bool hasTexture() { return m_hasTextures; }
+
+ typedef Lib3dsFace *FacePtr;
+
+protected:
+ void analyzeMesh();
+ void modulateMesh();
+ void checkTextures(int);
+ QMatrix4x4 meshMatrix() const;
+ void generateVertices();
+
+private:
+ void processNodeForMaterial(int matIx, QGLSceneNode *node);
+ QArray<int> mapFacesToVerts(Lib3dsDword *allKeys);
+ void addToAdjacencyMap(Lib3dsFace *face, Lib3dsFace *nbr);
+ void buildAdjacencyMap(const QArray<int> &vlist);
+ int cachedMaterialLookup(const char *material);
+ void findCommonNormal(ModulateRecord *mod) const;
+ void initAdjacencyMap();
+
+ Lib3dsMesh *m_mesh;
+ bool m_hasTextures;
+ Lib3dsDword m_smoothingGroups;
+ int m_smoothingGroupCount;
+ QSet<int> m_plainMaterials;
+ QSet<int> m_textureMaterials;
+ bool m_texFlip;
+ bool m_hasZeroSmoothing;
+ FacePtr *m_faceMap;
+ QGL::ModelOptions m_options;
+};
+
+#endif // QGL3DSMESH_H
diff --git a/src/plugins/sceneformats/3ds/qgl3dsscene.cpp b/src/plugins/sceneformats/3ds/qgl3dsscene.cpp
new file mode 100644
index 000000000..9e096b30d
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsscene.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** 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 "qgl3dsscene.h"
+
+#include "qglscenenode.h"
+#include "qgl3dsmesh.h"
+#include "qgl3dsloader.h"
+
+#include <lib3ds/file.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QGL3dsScene
+ \brief The QGL3dsScene class manages and contains a 3ds scene.
+ The scene consists of a QGLSceneNode object which is the top-level node
+ and references the geometry in a 3D Studio Max ".3ds" file. That top
+ level node references sub-nodes
+*/
+
+/*!
+ \internal
+ Construct a new QGL3dsScene object using the data in the \a file,
+ and setting the given \a parent. Resources are searched for at the
+ given \a url.
+
+ The QGL3dsScene object takes ownership of the \a file.
+*/
+QGL3dsScene::QGL3dsScene(Lib3dsFile *file, QGL3dsSceneHandler *h)
+ : QGLAbstractScene(0)
+ , mFile(file)
+{
+ Q_ASSERT(h);
+ Q_ASSERT(file);
+ QGL3dsLoader loader(file, h);
+ mRootNode = loader.loadMeshes();
+}
+
+/*!
+ \reimp
+ Destroy this QGL3dsScene, recovering all resources.
+
+ This method destroys the Lib3dsFile object the scene is based
+ on by calling the appropriate lib3ds function.
+*/
+QGL3dsScene::~QGL3dsScene()
+{
+ lib3ds_file_free(mFile);
+}
+
+/*!
+ \internal
+ \reimp
+*/
+QList<QObject *> QGL3dsScene::objects() const
+{
+ QList<QObject *> objs;
+ if (!mRootNode)
+ return objs;
+ objs.append(mRootNode);
+ QList<QGLSceneNode*> children = mRootNode->allChildren();
+ QList<QGLSceneNode*>::const_iterator it = children.constBegin();
+ for ( ; it != children.constEnd(); ++it)
+ objs.append(*it);
+ return objs;
+}
+
+/*!
+ \internal
+ \reimp
+*/
+QGLSceneNode *QGL3dsScene::mainNode() const
+{
+ return mRootNode;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/3ds/qgl3dsscene.h b/src/plugins/sceneformats/3ds/qgl3dsscene.h
new file mode 100644
index 000000000..e47d3efcb
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsscene.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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 QGL3DSSCENE_H
+#define QGL3DSSCENE_H
+
+#include "qglabstractscene.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+#include <QtCore/qurl.h>
+
+class QGLSceneNode;
+class QGLSceneNode;
+class QGL3dsSceneHandler;
+class Lib3dsFile;
+
+class QGL3dsScene : public QGLAbstractScene
+{
+ Q_OBJECT
+public:
+ explicit QGL3dsScene(Lib3dsFile *file, QGL3dsSceneHandler *h);
+ virtual ~QGL3dsScene();
+
+ QList<QObject *> objects() const;
+ QGLSceneNode *mainNode() const;
+
+ QUrl url() const { return mUrl; }
+
+private:
+ Lib3dsFile *mFile;
+ QUrl mUrl;
+ QGLSceneNode *mRootNode;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/sceneformats/3ds/qgl3dsscenehandler.cpp b/src/plugins/sceneformats/3ds/qgl3dsscenehandler.cpp
new file mode 100644
index 000000000..bf0f9b518
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsscenehandler.cpp
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** 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 "qgl3dsscenehandler.h"
+#include "qgl3dsscene.h"
+
+#include <lib3ds/file.h>
+#include <lib3ds/io.h>
+#include <lib3ds/mesh.h>
+#include <lib3ds/node.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+struct IODevice3ds
+{
+ QIODevice *dev;
+ bool errorState;
+
+};
+
+extern "C" {
+ static Lib3dsBool qgl3ds_fileio_error_func(void *self)
+ {
+ IODevice3ds *io3d = (IODevice3ds*)self;
+ return io3d->errorState;
+ }
+
+ static long qgl3ds_fileio_seek_func(void *self, long offset, Lib3dsIoSeek origin)
+ {
+ IODevice3ds *io3d = (IODevice3ds*)self;
+ // cannot deal with sockets right now
+ Q_ASSERT(!io3d->dev->isSequential());
+ switch (origin)
+ {
+ case LIB3DS_SEEK_SET:
+ io3d->errorState = io3d->dev->seek(offset);
+ break;
+ case LIB3DS_SEEK_CUR:
+ io3d->errorState = io3d->dev->seek(io3d->dev->pos() + offset);
+ break;
+ case LIB3DS_SEEK_END:
+ io3d->errorState = io3d->dev->seek(io3d->dev->size() + offset);
+ break;
+ default:
+ Q_ASSERT(0);
+ return(0);
+ }
+ if (io3d->errorState)
+ return -1;
+ return io3d->dev->pos();
+ }
+
+ static long qgl3ds_fileio_tell_func(void *self)
+ {
+ IODevice3ds *io3d = (IODevice3ds*)self;
+ return io3d->dev->pos();
+ }
+
+ static size_t qgl3ds_fileio_read_func(void *self, void *buffer, size_t size)
+ {
+ IODevice3ds *io3d = (IODevice3ds*)self;
+ qint64 result = io3d->dev->read((char*)buffer, size);
+ io3d->errorState = (result == -1);
+ if (io3d->errorState)
+ fprintf(stderr, "3ds io error: %s\n", io3d->dev->errorString().toLocal8Bit().constData());
+ return result;
+ }
+
+ static size_t qgl3ds_fileio_write_func(void *self, const void *buffer, size_t size)
+ {
+ IODevice3ds *io3d = (IODevice3ds*)self;
+ qint64 result = io3d->dev->write((char*)buffer, size);
+ io3d->errorState = (result == -1);
+ if (io3d->errorState)
+ fprintf(stderr, "3ds io error: %s\n", io3d->dev->errorString().toLocal8Bit().constData());
+ return result;
+ }
+}
+
+static Lib3dsFile *qgl3ds_lib3ds_file_load(QIODevice *iod)
+{
+ Lib3dsFile *file;
+ Lib3dsIo *io;
+ Q_ASSERT(iod->isOpen() && iod->isReadable());
+ file = lib3ds_file_new();
+ if (!file) {
+ iod->close();
+ return(0);
+ }
+ IODevice3ds io3d;
+ io3d.dev = iod;
+ io3d.errorState = false;
+ io = lib3ds_io_new(
+ &io3d,
+ qgl3ds_fileio_error_func,
+ qgl3ds_fileio_seek_func,
+ qgl3ds_fileio_tell_func,
+ qgl3ds_fileio_read_func,
+ qgl3ds_fileio_write_func
+ );
+ if (!io) {
+ lib3ds_file_free(file);
+ iod->close();
+ return(0);
+ }
+ if (!lib3ds_file_read(file, io)) {
+ lib3ds_file_free(file);
+ iod->close();
+ return(0);
+ }
+ lib3ds_io_free(io);
+ iod->close();
+ return(file);
+}
+
+QGL3dsSceneHandler::QGL3dsSceneHandler()
+ : m_options(0)
+{
+}
+
+QGL3dsSceneHandler::~QGL3dsSceneHandler()
+{
+ // nothing to do
+}
+
+void QGL3dsSceneHandler::decodeOptions(const QString &options)
+{
+ static const char *validOptions[] = {
+ "NativeIndices",
+ "CorrectNormals",
+ "CorrectAcute",
+ "ForceSmooth",
+ "ForceFaceted",
+ "ShowWarnings"
+ };
+ static int optionKeys[] = {
+ QGL::NativeIndices,
+ QGL::CorrectNormals,
+ QGL::CorrectAcute,
+ QGL::ForceSmooth,
+ QGL::ForceFaceted,
+ QGL::ShowWarnings,
+ -1
+ };
+
+ // format: "mesh=option mesh=option option option"
+ // mesh: string name of a mesh in the file, with no spaces
+ // standalone option applies to the whole file - all meshes
+ // option: NativeIndices | CorrectNormals | CorrectAcute etc
+ QStringList opList = options.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ for (int i = 0; i < opList.count(); ++i)
+ {
+ QString op = opList.at(i);
+ QString mdl;
+ if (op.contains(QLatin1Char('=')))
+ {
+ QStringList sl = op.split(QLatin1Char('='), QString::SkipEmptyParts);
+ mdl = sl[0];
+ op = sl[1];
+ }
+ int k = 0;
+ for ( ; optionKeys[k] != -1; ++k)
+ if (op == QLatin1String(validOptions[k]))
+ break;
+ if (optionKeys[k] != -1) // found
+ {
+ QGL::ModelOptions o = static_cast<QGL::ModelOptions>(optionKeys[k]);
+ if (!mdl.isEmpty())
+ setMeshOptions(o, mdl);
+ else
+ setOptions(o);
+ }
+ else
+ {
+ qWarning("Bad option: \"%s\" in %s", qPrintable(op),
+ qPrintable(options));
+ }
+ }
+}
+
+QGLAbstractScene *QGL3dsSceneHandler::read()
+{
+ Lib3dsFile *file = qgl3ds_lib3ds_file_load(device());
+ Q_CHECK_PTR(file); // wtf?
+
+ if (!file->nodes)
+ {
+ Lib3dsMesh *mesh;
+ Lib3dsNode *node;
+ for (mesh = file->meshes; mesh; mesh = mesh->next)
+ {
+ if (mesh->faces && mesh->points)
+ {
+ node = lib3ds_node_new_object();
+ qstrcpy(node->name, mesh->name);
+ node->parent_id = LIB3DS_NO_PARENT;
+ lib3ds_file_insert_node(file, node);
+ }
+ }
+ }
+
+ lib3ds_file_eval(file, 0.0f);
+
+ QGL3dsScene *scene = new QGL3dsScene(file, this);
+ return scene;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/3ds/qgl3dsscenehandler.h b/src/plugins/sceneformats/3ds/qgl3dsscenehandler.h
new file mode 100644
index 000000000..92cf6ff4b
--- /dev/null
+++ b/src/plugins/sceneformats/3ds/qgl3dsscenehandler.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 QGL3DSSCENEHANDLER_H
+#define QGL3DSSCENEHANDLER_H
+
+#include "qglsceneformatplugin.h"
+#include <QtCore/qmap.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QGL {
+ enum ModelOption
+ {
+ NativeIndices = 0x01,
+ CorrectNormals = 0x02,
+ CorrectAcute = 0x04,
+ ForceSmooth = 0x08,
+ ForceFaceted = 0x10,
+ ShowWarnings = 0x20
+ };
+ Q_DECLARE_FLAGS(ModelOptions, ModelOption);
+
+ typedef QMap<QString, QGL::ModelOptions> MeshOptionMap;
+};
+
+class QGL3dsSceneHandler : public QGLSceneFormatHandler
+{
+public:
+ QGL3dsSceneHandler();
+ ~QGL3dsSceneHandler();
+
+ QGLAbstractScene *read();
+
+ void setOptions(QGL::ModelOptions options) { m_options |= options; }
+ QGL::ModelOptions options() const { return m_options; }
+
+ void setMeshOptions(QGL::ModelOptions options, const QString &meshName)
+ {
+ m_meshOptions[meshName] |= options;
+ }
+ QGL::ModelOptions meshOptions(const QString &meshName) const
+ {
+ if (m_meshOptions.contains(meshName))
+ return m_meshOptions.value(meshName);
+ return 0;
+ }
+ QGL::MeshOptionMap meshOptions() const { return m_meshOptions; }
+ void decodeOptions(const QString &options);
+
+private:
+ QGL::ModelOptions m_options;
+ QGL::MeshOptionMap m_meshOptions;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGL::ModelOptions);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/sceneformats/assimp/README.txt b/src/plugins/sceneformats/assimp/README.txt
new file mode 100644
index 000000000..cabf1bdd8
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/README.txt
@@ -0,0 +1,12 @@
+This importer uses the Asset Importer library available from:
+
+http://assimp.sourceforge.net/
+
+Copyright (c) 2008-2010 ASSIMP Development Team
+All rights reserved.
+
+For convenience a stripped down source tree is included in this distribution. See the license
+included at $QT3D_SOURCE/3rdparty/assimp/LICENCE, or at http://assimp.sourceforge.net/main_license.html
+
+To use your own build of AssImp, modify the assimp.pro file and/or export the environment variables
+specified there.
diff --git a/src/plugins/sceneformats/assimp/ailoaderiostream.cpp b/src/plugins/sceneformats/assimp/ailoaderiostream.cpp
new file mode 100644
index 000000000..0ee44863f
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/ailoaderiostream.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** 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 "ailoaderiostream.h"
+
+#include <QtCore/qiodevice.h>
+
+#include <QtCore/qdebug.h>
+
+AiLoaderIOStream::AiLoaderIOStream(QIODevice *device)
+ : m_device(device)
+ , m_errorState(false)
+{
+ Q_ASSERT(device);
+}
+
+AiLoaderIOStream::~AiLoaderIOStream()
+{
+ // Nothing to do here
+}
+
+size_t AiLoaderIOStream::Read( void* pvBuffer, size_t pSize, size_t pCount)
+{
+ qint64 result = m_device->read((char*)pvBuffer, pSize * pCount);
+ size_t res = result;
+ m_errorState = (result == -1);
+ if (m_errorState)
+ fprintf(stderr, "AI read error: %s\n", qPrintable(m_device->errorString()));
+ if ((pSize * pCount) != res) // AI will treat as error
+ {
+ fprintf(stderr, "read mismatch requested size: %lu x count: %lu = %lu != %lu actuall read\n",
+ pSize, pCount, (pSize * pCount), res);
+ }
+ return res;
+}
+
+size_t AiLoaderIOStream::Write( const void* pvBuffer, size_t pSize, size_t pCount)
+{
+ qint64 result = m_device->write((char*)pvBuffer, pSize * pCount);
+ m_errorState = (result == -1);
+ if (m_errorState)
+ fprintf(stderr, "AI write error: %s\n", qPrintable(m_device->errorString()));
+ return result;
+}
+
+aiReturn AiLoaderIOStream::Seek(size_t pOffset, aiOrigin pOrigin)
+{
+ // cannot deal with sockets right now
+ Q_ASSERT(!m_device->isSequential());
+ switch (pOrigin)
+ {
+ case aiOrigin_SET:
+ m_errorState = m_device->seek(pOffset);
+ break;
+ case aiOrigin_CUR:
+ m_errorState = m_device->seek(m_device->pos() + pOffset);
+ break;
+ case aiOrigin_END:
+ m_errorState = m_device->seek(m_device->size() + pOffset);
+ break;
+ default:
+ Q_ASSERT(0);
+ return(aiReturn_FAILURE);
+ }
+ if (m_errorState)
+ return aiReturn_FAILURE;
+ return aiReturn_SUCCESS;
+}
+
+size_t AiLoaderIOStream::Tell() const
+{
+ return m_device->pos();
+}
+
+size_t AiLoaderIOStream::FileSize() const
+{
+ return m_device->size();
+}
+
+void AiLoaderIOStream::Flush()
+{
+ // do nothing
+}
diff --git a/src/plugins/sceneformats/assimp/ailoaderiostream.h b/src/plugins/sceneformats/assimp/ailoaderiostream.h
new file mode 100644
index 000000000..be3172bb2
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/ailoaderiostream.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 AILOADERIOSTREAM_H
+#define AILOADERIOSTREAM_H
+
+#include "IOStream.h"
+#include "IOSystem.h"
+
+class QIODevice;
+
+class AiLoaderIOStream : public Assimp::IOStream
+{
+public:
+ AiLoaderIOStream(QIODevice *device);
+ ~AiLoaderIOStream();
+ size_t Read( void* pvBuffer, size_t pSize, size_t pCount);
+ size_t Write( const void* pvBuffer, size_t pSize, size_t pCount);
+ aiReturn Seek( size_t pOffset, aiOrigin pOrigin);
+ size_t Tell() const;
+ size_t FileSize() const;
+ void Flush();
+ QIODevice *device() const { return m_device; }
+private:
+ QIODevice *m_device;
+ bool m_errorState;
+};
+
+#endif // AILOADERIOSTREAM_H
diff --git a/src/plugins/sceneformats/assimp/ailoaderiosystem.cpp b/src/plugins/sceneformats/assimp/ailoaderiosystem.cpp
new file mode 100644
index 000000000..b31f275d0
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/ailoaderiosystem.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** 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 "ailoaderiosystem.h"
+#include "ailoaderiostream.h"
+#include "DefaultLogger.h"
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdir.h>
+
+AiLoaderIOSystem::AiLoaderIOSystem(QIODevice *device, QUrl url)
+ : m_device(device)
+ , m_url(url)
+{
+}
+
+AiLoaderIOSystem::~AiLoaderIOSystem()
+{
+ // we don't own m_device
+ qDeleteAll(m_sub);
+}
+
+bool AiLoaderIOSystem::Exists(const char* path) const
+{
+ return QFile::exists(QLatin1String(path));
+}
+
+char AiLoaderIOSystem::getOsSeparator() const
+{
+ return QDir::separator().toLatin1();
+}
+
+/*!
+ \internal
+ Open the pFile with the pMode, where mode is given by "man fopen"
+*/
+Assimp::IOStream* AiLoaderIOSystem::Open(const char* pFile, const char* pMode)
+{
+ // This is just the file already opened on the device
+ if (m_url.toEncoded().endsWith(pFile))
+ return new AiLoaderIOStream(m_device);
+
+ // New relative file
+ QUrl rel;
+ rel.setScheme(m_url.scheme());
+ rel.setPath(QLatin1String(pFile));
+ QUrl url = m_url.resolved(rel);
+
+ // TODO: handle network case
+ if (url.scheme() != QLatin1String("file"))
+ {
+ qWarning("Opening %s url not supported", qPrintable(url.scheme()));
+ return 0;
+ }
+
+ char mode_str[4];
+ qMemSet(mode_str, '\0', 4);
+ int i = 0;
+ for (const char *ptr = pMode; i < 4 && *ptr; ++ptr)
+ {
+ if (*ptr != 'b') // ignore the binary attribute
+ mode_str[i++] = *ptr;
+ }
+ QIODevice::OpenMode mode = QIODevice::NotOpen;
+ if (::strncmp("r", mode_str, 1) == 0)
+ {
+ mode = QIODevice::ReadOnly;
+ }
+ else if (::strncmp("r+", mode_str, 2) == 0)
+ {
+ mode = QIODevice::ReadWrite;
+ }
+ else if (::strncmp("w", mode_str, 1) == 0)
+ {
+ mode = QIODevice::WriteOnly | QIODevice::Truncate;
+ }
+ else if (::strncmp("w+", mode_str, 2) == 0)
+ {
+ mode = QIODevice::ReadWrite | QIODevice::Truncate;
+ }
+ else if (::strncmp("a", mode_str, 1) == 0)
+ {
+ mode = QIODevice::WriteOnly | QIODevice::Append;
+ }
+ else if (::strncmp("a+", mode_str, 2) == 0)
+ {
+ mode = QIODevice::ReadWrite | QIODevice::Append;
+ }
+ else
+ {
+ std::string err("Error: invalid mode flag:");
+ err.append(mode_str).append(" when opening ").append(pFile);
+ Assimp::DefaultLogger::get()->warn(err);
+ return 0;
+ }
+
+ QFile *f = new QFile(url.toLocalFile());
+ bool res = f->open(mode);
+ if (!res)
+ {
+ std::string err("Error: could not open subsequent file:");
+ err.append(pFile).append("--").append(f->errorString().toStdString());
+ Assimp::DefaultLogger::get()->warn(err);
+ delete f;
+ return 0;
+ }
+ m_sub.append(f);
+ AiLoaderIOStream *s = new AiLoaderIOStream(f);
+ return s;
+}
+
+void AiLoaderIOSystem::Close(Assimp::IOStream* stream)
+{
+ AiLoaderIOStream *s = static_cast<AiLoaderIOStream*>(stream);
+ Q_ASSERT(s);
+ s->device()->close();
+ delete stream;
+}
diff --git a/src/plugins/sceneformats/assimp/ailoaderiosystem.h b/src/plugins/sceneformats/assimp/ailoaderiosystem.h
new file mode 100644
index 000000000..8df0a3c75
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/ailoaderiosystem.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 AILOADERIOSYSTEM_H
+#define AILOADERIOSYSTEM_H
+
+#include "IOSystem.h"
+
+#include <QtCore/qurl.h>
+
+class QIODevice;
+class IOStream;
+
+class AiLoaderIOSystem : public Assimp::IOSystem
+{
+public:
+ AiLoaderIOSystem(QIODevice *device, QUrl url);
+ ~AiLoaderIOSystem();
+ virtual bool Exists( const char* path) const;
+ virtual char getOsSeparator() const;
+ virtual Assimp::IOStream* Open(const char* pFile, const char* pMode = "rb");
+ virtual void Close(Assimp::IOStream* pFile);
+private:
+ QIODevice *m_device;
+ QList<QIODevice*> m_sub;
+ QUrl m_url;
+};
+
+#endif // AILOADERIOSYSTEM_H
diff --git a/src/plugins/sceneformats/assimp/assimp.pro b/src/plugins/sceneformats/assimp/assimp.pro
new file mode 100644
index 000000000..43b74363e
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/assimp.pro
@@ -0,0 +1,32 @@
+TARGET = qsceneai
+include(../../qpluginbase.pri)
+HEADERS += qailoader.h \
+ qaiscene.h \
+ qaiscenehandler.h \
+ qaimesh.h \
+ ailoaderiostream.h \
+ ailoaderiosystem.h
+SOURCES += main.cpp \
+ qailoader.cpp \
+ qaiscene.cpp \
+ qaiscenehandler.cpp \
+ qaimesh.cpp \
+ ailoaderiostream.cpp \
+ ailoaderiosystem.cpp
+CONFIG += qt3d
+system_ai {
+ !isEmpty(QMAKE_INCDIR_AI):INCLUDEPATH += $$QMAKE_INCDIR_AI
+ !isEmpty(QMAKE_LIBDIR_AI):LIBS += -L$$QMAKE_LIBDIR_AI
+
+ !isEmpty(QMAKE_LIBS_AI):LIBS += -l$$QMAKE_LIBS_AI
+ else {
+ win32:LIBS += -llibai-1_3
+ else:LIBS += -lai
+ }
+} else {
+ include(../../../../3rdparty/assimp/assimp.pri)
+}
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/sceneformats
+target.path += $$[QT_INSTALL_PLUGINS]/sceneformats
+INSTALLS += target
diff --git a/src/plugins/sceneformats/assimp/main.cpp b/src/plugins/sceneformats/assimp/main.cpp
new file mode 100644
index 000000000..7251e4627
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/main.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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 "qglsceneformatplugin.h"
+#include "qaiscenehandler.h"
+
+#include "assimp.hpp"
+
+#include <QtCore/qmap.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAiScenePlugin : public QGLSceneFormatPlugin
+{
+public:
+ QStringList keys() const;
+ virtual QGLSceneFormatHandler *create(QIODevice *device, const QUrl& url, const QString &format) const;
+};
+
+QStringList QAiScenePlugin::keys() const
+{
+ static QMultiMap<QString, QString> mimetypes;
+ if (mimetypes.size() == 0)
+ {
+ mimetypes.insertMulti("3ds", "application/x-3ds");
+ mimetypes.insertMulti("3ds", "image/x-3ds");
+ mimetypes.insertMulti("dae", "model/x3d+binary");
+ mimetypes.insertMulti("dxf", "application/x-dxf");
+ }
+ QStringList result;
+ Assimp::Importer importer;
+ aiString extns;
+ importer.GetExtensionList(extns);
+ QString qextns = QString::fromUtf8(extns.data, extns.length);
+ QStringList extnList = qextns.split(';');
+ for (int i = 0; i < extnList.size(); ++i)
+ {
+ QString xt = extnList.at(i);
+ xt = xt.simplified();
+ if (xt.startsWith(QLatin1String("*.")))
+ xt = xt.mid(2);
+ result << xt;
+ QMap<QString, QString>::const_iterator it = mimetypes.constFind(xt);
+ for ( ; it != mimetypes.constEnd(); ++it)
+ result << it.value();
+ }
+ return result;
+}
+
+QGLSceneFormatHandler *QAiScenePlugin::create(QIODevice *device, const QUrl& url, const QString &format) const
+{
+ Q_UNUSED(device);
+ Q_UNUSED(url);
+ Q_UNUSED(format);
+ return new QAiSceneHandler;
+}
+
+Q_EXPORT_STATIC_PLUGIN(QAiScenePlugin)
+Q_EXPORT_PLUGIN2(qsceneai, QAiScenePlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/assimp/qailoader.cpp b/src/plugins/sceneformats/assimp/qailoader.cpp
new file mode 100644
index 000000000..18ba1e172
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qailoader.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** 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 "qailoader.h"
+#include "qaiscenehandler.h"
+#include "qaiscene.h"
+#include "qaimesh.h"
+
+#include "qgeometrydata.h"
+#include "qgltwosidedmaterial.h"
+#include "qglmaterial.h"
+#include "qglmaterialcollection.h"
+#include "qglpainter.h"
+#include "qgltexture2d.h"
+#include "qglscenenode.h"
+#include "qlogicalvertex.h"
+
+#include "aiScene.h"
+#include "aiMaterial.h"
+#include "aiMesh.h"
+#include "DefaultLogger.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qfileinfo.h>
+
+QAiLoader::QAiLoader(const aiScene *scene, QAiSceneHandler* handler)
+ : m_scene(scene)
+ , m_root(0)
+ , m_handler(handler)
+ , m_hasTextures(false)
+ , m_hasLitMaterials(false)
+ , m_builder(new QGLMaterialCollection(m_root))
+{
+}
+
+QAiLoader::~QAiLoader()
+{
+ // nothing to do here - m_rootNode is taken ownership of by caller of
+ // rootNode() method
+}
+
+static inline void assertOnePrimitiveType(aiMesh *mesh)
+{
+#ifndef QT_NO_DEBUG
+ int k = 0; // count the number of bits set in the primitives
+ unsigned int msk = 0x01;
+ for (unsigned int p = mesh->mPrimitiveTypes; p; p >>= 1)
+ if (p & msk)
+ ++k;
+ Q_ASSERT(k == 1); // Assimp SortByPType promises this
+#else
+ Q_UNUSED(mesh);
+#endif
+}
+
+static inline bool qHasTextures(const QGLSceneNode *node)
+{
+ QGLMaterial *mat = node->material();
+ for (int i = 0; i < mat->textureLayerCount(); ++i)
+ if (node->material()->texture(i))
+ return true;
+ return false;
+}
+
+void QAiLoader::loadMesh(aiMesh *mesh)
+{
+ QString name = QString::fromUtf8(mesh->mName.data, mesh->mName.length);
+ // qDebug() << "loadMesh" << name << "with" << mesh->mNumVertices << "vertices"
+ // << "and" << mesh->mNumFaces << "faces";
+
+ assertOnePrimitiveType(mesh);
+
+ if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)
+ {
+ m_builder.newSection();
+ QGLSceneNode *node = m_builder.currentNode();
+ node->setObjectName(name);
+ QAiMesh m(mesh);
+ m.build(m_builder, m_handler->showWarnings());
+ m_meshes.append(node);
+ if (qHasTextures(node))
+ m_hasTextures = true;
+ else
+ m_hasLitMaterials = true;
+ }
+ else
+ {
+ // TODO: Implement other types in qaimesh.cpp
+ if (m_handler->showWarnings())
+ {
+ QString error = QLatin1String("Bad primitive type in mesh %1 : %2");
+ error = error.arg(name).arg(mesh->mPrimitiveTypes);
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ }
+ }
+
+ if (m_handler->showWarnings())
+ {
+ if (!(m_handler->removeComponentFlags() & aiComponent_COLORS))
+ {
+ // TODO: Implement models with per vertex colors. Ok, the
+ // vertex colors were wanted but are not supported yet.
+ for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i)
+ {
+ if (mesh->HasVertexColors(i))
+ {
+ QString error = QLatin1String(
+ "Found color information in mesh %1, channel %2"
+ "- per vertex color not yet supported");
+ error = error.arg(name).arg(i);
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ break;
+ }
+ }
+ }
+ if (mesh->HasBones())
+ {
+ // TODO: Implement skeletal animation
+ QString error = QLatin1String("Bones in mesh %1 not yet supported");
+ error.arg(name);
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ }
+ if (mesh->HasTangentsAndBitangents())
+ {
+ // TODO: Implement normal maps - here and in the texture import
+ QString error = QLatin1String("Tangents for normal map in mesh %1 not yet supported");
+ error.arg(name);
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ }
+ }
+}
+
+inline static QMatrix4x4 getNodeMatrix(aiNode *node)
+{
+ QMatrix4x4 nodeMatrix;
+ if (node->mTransformation.IsIdentity())
+ return nodeMatrix;
+ aiQuaternion rotation;
+ aiVector3D position;
+ aiVector3D scale;
+ node->mTransformation.Decompose(scale, rotation, position);
+ QVector3D qscale(scale.x,scale.y, scale.z);
+ QVector3D qposition(position.x, position.y, position.z);
+ QQuaternion qrotation(rotation.w, rotation.x, rotation.y, rotation.z);
+ if (!qscale.isNull())
+ nodeMatrix.scale(qscale);
+ if (!qposition.isNull())
+ nodeMatrix.translate(qposition);
+ if (!qrotation.isNull())
+ nodeMatrix.rotate(qrotation);
+ return nodeMatrix;
+}
+
+void QAiLoader::loadNodes(aiNode *nodeList, QGLSceneNode *parentNode)
+{
+ QMap<aiNode *, QGLSceneNode *>::const_iterator it = m_nodeMap.constFind(nodeList);
+ QGLSceneNode *node = 0;
+ if (it == m_nodeMap.constEnd()) // not found
+ {
+ node = new QGLSceneNode(parentNode);
+ m_nodes.append(node);
+ QString name = QString::fromUtf8(nodeList->mName.data, nodeList->mName.length);
+ if (name.isEmpty())
+ name = QString(QLatin1String("aiNode %1")).arg(m_nodes.size());
+ node->setObjectName(name);
+ QMatrix4x4 mat = getNodeMatrix(nodeList);
+ if (!mat.isIdentity())
+ node->setLocalTransform(mat);
+ for (unsigned int i = 0; i < nodeList->mNumChildren; ++i)
+ loadNodes(nodeList->mChildren[i], node);
+ for (unsigned int i = 0; i < nodeList->mNumMeshes; ++i)
+ {
+ int n = nodeList->mMeshes[i];
+ if (n < m_meshes.size())
+ node->addNode(m_meshes.at(n));
+ }
+ }
+ else
+ {
+ node = it.value();
+ parentNode->addNode(node);
+ }
+}
+
+/*!
+ \internal
+ Loads all the geometry, materials, and texture associations from the assigned
+ file, and returns the root node of the resulting scene graph.
+
+ The caller must take ownership of the root node returned, and delete it
+ when its no longer required.
+*/
+QGLSceneNode *QAiLoader::loadMeshes()
+{
+ Q_ASSERT(m_scene);
+ for (unsigned int i = 0; i < m_scene->mNumMaterials; ++i)
+ loadMaterial(m_scene->mMaterials[i]);
+
+ // builds a naive scene heierarchy with all meshes under the root node
+ for (unsigned int i = 0; i < m_scene->mNumMeshes; ++i)
+ loadMesh(m_scene->mMeshes[i]);
+
+ // fetch the naive scene heierarchy from the builder
+ m_root = m_builder.finalizedSceneNode();
+
+ QString name = m_handler->url().path();
+ int pos = name.lastIndexOf("/");
+ if (pos == -1)
+ pos = name.lastIndexOf("\\");
+ if (pos != -1)
+ name = name.mid(pos+1);
+ m_root->setObjectName(name);
+
+ // if scene has a node heierarchy replace the naive heierarchy with that
+ if (m_scene->mRootNode->mNumChildren > 0 && m_scene->mRootNode->mChildren)
+ {
+ m_root->removeNodes(m_root->children());
+ loadNodes(m_scene->mRootNode, m_root);
+ }
+
+ if (m_hasTextures) // make textures the default
+ {
+ m_root->setEffect(QGL::LitModulateTexture2D);
+ if (m_hasLitMaterials)
+ {
+ for (int i = 0; i < m_meshes.size(); ++i)
+ if (!qHasTextures(m_meshes.at(i)))
+ m_meshes.at(i)->setEffect(QGL::LitMaterial);
+ }
+ }
+ else
+ {
+ m_root->setEffect(QGL::LitMaterial);
+ }
+
+ if (m_handler->showWarnings())
+ {
+ QString message = QLatin1String("AssetImporter loader %1 -- "
+ "Mesh count: %2 -- Node count: %3 -- "
+ "Material count: %4");
+ QUrl url = m_handler->url();
+ message = message.arg(url.toString()).arg(m_meshes.size())
+ .arg(m_nodes.size()).arg(m_root->palette()->size());
+ Assimp::DefaultLogger::get()->warn(message.toStdString());
+ }
+
+//#define DEBUG_ME
+#ifdef DEBUG_ME
+ qDumpScene(m_root);
+
+ QList<QGLSceneNode*> c = m_root->allChildren();
+ QSet<quint64> debugged;
+ for (int i = 0; i < c.size(); ++i)
+ {
+ if (c.at(i)->geometry().count() > 0)
+ {
+ QGeometryData g = c.at(i)->geometry();
+ qDebug() << "geometry for:" << c.at(i) << "is:" << g.id();
+ if (!debugged.contains(g.id()))
+ {
+ qDebug() << g;
+ debugged.insert(g.id());
+ }
+ }
+ }
+#endif
+
+ return m_root;
+}
+
+/*!
+ \internal
+ Search for a resource based on the given \a path.
+
+ If the URL for the currently loading mesh has a scheme other than
+ "file" then a URL with the path relative to that URL is returned.
+
+ If the URL for the currently loading mesh has a "file" scheme, then
+ first a case-sensitive search is done of all of the current directory,
+ and the :/ resource directory, and the directory of the current mesh
+ file.
+
+ If the file is not found in any of those locations then they are
+ searched again case-insensitively. If the file is found, then a
+ URL based on the absolute file path of the matching file is returned.
+
+ Otherwise an empty string is returned.
+*/
+QUrl QAiLoader::ensureResource(const QString &path)
+{
+ QUrl res;
+ QUrl base = m_handler->url();
+ if (base.scheme() == QLatin1String("file"))
+ {
+ res = base.resolved(path);
+ //qDebug() << "ensureResource - base:" << base
+ // << " -- path:" << path << "-- resolved:" << res;
+ if (QFile::exists(res.path())) // shortcut common case
+ return res;
+ QStringList paths;
+ paths << QLatin1String(".") << QLatin1String(":/"); // current directory and aliased/root resource file
+ if (!base.isEmpty())
+ {
+ QFileInfo fi(base.path());
+ paths.prepend(fi.absoluteDir().absolutePath());
+ }
+ bool caseInsensitive = false;
+ do {
+ QStringList::const_iterator it(paths.begin());
+ for ( ; it != paths.end(); ++it)
+ {
+ QDir resDir(*it);
+ QStringList fileList = resDir.entryList(QDir::Files);
+ if (caseInsensitive)
+ {
+ QStringList::const_iterator fit(fileList.begin());
+ for ( ; fit != fileList.end(); ++fit)
+ {
+ if (fit->toLower() == path.toLower())
+ {
+ res.setScheme(QLatin1String("file"));
+ res.setPath(resDir.absoluteFilePath(*fit));
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (fileList.contains(path))
+ {
+ //return resDir.absoluteFilePath(path);
+ res.setScheme(QLatin1String("file"));
+ res.setPath(resDir.absoluteFilePath(path));
+ break;
+ }
+ }
+ }
+ if (caseInsensitive)
+ break;
+ caseInsensitive = true;
+ } while (true);
+ }
+ else
+ {
+ // non-file url
+ res = base.resolved(path);
+ }
+ return res;
+}
+
+void QAiLoader::loadTextures(aiMaterial *ma, QGLMaterial *mq)
+{
+ int texCount;
+ aiTextureType texType;
+ if (m_handler->showWarnings())
+ {
+ // TODO: AssImp has a very rich set of texture related functionality
+ // but until things in this list get implemented, all are just going
+ // to get ignored, tho' they will generate a warning in verbose mode.
+ // So for now, its just inside this conditional - move it out once
+ // implementation of these items begins.
+ static const char * typeNames[] = {
+ "None",
+ "Diffuse",
+ "Specular",
+ "Ambient",
+ "Emissive",
+ "Height",
+ "Normals",
+ "Shininess",
+ "Opacity",
+ "Displacement",
+ "Lightmap",
+ "Reflection",
+ "Unknown",
+ 0
+ };
+
+ for (unsigned int i = 0; i <= aiTextureType_UNKNOWN; ++i)
+ {
+ texType = static_cast<aiTextureType>(i);
+ texCount = ma->GetTextureCount(texType);
+ if (texCount && texType != aiTextureType_DIFFUSE)
+ {
+ QString error = QLatin1String("Unsupported texture type \"%1\" in material \"%2\".");
+ error.arg(typeNames[i]).arg(mq->objectName());
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ }
+ }
+ }
+ // TODO: For now assume the only texture we care about is the diffuse one
+ //
+ texCount = ma->GetTextureCount(aiTextureType_DIFFUSE);
+ if (texCount > 0)
+ {
+ if (texCount > 1 && m_handler->showWarnings())
+ {
+ QString error = QLatin1String("Multi-textures not supported: \"%1\" has %2");
+ error.arg(mq->objectName()).arg(texCount);
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ }
+ else
+ {
+ aiString path;
+ ma->Get(AI_MATKEY_TEXTURE_DIFFUSE(0), path);
+ QString qpath = QString::fromUtf8(path.data, path.length);
+ QUrl url = ensureResource(qpath);
+ if (url.isEmpty())
+ {
+ if (m_handler->showWarnings())
+ {
+ QString error = QLatin1String("Could not load texture: %1 for material %2");
+ error.arg(url.toString()).arg(mq->objectName());
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ }
+ }
+ else
+ {
+ mq->setTextureUrl(url);
+ }
+ }
+ }
+}
+
+/*!
+ Load a material
+*/
+void QAiLoader::loadMaterial(aiMaterial *ma)
+{
+ QGLMaterialCollection *palette = m_builder.palette();
+ QGLMaterial *mq = new QGLMaterial;
+ mq->setObjectName("___DEFAULT_NAME___");
+
+ bool isTwoSided = false;
+ bool isWireframe = false;
+ struct aiColor4D clr;
+ float shininess;
+ float amplitude;
+
+ aiReturn r;
+
+ // In AssImp if the material is two sided then it means cull face
+ // should be turned off: http://assimp.sourceforge.net/lib_html/materials.html
+ r = ma->Get(AI_MATKEY_TWOSIDED, isTwoSided);
+ if (r == aiReturn_SUCCESS && isTwoSided)
+ mq->setProperty("isTwoSided", isTwoSided);
+
+ aiString aName;
+ r = ma->Get(AI_MATKEY_NAME, aName);
+ if (r == aiReturn_SUCCESS && aName.length > 0)
+ mq->setObjectName(QLatin1String(aName.data));
+
+ r = ma->Get(AI_MATKEY_COLOR_AMBIENT, clr);
+ if (r == aiReturn_SUCCESS)
+ mq->setAmbientColor(QColor::fromRgbF(clr.r, clr.g, clr.b, clr.a));
+
+ r = ma->Get(AI_MATKEY_COLOR_DIFFUSE, clr);
+ if (r == aiReturn_SUCCESS)
+ mq->setDiffuseColor(QColor::fromRgbF(clr.r, clr.g, clr.b, clr.a));
+
+ r = ma->Get(AI_MATKEY_COLOR_SPECULAR, clr);
+ if (r == aiReturn_SUCCESS)
+ {
+ QColor spec = QColor::fromRgbF(clr.r, clr.g, clr.b, clr.a);
+ mq->setSpecularColor(spec);
+
+ // By default the specular color is black - very dark.
+ // If the specular color is bright be careful with shininess -
+ // a shininess of 0 will blow everything out to full white. So in
+ // the case of bad materials with this problem, set shiness low.
+ mq->setShininess(64.0);
+ }
+
+ r = ma->Get(AI_MATKEY_SHININESS, shininess);
+ if (r == aiReturn_SUCCESS)
+ mq->setShininess(shininess);
+
+ r = ma->Get(AI_MATKEY_SHININESS_STRENGTH, amplitude);
+ if (r == aiReturn_SUCCESS)
+ mq->setShininess(shininess * amplitude);
+
+ r = ma->Get(AI_MATKEY_ENABLE_WIREFRAME, isWireframe);
+ if (r == aiReturn_SUCCESS && isWireframe)
+ mq->setProperty("isWireFrame", isWireframe);
+
+ loadTextures(ma, mq);
+
+ // INVARIANT: since we create the palette newly in this class, and this
+ // function is the only place we add materials to this palette, the index
+ // values (the positions in the palette generated by this call to addMaterial)
+ // will exactly match the index values of the materials traversed in the
+ // for loop in loadMeshes() - so therefore AI's index values and the ones in
+ // the palette will be the same.
+ //
+ // executive summary: don't muck around with the palettte outside of this call
+
+ int k = palette->addMaterial(mq);
+
+ Q_UNUSED(k);
+ //qDebug() << "loaded material" << k << mq;
+}
diff --git a/src/plugins/sceneformats/assimp/qailoader.h b/src/plugins/sceneformats/assimp/qailoader.h
new file mode 100644
index 000000000..cb646295a
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qailoader.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 QGL3DSLOADER_H
+#define QGL3DSLOADER_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmap.h>
+
+#include "aiScene.h"
+
+#include "qglbuilder.h"
+
+class QAiMesh;
+class QGLSceneNode;
+class QAiSceneHandler;
+class QGLMaterial;
+class aiMaterial;
+
+class QAiLoader
+{
+public:
+ QAiLoader(const aiScene *scene, QAiSceneHandler* handler);
+ ~QAiLoader();
+ QGLSceneNode *loadMeshes();
+
+private:
+ void loadMesh(aiMesh *);
+ void loadNodes(aiNode *, QGLSceneNode *);
+ void loadMaterial(aiMaterial *);
+ void loadTextures(aiMaterial *, QGLMaterial *);
+ QUrl ensureResource(const QString &);
+ void optimizeData();
+ void optimizeNodes(QGLSceneNode *node = 0, QGLSceneNode *parent = 0);
+ void countChildNodeReferences();
+
+ const aiScene *m_scene;
+ QGLSceneNode *m_root;
+ QAiSceneHandler *m_handler;
+ QList<QGLSceneNode *> m_nodes;
+ QList<QGLMaterial *> m_materials;
+ QList<QGLSceneNode *> m_meshes;
+ QMap<aiNode *, QGLSceneNode *> m_nodeMap;
+ QMap<QGLSceneNode *, int> m_refCounts;
+ bool m_hasTextures;
+ bool m_hasLitMaterials;
+ QGLBuilder m_builder;
+};
+
+#endif // QGL3DSLOADER_H
diff --git a/src/plugins/sceneformats/assimp/qaimesh.cpp b/src/plugins/sceneformats/assimp/qaimesh.cpp
new file mode 100644
index 000000000..e7d801dc3
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qaimesh.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** 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 "qaimesh.h"
+#include "qglscenenode.h"
+#include "qglmaterialcollection.h"
+#include "qglbuilder.h"
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qmath.h>
+
+#include "aiMesh.h"
+#include "DefaultLogger.h"
+
+QAiMesh::QAiMesh(aiMesh *mesh)
+ : m_mesh(mesh)
+{
+}
+
+QAiMesh::~QAiMesh()
+{
+}
+
+static inline QVector2D qv2d(const aiVector3D &v)
+{
+ return QVector2D(v.x, v.y);
+}
+
+static inline QVector2D qv2d_inv(const aiVector3D &v)
+{
+ // invert the v coord because Qt is upside-down
+ return QVector2D(v.x, (1.0 - v.y));
+}
+
+static inline QVector3D qv3d(const aiVector3D &v)
+{
+ return QVector3D(v.x, v.y, v.z);
+}
+
+void QAiMesh::loadTriangles(QGLBuilder &builder)
+{
+ QGeometryData data;
+ for (unsigned int i = 0; i < m_mesh->mNumVertices; ++i)
+ data.appendVertex(qv3d(m_mesh->mVertices[i]));
+ if (m_mesh->HasNormals())
+ for (unsigned int i = 0; i < m_mesh->mNumVertices; ++i)
+ data.appendNormal(qv3d(m_mesh->mNormals[i]));
+ int k = m_mesh->GetNumUVChannels();
+ for (int t = 0; t < k; ++t)
+ {
+ if (m_mesh->mNumUVComponents[t] != 2)
+ Assimp::DefaultLogger::get()->warn("Tex co-ords only supports U & V");
+ QGLMaterial *m = builder.currentNode()->material();
+ if (m && m->textureUrl().path().endsWith(".dds", Qt::CaseInsensitive))
+ {
+ for (unsigned int i = 0; i < m_mesh->mNumVertices; ++i)
+ data.appendTexCoord(qv2d_inv(m_mesh->mTextureCoords[t][i]), static_cast<QGL::VertexAttribute>(QGL::TextureCoord0 + t));
+ }
+ else
+ {
+ for (unsigned int i = 0; i < m_mesh->mNumVertices; ++i)
+ data.appendTexCoord(qv2d(m_mesh->mTextureCoords[t][i]), static_cast<QGL::VertexAttribute>(QGL::TextureCoord0 + t));
+ }
+ }
+
+ for (unsigned int i = 0; i < m_mesh->mNumFaces; ++i)
+ {
+ aiFace *face = &m_mesh->mFaces[i];
+ data.appendIndices(face->mIndices[0], face->mIndices[1], face->mIndices[2]);
+ }
+
+ // raw triangle mode
+ builder.addTriangles(data);
+}
+
+void QAiMesh::build(QGLBuilder &builder, bool showWarnings)
+{
+ QGLSceneNode *node = builder.currentNode();
+ QString name = node->objectName();
+
+ if (!m_mesh->HasFaces() || !m_mesh->HasPositions())
+ {
+ if (showWarnings)
+ {
+ QString error = QLatin1String("Mesh %1 has zero vertex/face count");
+ error.arg(name.isEmpty() ? QString(QLatin1String("<unnamed mesh>")) : name);
+ Assimp::DefaultLogger::get()->warn(error.toStdString());
+ }
+ return;
+ }
+
+ node->setMaterialIndex(m_mesh->mMaterialIndex);
+ node->palette()->markMaterialAsUsed(m_mesh->mMaterialIndex);
+
+ if (m_mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)
+ loadTriangles(builder);
+ else
+ return; // TODO - lines, points, quads, polygons
+
+ QGLMaterial * mat = node->palette()->material(m_mesh->mMaterialIndex);
+ if (mat->property("isTwoSided").isValid() && mat->property("isTwoSided").toBool())
+ node->setBackMaterialIndex(m_mesh->mMaterialIndex);
+ if (mat->property("isWireFrame").isValid() && mat->property("isWireFrame").toBool())
+ node->setDrawingMode(QGL::Lines);
+}
diff --git a/src/plugins/sceneformats/assimp/qaimesh.h b/src/plugins/sceneformats/assimp/qaimesh.h
new file mode 100644
index 000000000..2a1efc2ed
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qaimesh.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 QGL3DSMESH_H
+#define QGL3DSMESH_H
+
+#include "qaiscenehandler.h"
+#include "qgeometrydata.h"
+
+class QGLMaterialCollection;
+class QGLSceneNode;
+class QGLBuilder;
+class QAiLoader;
+class aiMesh;
+
+class QAiMesh
+{
+public:
+ QAiMesh(aiMesh *mesh);
+ virtual ~QAiMesh();
+
+ void build(QGLBuilder &builder, bool showWarnings = false);
+private:
+ void loadTriangles(QGLBuilder &builder);
+
+ aiMesh *m_mesh;
+};
+
+#endif // QGL3DSMESH_H
diff --git a/src/plugins/sceneformats/assimp/qaiscene.cpp b/src/plugins/sceneformats/assimp/qaiscene.cpp
new file mode 100644
index 000000000..cb67fe99d
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qaiscene.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "qaiscene.h"
+#include "qaimesh.h"
+#include "qailoader.h"
+
+#include "qglscenenode.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QAiScene
+ \brief The QAiScene class manages and contains an asset importer scene.
+ The scene consists of a QGLSceneNode object which is the top-level node
+ and references the geometry imported from a file.
+*/
+
+/*!
+ \internal
+ Construct a new QAiScene object using the data in the \a scene,
+ and setting the given \a parent.
+
+ The QAiScene object takes ownership of the \a file.
+*/
+QAiScene::QAiScene(const aiScene *scene, QAiSceneHandler *handler)
+ : QGLAbstractScene(0)
+{
+ Q_ASSERT(handler);
+ Q_ASSERT(scene);
+ QAiLoader loader(scene, handler);
+ m_root = loader.loadMeshes();
+}
+
+/*!
+ \reimp
+ Destroy this QAiScene, recovering all resources.
+
+ This method destroys the Lib3dsFile object the scene is based
+ on by calling the appropriate lib3ds function.
+*/
+QAiScene::~QAiScene()
+{
+ // nothing to do here
+}
+
+/*!
+ \internal
+ \reimp
+*/
+QList<QObject *> QAiScene::objects() const
+{
+ QList<QObject *> objs;
+ if (!m_root)
+ return objs;
+ objs.append(m_root);
+ QList<QGLSceneNode*> children = m_root->allChildren();
+ QList<QGLSceneNode*>::const_iterator it = children.constBegin();
+ for ( ; it != children.constEnd(); ++it)
+ objs.append(*it);
+ return objs;
+}
+
+/*!
+ \internal
+ \reimp
+*/
+QGLSceneNode *QAiScene::mainNode() const
+{
+ return m_root;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/assimp/qaiscene.h b/src/plugins/sceneformats/assimp/qaiscene.h
new file mode 100644
index 000000000..5b9aac58c
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qaiscene.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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 QGL3DSSCENE_H
+#define QGL3DSSCENE_H
+
+#include "qglabstractscene.h"
+
+#include "aiScene.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Qt3D)
+
+#include <QtCore/qurl.h>
+
+class QGLSceneNode;
+class QAiSceneHandler;
+
+class QAiScene : public QGLAbstractScene
+{
+ Q_OBJECT
+public:
+ explicit QAiScene(const aiScene *scene, QAiSceneHandler *handler);
+ virtual ~QAiScene();
+
+ QList<QObject *> objects() const;
+ QGLSceneNode *mainNode() const;
+private:
+ QGLSceneNode *m_root;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/sceneformats/assimp/qaiscenehandler.cpp b/src/plugins/sceneformats/assimp/qaiscenehandler.cpp
new file mode 100644
index 000000000..259bf9021
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qaiscenehandler.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** 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 "qaiscenehandler.h"
+#include "qaiscene.h"
+#include "ailoaderiosystem.h"
+
+#include "aiScene.h"
+#include "aiPostProcess.h"
+#include "DefaultLogger.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qdebug.h>
+
+
+#define qAiPostProcessPreset ( \
+ aiProcess_CalcTangentSpace | \
+ aiProcess_GenSmoothNormals | \
+ aiProcess_JoinIdenticalVertices | \
+ aiProcess_ImproveCacheLocality | \
+ aiProcess_LimitBoneWeights | \
+ aiProcess_RemoveRedundantMaterials | \
+ aiProcess_SplitLargeMeshes | \
+ aiProcess_Triangulate | \
+ aiProcess_GenUVCoords | \
+ aiProcess_SortByPType | \
+ aiProcess_FindDegenerates | \
+ aiProcess_FindInvalidData )
+
+QT_BEGIN_NAMESPACE
+
+QAiSceneHandler::QAiSceneHandler()
+ : m_options(qAiPostProcessPreset)
+ , m_showWarnings(false)
+ , m_mayHaveLinesPoints(false)
+ , m_meshSplitVertexLimit(2000)
+ , m_meshSplitTriangleLimit(2000)
+ , m_removeComponentFlags(0)
+ , m_removeSortFlags(0)
+{
+ // by default remove per vertex colors from the data - no-one uses that in
+ // models - if they need it it can be turned on with UseVertexColors
+ m_removeComponentFlags |= aiComponent_COLORS;
+
+ // by default remove points and lines from the model, since these are usually
+ // degenerate structures from bad modelling or bad import/export. if they
+ // are needed it can be turned on with IncludeLinesPoints
+ m_removeSortFlags |= aiPrimitiveType_POINT | aiPrimitiveType_LINE;
+}
+
+QAiSceneHandler::~QAiSceneHandler()
+{
+ // nothing to do
+}
+
+void QAiSceneHandler::decodeOptions(const QString &options)
+{
+ if (options.isEmpty())
+ return;
+
+ // See aiPostProcess.h for aiProcessPreset_TargetRealtime_Quality
+ // - a useful default set of values - its exactly what we want but
+ // wont compile with flags, so redefined with the above macro.
+ // Also, allow the user to override some settings
+ m_options = qAiPostProcessPreset;
+
+ // Has to match the enum
+ static const char *validOptions[] = {
+ "NoOptions",
+ "ShowWarnings",
+ "CalculateNormals",
+ "ForceFaceted",
+ "ForceSmooth",
+ "IncludeAllMaterials",
+ "IncludeLinesPoints",
+ "FixNormals",
+ "DeDupMeshes",
+ "Optimize",
+ "FlipUVs",
+ "FlipWinding",
+ "UseVertexColors",
+ "VertexSplitLimitx2",
+ "TriangleSplitLimitx2",
+ 0
+ };
+
+ QStringList opList = options.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts);
+
+ for (int i = 0; i < opList.count(); ++i)
+ {
+ QString op = opList.at(i);
+ op = op.trimmed();
+ int k = 0;
+ for ( ; validOptions[k]; ++k)
+ if (op == QString::fromLatin1(validOptions[k]))
+ break;
+ if (validOptions[k]) // found
+ {
+ Options o = static_cast<Options>(k);
+ switch (o)
+ {
+ case NoOptions:
+ break;
+ case ShowWarnings:
+ if (m_showWarnings)
+ {
+ m_importer.SetExtraVerbose(true);
+ }
+ else
+ {
+ m_showWarnings = true;
+ m_options |= aiProcess_ValidateDataStructure;
+ }
+ break;
+ case CalculateNormals:
+ m_removeComponentFlags |= aiComponent_NORMALS;
+ m_options |= aiProcess_GenSmoothNormals;
+ m_options &= ~aiProcess_GenNormals;
+ break;
+ case ForceFaceted:
+ m_removeComponentFlags |= aiComponent_NORMALS;
+ m_options |= aiProcess_GenNormals;
+ m_options &= ~aiProcess_GenSmoothNormals;
+ m_options &= ~aiProcess_JoinIdenticalVertices;
+ break;
+ case ForceSmooth:
+ Assimp::DefaultLogger::get()->warn("ForceSmooth is deprecated - ignoring (meshes now smooth by default)");
+ break;
+ case IncludeAllMaterials:
+ m_options &= ~aiProcess_RemoveRedundantMaterials;
+ break;
+ case IncludeLinesPoints:
+ m_removeSortFlags &= ~(aiPrimitiveType_LINE | aiPrimitiveType_POINT);
+ m_mayHaveLinesPoints = true;
+ // leave it with the FindDegenerates option turned on - we want zero
+ // area triangles to display as proper GL lines or points
+ break;
+ case FixNormals:
+ m_options |= aiProcess_FixInfacingNormals;
+ break;
+ case DeDupMeshes:
+ m_options |= aiProcess_FindInstances;
+ break;
+ case Optimize:
+ m_options |= aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes;
+ break;
+ case FlipUVs:
+ m_options |= aiProcess_FlipUVs;
+ break;
+ case FlipWinding:
+ m_options |= aiProcess_FlipWindingOrder;
+ break;
+ case UseVertexColors:
+ m_removeComponentFlags &= ~aiComponent_COLORS;
+ break;
+ case VertexSplitLimitx2:
+ m_meshSplitVertexLimit <<= 1;
+ // repeating this in the option string more than once works...
+ break;
+ case TriangleSplitLimitx2:
+ // ....and we're OK with that, just don't overdo it
+ m_meshSplitTriangleLimit <<= 1;
+ break;
+ }
+ }
+ else
+ {
+ qWarning("Bad option: \"%s\" in %s", qPrintable(op),
+ qPrintable(options));
+ }
+ }
+}
+
+QGLAbstractScene *QAiSceneHandler::read()
+{
+ AiLoaderIOSystem *ios = new AiLoaderIOSystem(device(), url());
+ m_importer.SetIOHandler(ios);
+
+ Assimp::Logger *log = 0;
+ Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL;
+ if (m_showWarnings)
+ {
+ severity = Assimp::Logger::VERBOSE;
+ int streams = aiDefaultLogStream_FILE |
+#ifdef Q_CC_MSVC
+ aiDefaultLogStream_DEBUGGER
+#else
+ aiDefaultLogStream_STDERR
+#endif
+ ;
+ log = Assimp::DefaultLogger::create("AssimpLog.txt", severity, streams);
+ }
+
+ QString path;
+ QUrl u = url();
+ if (u.scheme() != QLatin1String("file"))
+ {
+ qWarning("Non-file URL's not yet supported");
+ return 0;
+ }
+ path = u.toLocalFile();
+
+ if (m_removeComponentFlags)
+ m_options |= aiProcess_RemoveComponent;
+ else
+ m_options &= ~aiProcess_RemoveComponent;
+
+ m_importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, m_removeComponentFlags);
+ m_importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, m_removeSortFlags);
+ m_importer.SetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT, m_meshSplitVertexLimit);
+ m_importer.SetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, m_meshSplitTriangleLimit);
+
+ // force this on, and provide no way to turn it off. Its set by the
+ // aiProcessPreset_TargetRealtime_Quality option in the constructor.
+ // Guarantees that all meshes only have one primitive type
+ Q_ASSERT(m_options & aiProcess_SortByPType);
+
+ // the importer owns the scene, so when the it goes out of scope on exiting
+ // this function the scene will get destroyed
+ const aiScene* scene = m_importer.ReadFile(path.toStdString(), m_options);
+
+ if (!scene)
+ {
+ // Notes on import success flags - according to assimp doco if validation
+ // is requested the flags AI_SCENE_FLAGS_VALIDATION_WARNING will be set
+ // if there's a warning, and AI_SCENE_FLAGS_VALIDATED is set on success.
+ // This does not happen. Also AI_SCENE_FLAGS_INCOMPLETE can be set on a
+ // valid model, so checking for that is no use either. Best way to proceed
+ // is that if ShowWarnings is turned on above, then any pertinent warnings
+ // will be shown; and if a NULL result is returned here, then its a fatal
+ // error and a message is shown here. If a non-NULL result is returned
+ // just go ahead and try to load it.
+ QString c = QDir::current().absolutePath();
+ qWarning("Asset importer error: %s\n", m_importer.GetErrorString());
+ if (log)
+ qWarning("For details check log: %s/AssimpLog.txt\n", qPrintable(c));
+ return 0;
+ }
+
+
+ QAiScene *qscene = new QAiScene(scene, this);
+
+ Assimp::DefaultLogger::kill();
+
+ return qscene;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/assimp/qaiscenehandler.h b/src/plugins/sceneformats/assimp/qaiscenehandler.h
new file mode 100644
index 000000000..95b800025
--- /dev/null
+++ b/src/plugins/sceneformats/assimp/qaiscenehandler.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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 QGL3DSSCENEHANDLER_H
+#define QGL3DSSCENEHANDLER_H
+
+#include "qglsceneformatplugin.h"
+
+#include "aiPostProcess.h"
+#include "assimp.hpp"
+
+#include <QtCore/qurl.h>
+
+Q_DECLARE_FLAGS(aiPostProcessFlags, aiPostProcessSteps);
+Q_DECLARE_OPERATORS_FOR_FLAGS(aiPostProcessFlags);
+
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class QAiSceneHandler : public QGLSceneFormatHandler
+{
+public:
+ enum Options {
+ NoOptions,
+ ShowWarnings, // show any warnings while loading the file
+ CalculateNormals, // replace normals from the file with smooth generated ones
+ ForceFaceted, // generate non-smooth normals (implies CalculateNormals)
+ ForceSmooth, // deprecated - retained only for backward compatibility
+ IncludeAllMaterials, // include even redundant (unused) materials
+ IncludeLinesPoints, // include even collapsed triangles (lines or points)
+ FixNormals, // try to fix incorrect (in facing) normals
+ DeDupMeshes, // replace copied meshes with refs to a single instance
+ Optimize, // collapse meshes, nodes & scene heierarchies
+ FlipUVs, // flips UV's on the y-axis (for upside-down textures)
+ FlipWinding, // makes faces CW instead of CCW
+ UseVertexColors, // use vertex colors that are in a model
+ VertexSplitLimitx2, // double the vertex count which will split a large mesh
+ TriangleSplitLimitx2 // double the triangle count which will split a large mesh
+ };
+
+ QAiSceneHandler();
+ ~QAiSceneHandler();
+
+ QGLAbstractScene *read();
+
+ void decodeOptions(const QString &options);
+
+ bool showWarnings() const { return m_showWarnings; }
+ bool mayHaveLinesPoints() const { return m_mayHaveLinesPoints; }
+
+ aiPostProcessFlags options() const { return m_options; }
+ quint32 removeComponentFlags() const { return m_removeComponentFlags; }
+ quint32 removeSortFlags() const { return m_removeSortFlags; }
+
+private:
+ aiPostProcessFlags m_options;
+ bool m_showWarnings;
+ bool m_mayHaveLinesPoints;
+ int m_meshSplitVertexLimit;
+ int m_meshSplitTriangleLimit;
+ Assimp::Importer m_importer;
+ quint32 m_removeComponentFlags;
+ quint32 m_removeSortFlags;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/sceneformats/bezier/bezier.pro b/src/plugins/sceneformats/bezier/bezier.pro
new file mode 100644
index 000000000..bed100239
--- /dev/null
+++ b/src/plugins/sceneformats/bezier/bezier.pro
@@ -0,0 +1,12 @@
+TARGET = qscenebezier
+include(../../qpluginbase.pri)
+
+HEADERS += qglbezierscene.h \
+ qglbezierscenehandler.h
+SOURCES += main.cpp \
+ qglbezierscene.cpp \
+ qglbezierscenehandler.cpp
+CONFIG += qt3d
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/sceneformats
+target.path += $$[QT_INSTALL_PLUGINS]/sceneformats
+INSTALLS += target
diff --git a/src/plugins/sceneformats/bezier/main.cpp b/src/plugins/sceneformats/bezier/main.cpp
new file mode 100644
index 000000000..592da2e69
--- /dev/null
+++ b/src/plugins/sceneformats/bezier/main.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "qglsceneformatplugin.h"
+#include "qglbezierscenehandler.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGLBezierScenePlugin : public QGLSceneFormatPlugin
+{
+public:
+ QStringList keys() const;
+ virtual QGLSceneFormatHandler *create(QIODevice *device, const QUrl& url, const QString &format) const;
+};
+
+QStringList QGLBezierScenePlugin::keys() const
+{
+ return QStringList() << QLatin1String("bezier") << QLatin1String("bez");
+}
+
+QGLSceneFormatHandler *QGLBezierScenePlugin::create(QIODevice *device, const QUrl& url, const QString &format) const
+{
+ Q_UNUSED(device);
+ Q_UNUSED(url);
+ Q_UNUSED(format);
+ return new QGLBezierSceneHandler;
+}
+
+Q_EXPORT_STATIC_PLUGIN(QGLBezierScenePlugin)
+Q_EXPORT_PLUGIN2(qscenebezier, QGLBezierScenePlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/bezier/qglbezierscene.cpp b/src/plugins/sceneformats/bezier/qglbezierscene.cpp
new file mode 100644
index 000000000..d0428c876
--- /dev/null
+++ b/src/plugins/sceneformats/bezier/qglbezierscene.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** 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 "qglbezierscene.h"
+#include "qglscenenode.h"
+
+QT_BEGIN_NAMESPACE
+
+QGLBezierScene::QGLBezierScene(QGLSceneNode *geometry, QObject *parent)
+ : QGLAbstractScene(parent)
+{
+ mainObject = geometry;
+ mainObject->setObjectName(QLatin1String("mesh")); // No tr
+ mainObject->setParent(this);
+}
+
+QGLBezierScene::~QGLBezierScene()
+{
+}
+
+QList<QObject *> QGLBezierScene::objects() const
+{
+ QList<QObject *> objs;
+ objs.append(mainObject);
+ return objs;
+}
+
+QGLSceneNode *QGLBezierScene::mainNode() const
+{
+ return mainObject;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/bezier/qglbezierscene.h b/src/plugins/sceneformats/bezier/qglbezierscene.h
new file mode 100644
index 000000000..2c34c9e5b
--- /dev/null
+++ b/src/plugins/sceneformats/bezier/qglbezierscene.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 QGLBEZIERSCENE_H
+#define QGLBEZIERSCENE_H
+
+#include "qglabstractscene.h"
+#include "qglbuilder.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGLBezierScene : public QGLAbstractScene
+{
+ Q_OBJECT
+public:
+ explicit QGLBezierScene(QGLSceneNode *geometry, QObject *parent = 0);
+ virtual ~QGLBezierScene();
+
+ QList<QObject *> objects() const;
+ QGLSceneNode *mainNode() const;
+
+private:
+ QGLSceneNode *mainObject;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp b/src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp
new file mode 100644
index 000000000..dfe579cd8
--- /dev/null
+++ b/src/plugins/sceneformats/bezier/qglbezierscenehandler.cpp
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** 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 "qglbezierscenehandler.h"
+#include "qglbezierscene.h"
+#include "qglbezierpatches.h"
+#include "qvector3darray.h"
+#include <QtCore/qtextstream.h>
+
+QT_BEGIN_NAMESPACE
+
+QGLAbstractScene *QGLBezierSceneHandler::read()
+{
+ QTextStream stream(device());
+ QGLBezierPatches patches;
+
+ // Read the number of patches from the first line.
+ int patchCount;
+ stream >> patchCount;
+ stream.skipWhiteSpace();
+ if (patchCount <= 0)
+ return 0;
+
+ // Read the patch indices.
+ int depth = 0;
+ QArray<int> indices;
+ for (int patch = 0; patch < patchCount; ++patch) {
+ bool eoln = false;
+ for (int index = 0; index < 16; ++index) {
+ int value;
+ stream >> value;
+ indices.append(value - 1);
+
+ QChar sep;
+ stream >> sep;
+ if (sep == QLatin1Char('\n') || sep == QLatin1Char('\r')) {
+ eoln = true;
+ break;
+ }
+ if (sep != QLatin1Char(','))
+ return 0;
+ }
+ if (!eoln) {
+ // Optional sub-division depth on the end.
+ int value;
+ stream >> value;
+ if (value > depth)
+ depth = value;
+ }
+ stream.skipWhiteSpace();
+ }
+
+ // Read the number of vertices.
+ int vertexCount;
+ stream >> vertexCount;
+ stream.skipWhiteSpace();
+ if (vertexCount <= 0)
+ return 0;
+
+ // Read the vertex values.
+ QVector3DArray vertices;
+ for (int vertex = 0; vertex < vertexCount; ++vertex) {
+ bool eoln = false;
+ qreal coords[3] = {0.0f, 0.0f, 0.0f};
+ for (int index = 0; index < 3; ++index) {
+ stream >> coords[index];
+
+ QChar sep;
+ stream >> sep;
+ if (sep == QLatin1Char('\n') || sep == QLatin1Char('\r')) {
+ eoln = true;
+ break;
+ }
+ if (sep != QLatin1Char(','))
+ return 0;
+ }
+ vertices.append(coords[0], coords[1], coords[2]);
+ if (!eoln) {
+ // Optional normal on the end: read it but discard.
+ for (int index = 0; index < 3; ++index) {
+ stream >> coords[index];
+
+ QChar sep;
+ stream >> sep;
+ if (sep == QLatin1Char('\n') || sep == QLatin1Char('\r'))
+ break;
+ if (sep != QLatin1Char(','))
+ return 0;
+ }
+ }
+ stream.skipWhiteSpace();
+ }
+
+ // Check for options at the end of the stream.
+ if (!stream.atEnd()) {
+ QChar ch;
+ stream >> ch;
+ if (ch == QLatin1Char('#')) {
+ QString options = stream.readLine();
+ if (options.contains(QLatin1String("teapot-adjust"))) {
+ // Perform the "teapot adjustment" to convert the raw
+ // teapot data into something more suitable for applications.
+ // i.e., do the equivalent of the following transformation:
+ // matrix.rotate(270.0f, 1.0f, 0.0f, 0.0f);
+ // matrix.scale(0.5f, 0.5f, 0.5f);
+ // matrix.translate(0.0f, 0.0f, -1.5f);
+ for (int vertex = 0; vertex < vertexCount; ++vertex) {
+ QVector3D vec = vertices[vertex];
+ qreal x = vec.x();
+ qreal y = vec.y();
+ qreal z = vec.z();
+ z -= 1.5f;
+ x *= 0.5f;
+ y *= 0.5f;
+ z *= 0.5f;
+ qreal y2 = z;
+ qreal z2 = -y;
+ y = y2;
+ z = z2;
+ vertices[vertex] = QVector3D(x, y, z);
+ }
+ }
+ if (options.contains(QLatin1String("reverse-patches"))) {
+ // Reverse the patch order to convert clockwise
+ // patches into standard anti-clockwise patches.
+ QArray<int> newIndices;
+ for (int patch = 0; patch < patchCount; ++patch) {
+ int temp[16];
+ for (int index = 0; index < 16; ++index)
+ temp[index] = indices[patch * 16 + index];
+ for (int i = 0; i < 16; ++i)
+ newIndices.append(temp[(i & 0x0C) + (3 - (i % 4))]);
+ }
+ indices = newIndices;
+ }
+ }
+ }
+
+ // Create the geometry node from the Bezier patch data.
+ if (depth != 0)
+ patches.setSubdivisionDepth(depth);
+ QVector3DArray positions;
+ for (int pindex = 0; pindex < indices.size(); ++pindex)
+ positions += vertices[indices[pindex]];
+ patches.setPositions(positions);
+ QGLBuilder geometry;
+ geometry << patches;
+
+ // Create a scene with a single object containing the geometry.
+ return new QGLBezierScene(geometry.finalizedSceneNode());
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/bezier/qglbezierscenehandler.h b/src/plugins/sceneformats/bezier/qglbezierscenehandler.h
new file mode 100644
index 000000000..ce43c28e9
--- /dev/null
+++ b/src/plugins/sceneformats/bezier/qglbezierscenehandler.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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 QGLBEZIERSCENEHANDLER_H
+#define QGLBEZIERSCENEHANDLER_H
+
+#include "qglsceneformatplugin.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGLBezierSceneHandler : public QGLSceneFormatHandler
+{
+public:
+ QGLAbstractScene *read();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/sceneformats/obj/main.cpp b/src/plugins/sceneformats/obj/main.cpp
new file mode 100644
index 000000000..1da55b4e7
--- /dev/null
+++ b/src/plugins/sceneformats/obj/main.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 "qglsceneformatplugin.h"
+#include "qglobjscenehandler.h"
+
+QT_BEGIN_NAMESPACE
+
+//! [1]
+class QGLObjScenePlugin : public QGLSceneFormatPlugin
+{
+public:
+ QStringList keys() const;
+ virtual QGLSceneFormatHandler *create(QIODevice *device, const QUrl& url, const QString &format) const;
+};
+//! [1]
+
+//! [2]
+QStringList QGLObjScenePlugin::keys() const
+{
+ return QStringList() << QLatin1String("obj") << QLatin1String("model/obj");
+}
+//! [2]
+
+//! [3]
+QGLSceneFormatHandler *QGLObjScenePlugin::create(QIODevice *device, const QUrl& url, const QString &format) const
+{
+ Q_UNUSED(device);
+ Q_UNUSED(url);
+ Q_UNUSED(format);
+ return new QGLObjSceneHandler;
+}
+//! [3]
+
+//! [4]
+Q_EXPORT_STATIC_PLUGIN(QGLObjScenePlugin)
+Q_EXPORT_PLUGIN2(qsceneobj, QGLObjScenePlugin)
+//! [4]
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/obj/obj.pro b/src/plugins/sceneformats/obj/obj.pro
new file mode 100644
index 000000000..0eaa76e09
--- /dev/null
+++ b/src/plugins/sceneformats/obj/obj.pro
@@ -0,0 +1,12 @@
+TARGET = qsceneobj
+include(../../qpluginbase.pri)
+
+HEADERS += qglobjscene.h \
+ qglobjscenehandler.h
+SOURCES += main.cpp \
+ qglobjscene.cpp \
+ qglobjscenehandler.cpp
+CONFIG += qt3d
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/sceneformats
+target.path += $$[QT_INSTALL_PLUGINS]/sceneformats
+INSTALLS += target
diff --git a/src/plugins/sceneformats/obj/qglobjscene.cpp b/src/plugins/sceneformats/obj/qglobjscene.cpp
new file mode 100644
index 000000000..c34c5bfc9
--- /dev/null
+++ b/src/plugins/sceneformats/obj/qglobjscene.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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 "qglobjscene.h"
+#include "qglbuilder.h"
+#include "qglscenenode.h"
+
+QT_BEGIN_NAMESPACE
+
+QGLObjScene::QGLObjScene(QGLSceneNode *defaultNode, QObject *parent)
+ : QGLAbstractScene(parent)
+ , mainObject(defaultNode)
+{
+ defaultNode->setParent(this);
+}
+
+QGLObjScene::~QGLObjScene()
+{
+}
+
+QList<QObject *> QGLObjScene::objects() const
+{
+ QList<QObject *> objs;
+ objs.append(mainObject);
+ QList<QGLSceneNode *> children = mainObject->allChildren();
+ for (int index = 0; index < children.count(); ++index)
+ objs.append(children.at(index));
+ return objs;
+}
+
+QGLSceneNode *QGLObjScene::mainNode() const
+{
+ return mainObject;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/obj/qglobjscene.h b/src/plugins/sceneformats/obj/qglobjscene.h
new file mode 100644
index 000000000..4f4875413
--- /dev/null
+++ b/src/plugins/sceneformats/obj/qglobjscene.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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 QGLOBJSCENE_H
+#define QGLOBJSCENE_H
+
+#include "qglabstractscene.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGLBuilder;
+class QGLSceneNode;
+
+//! [1]
+class QGLObjScene : public QGLAbstractScene
+{
+ Q_OBJECT
+public:
+//! [1]
+ explicit QGLObjScene(QGLSceneNode *defaultNode, QObject *parent = 0);
+ virtual ~QGLObjScene();
+
+//! [2]
+ QList<QObject *> objects() const;
+ QGLSceneNode *mainNode() const;
+//! [2]
+
+private:
+ QGLSceneNode *mainObject;
+//! [3]
+};
+//! [3]
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/sceneformats/obj/qglobjscenehandler.cpp b/src/plugins/sceneformats/obj/qglobjscenehandler.cpp
new file mode 100644
index 000000000..bad2f3d42
--- /dev/null
+++ b/src/plugins/sceneformats/obj/qglobjscenehandler.cpp
@@ -0,0 +1,463 @@
+/****************************************************************************
+**
+** 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 "qglobjscenehandler.h"
+#include "qglobjscene.h"
+#include "qvector2darray.h"
+#include "qvector3darray.h"
+#include "qglbuilder.h"
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qfile.h>
+#include <QtGui/qimage.h>
+
+QT_BEGIN_NAMESPACE
+
+QGLObjSceneHandler::QGLObjSceneHandler()
+ : QGLSceneFormatHandler()
+ , palette(0)
+ , smoothing(QGL::Faceted)
+ , smoothingForced(false)
+{
+}
+
+// Documentation for OBJ and MTL files from:
+// http://www.fileformat.info/format/wavefrontobj/egff.htm
+// http://www.fileformat.info/format/material/
+
+static int objSkipWS(const QByteArray& line, int posn)
+{
+ while (posn < line.size() && (line[posn] == ' ' || line[posn] == '\t'))
+ ++posn;
+ return posn;
+}
+
+static int objSkipNonWS(const QByteArray& line, int posn, int stopch)
+{
+ while (posn < line.size() &&
+ line[posn] != ' ' && line[posn] != '\t' && line[posn] != stopch)
+ ++posn;
+ return posn;
+}
+
+static qreal objReadFloat(const QByteArray& line, int *posn)
+{
+ *posn = objSkipWS(line, *posn);
+ int end = objSkipNonWS(line, *posn, 0);
+ qreal value;
+ if (end > *posn)
+ value = qreal(line.mid(*posn, end - *posn).toDouble());
+ else
+ value = 0.0f;
+ *posn = end;
+ return value;
+}
+
+static int objReadInteger(const QByteArray& line, int *posn)
+{
+ *posn = objSkipWS(line, *posn);
+ int end = objSkipNonWS(line, *posn, '/');
+ int value;
+ if (end > *posn)
+ value = line.mid(*posn, end - *posn).toInt();
+ else
+ value = 0;
+ //*posn = objSkipNonWS(line, end, 0);
+ *posn = end;
+ return value;
+}
+
+static int objReadSlashInteger(const QByteArray& line, int *posn)
+{
+ if (*posn >= line.size() || line[*posn] != '/')
+ return 0;
+ ++(*posn);
+ int end = objSkipNonWS(line, *posn, '/');
+ int value;
+ if (end > *posn)
+ value = line.mid(*posn, end - *posn).toInt();
+ else
+ value = 0;
+ //*posn = objSkipNonWS(line, end, 0);
+ *posn = end;
+ return value;
+}
+
+static QColor objReadColor(const QByteArray& line, int posn)
+{
+ qreal red = objReadFloat(line, &posn);
+ qreal green = objReadFloat(line, &posn);
+ qreal blue = objReadFloat(line, &posn);
+ qreal alpha = 1.0f;
+ posn = objSkipWS(line, posn);
+ if (posn < line.size())
+ alpha = objReadFloat(line, &posn);
+ return QColor::fromRgbF(red, green, blue, alpha);
+}
+
+void QGLObjSceneHandler::decodeOptions(const QString &options)
+{
+ if (options.contains(QLatin1String("ForceSmooth")))
+ {
+ smoothingForced = true;
+ smoothing = QGL::Smooth;
+ }
+ else
+ {
+ smoothingForced = true;
+ smoothing = QGL::Faceted;
+ }
+}
+
+QGLAbstractScene *QGLObjSceneHandler::read()
+{
+ QByteArray line;
+ QByteArray keyword;
+ int posn, index, count;
+ int tindex, nindex;
+ QVector3DArray positions;
+ QVector2DArray texCoords;
+ QVector3DArray normals;
+ qreal x, y, z;
+ quint32 fields = 0;
+ QGLMaterial *material = 0;
+ QGLSceneNode *defaultNode;
+
+ // Create the geometry builder and start an initial Faceted section.
+ QGLBuilder builder;
+ builder.newSection(smoothing);
+ QGLSceneNode *root = builder.sceneNode();
+ palette = root->palette();
+ defaultNode = root;
+ defaultNode->setObjectName(QLatin1String("__main"));
+ builder.pushNode();
+
+ QGeometryData op;
+ while (!device()->atEnd()) {
+ // Read the next line, including any backslash continuations.
+ line = device()->readLine().trimmed();
+ while (line.endsWith('\\')) {
+ line.truncate(line.size() - 1);
+ if (device()->atEnd())
+ break;
+ line += device()->readLine().trimmed();
+ }
+ if (line.startsWith('#') || line.isEmpty())
+ continue; // Skip comments and blank lines.
+
+ // Extract the keyword at the start of the line.
+ posn = 0;
+ while (posn < line.size() &&
+ line[posn] != ' ' && line[posn] != '\t')
+ ++posn;
+ keyword = line.left(posn);
+
+ // Determine how to process this line from the keyword.
+ if (keyword == "v") {
+ x = objReadFloat(line, &posn);
+ y = objReadFloat(line, &posn);
+ z = objReadFloat(line, &posn);
+ positions.append(x, y, z);
+ } else if (keyword == "vt") {
+ x = objReadFloat(line, &posn);
+ y = objReadFloat(line, &posn);
+ texCoords.append(x, y);
+ } else if (keyword == "vn") {
+ x = objReadFloat(line, &posn);
+ y = objReadFloat(line, &posn);
+ z = objReadFloat(line, &posn);
+ normals.append(x, y, z);
+ } else if (keyword == "f") {
+ posn = objSkipWS(line, posn);
+ count = 0;
+ //QGeometryData op; //(dlist, QGL::TRIANGLE_FAN);
+ op = QGeometryData(); // clear leaves field definitions
+ while (posn < line.size()) {
+ // Note: we currently only read the initial vertex
+ // index and also use it for texture co-ordinates
+ // and normals. e.g. "2/2", "3/3", etc. This will
+ // need to be fixed to handle "2/1", "3/7", etc.
+ index = objReadInteger(line, &posn);
+ tindex = objReadSlashInteger(line, &posn);
+ nindex = objReadSlashInteger(line, &posn);
+ if (index < 0)
+ index = positions.count() + index;
+ else if (index > 0)
+ --index; // Indices in obj are 1-based.
+ if (index >= 0 && index < positions.count())
+ op.appendVertex(positions[index]);
+ if (tindex < 0)
+ tindex = texCoords.count() + tindex;
+ else if (tindex > 0)
+ --tindex; // Indices in obj are 1-based.
+ else
+ tindex = -1;
+ if (tindex >= 0 && tindex < texCoords.count())
+ op.appendTexCoord(texCoords[tindex]);
+ if (nindex < 0)
+ nindex = normals.count() + nindex;
+ else if (nindex > 0)
+ --nindex; // Indices in obj are 1-based.
+ else
+ nindex = -1;
+ if (nindex >= 0 && nindex < normals.count())
+ op.appendNormal(normals[nindex]);
+ ++count;
+ posn = objSkipNonWS(line, posn, 0);
+ posn = objSkipWS(line, posn);
+ }
+ // if geometry has already been added with a different combination
+ // of fields start a new section
+ // the primitive doesn't get posted to the section until op.end()
+ if (op.fields() != fields)
+ {
+ if (fields && builder.currentNode()->count() > 0)
+ builder.newSection(smoothing);
+ fields = op.fields();
+ }
+ builder.addTriangleFan(op);
+ } else if (keyword == "usemtl") {
+ // Specify a material for the faces that follow.
+ posn = objSkipWS(line, posn);
+ QByteArray rest = line.mid(posn);
+ QString materialName = QString::fromLocal8Bit(rest.constData(), rest.size());
+ if (!materialName.isEmpty() &&
+ materialName != QLatin1String("(null)")) {
+ index = palette->indexOf(materialName);
+ if (index != -1) {
+ QGLSceneNode *node = builder.newNode();
+ node->setMaterialIndex(index);
+ QGLMaterial *material = palette->material(index);
+ if (material->texture())
+ node->setEffect(QGL::LitDecalTexture2D);
+ else
+ node->setEffect(QGL::LitMaterial);
+ } else {
+ qWarning() << "obj material" << materialName << "not found";
+ material = 0;
+ }
+ }
+ } else if (keyword == "mtllib") {
+ // Load a material library.
+ posn = objSkipWS(line, posn);
+ QByteArray filename = line.mid(posn);
+ loadMaterialLibrary(QString::fromLocal8Bit(filename.constData(), filename.size()));
+ } else if (keyword == "s") {
+ if (!smoothingForced)
+ {
+ // Set smoothing on or off.
+ posn = objSkipWS(line, posn);
+ index = objSkipNonWS(line, posn, 0);
+ QByteArray arg = line.mid(posn, index - posn);
+ QGL::Smoothing smooth;
+ if (arg == "on" || arg == "1")
+ smooth = QGL::Smooth;
+ else
+ smooth = QGL::Faceted;
+ if (smoothing != smooth) {
+ smoothing = smooth;
+ builder.newSection(smooth);
+ }
+ }
+ } else if (keyword == "g" || keyword == "o") {
+ // Label the faces that follow as part of a named group or object.
+ posn = objSkipWS(line, posn);
+ QByteArray rest = line.mid(posn);
+ QString objectName = QString::fromLocal8Bit(rest.constData(), rest.size());
+ QGLSceneNode *node = builder.currentNode();
+ // if content has already been added to a current group, then
+ // create a new node in the scene graph for the group, otherwise
+ // just label the existing group with this name
+ QGLSceneNode *p = qobject_cast<QGLSceneNode*>(node->parent());
+ if (node->count() > 0 && p && p->objectName().isEmpty())
+ {
+ node = p;
+ }
+ else
+ {
+ builder.popNode();
+ node = builder.currentNode();
+ builder.pushNode();
+ }
+ node->setObjectName(objectName);
+ } else {
+ qWarning() << "unsupported obj command: " << keyword.constData();
+ }
+ }
+
+ // Create a scene from the geometry
+ return new QGLObjScene(builder.finalizedSceneNode());
+}
+
+void QGLObjSceneHandler::loadMaterialLibrary(const QString& name)
+{
+ QUrl materialUrl = url().resolved(name);
+ if (materialUrl.scheme() == QLatin1String("file")) {
+ QFile file(materialUrl.toLocalFile());
+ if (!file.open(QIODevice::ReadOnly))
+ qWarning() << "QGLObjSceneHandler::loadMaterialLibrary: could not open:" << materialUrl.toLocalFile();
+ else
+ loadMaterials(&file);
+ } else {
+ // TODO
+ qWarning("QGLObjSceneHandler::loadMaterialLibrary: non-file urls not supported");
+ }
+}
+
+void QGLObjSceneHandler::loadMaterials(QIODevice *device)
+{
+ QByteArray line;
+ QByteArray keyword;
+ int posn, index;
+ QGLMaterial *material = 0;
+ QString materialName;
+ QString textureName;
+
+ while (!device->atEnd()) {
+ // Read the next line, including any backslash continuations.
+ line = device->readLine().trimmed();
+ while (line.endsWith('\\')) {
+ line.truncate(line.size() - 1);
+ if (device->atEnd())
+ break;
+ line += device->readLine().trimmed();
+ }
+ if (line.startsWith('#') || line.isEmpty())
+ continue; // Skip comments and blank lines.
+
+ // Extract the keyword at the start of the line.
+ posn = 0;
+ while (posn < line.size() &&
+ line[posn] != ' ' && line[posn] != '\t')
+ ++posn;
+ keyword = line.left(posn);
+
+ // Determine how to process this line from the keyword.
+ if (keyword == "newmtl") {
+ // Start a new material definition.
+ posn = objSkipWS(line, posn);
+ QByteArray rest = line.mid(posn);
+ materialName = QString::fromLocal8Bit(rest.constData(), rest.size());
+ index = palette->indexOf(materialName);
+ if (index != -1) {
+ qWarning() << "redefining obj material:" << materialName;
+ material = palette->material(index);
+ } else {
+ material = new QGLMaterial();
+ material->setObjectName(materialName);
+ palette->addMaterial(material);
+ }
+ } else if (keyword == "Ka") {
+ // Ambient color of the material.
+ if (material)
+ material->setAmbientColor(objReadColor(line, posn));
+ } else if (keyword == "Kd") {
+ // Diffuse color of the material.
+ if (material)
+ material->setDiffuseColor(objReadColor(line, posn));
+ } else if (keyword == "Ks") {
+ // Specular color of the material.
+ if (material)
+ material->setSpecularColor(objReadColor(line, posn));
+ } else if (keyword == "map_Kd") {
+ // Texture associated with the material.
+ posn = objSkipWS(line, posn);
+ QByteArray rest = line.mid(posn);
+ textureName = QString::fromLocal8Bit(rest.constData(), rest.size());
+ QGLTexture2D *texture = loadTexture(textureName);
+ if (texture) {
+ index = palette->indexOf(materialName);
+ if (index >= 0) {
+ QGLMaterial *material = palette->material(index);
+ texture->setParent(material);
+ material->setTexture(texture);
+ } else {
+ delete texture;
+ }
+ }
+ } else if (keyword == "d") {
+ // "Dissolve factor" of the material, which is its opacity.
+ if (material) {
+ qreal alpha = objReadFloat(line, &posn);
+ QColor ambient = material->ambientColor();
+ QColor diffuse = material->diffuseColor();
+ ambient.setAlphaF(alpha);
+ diffuse.setAlphaF(alpha);
+ material->setAmbientColor(ambient);
+ material->setDiffuseColor(diffuse);
+ }
+ } else if (keyword == "Ns") {
+ // Specular exponent of the material.
+ if (material)
+ material->setShininess(qRound(objReadFloat(line, &posn)));
+ } else if (keyword == "illum") {
+ // Illumination model - ignored at present.
+ } else if (keyword == "Ni") {
+ // Optical density - ignored at present.
+ } else {
+ qWarning() << "unsupported obj material command: " << keyword.constData();
+ }
+ }
+}
+
+QGLTexture2D *QGLObjSceneHandler::loadTexture(const QString& name)
+{
+ QUrl textureUrl = url().resolved(name);
+ if (textureUrl.scheme() == QLatin1String("file")) {
+ QFile file(textureUrl.toLocalFile());
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "QGLObjSceneHandler::loadTexture: could not open:" << textureUrl.toLocalFile();
+ return 0;
+ } else {
+ file.close();
+ QImage image(textureUrl.toLocalFile());
+ QGLTexture2D *tex = new QGLTexture2D();
+ tex->setImage(image);
+ return tex;
+ }
+ } else {
+ // TODO
+ qWarning("QGLObjSceneHandler::loadTexture: non-file urls not supported");
+ return 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/sceneformats/obj/qglobjscenehandler.h b/src/plugins/sceneformats/obj/qglobjscenehandler.h
new file mode 100644
index 000000000..c46caf529
--- /dev/null
+++ b/src/plugins/sceneformats/obj/qglobjscenehandler.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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 QGLOBJSCENEHANDLER_H
+#define QGLOBJSCENEHANDLER_H
+
+#include "qglsceneformatplugin.h"
+#include "qglmaterialcollection.h"
+#include <QtCore/qmap.h>
+#include <QtCore/qset.h>
+
+QT_BEGIN_NAMESPACE
+
+//! [1]
+class QGLObjSceneHandler : public QGLSceneFormatHandler
+{
+public:
+ QGLObjSceneHandler();
+ QGLAbstractScene *read();
+//! [1]
+ void decodeOptions(const QString &options);
+
+private:
+ void loadMaterialLibrary(const QString& name);
+ void loadMaterials(QIODevice *device);
+ QGLTexture2D *loadTexture(const QString& name);
+
+ QGLMaterialCollection *palette;
+ QGL::Smoothing smoothing;
+ bool smoothingForced;
+//! [2]
+};
+//! [2]
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/sceneformats/sceneformats.pro b/src/plugins/sceneformats/sceneformats.pro
new file mode 100644
index 000000000..97ec09a6f
--- /dev/null
+++ b/src/plugins/sceneformats/sceneformats.pro
@@ -0,0 +1,7 @@
+TEMPLATE = subdirs
+
+old_importer {
+ SUBDIRS = bezier 3ds obj
+} else {
+ SUBDIRS = bezier assimp
+}
diff --git a/src/plugins/scenegraph/scenegraph.pro b/src/plugins/scenegraph/scenegraph.pro
new file mode 100644
index 000000000..e34fa2537
--- /dev/null
+++ b/src/plugins/scenegraph/scenegraph.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += stereo
diff --git a/src/plugins/scenegraph/stereo/main.cpp b/src/plugins/scenegraph/stereo/main.cpp
new file mode 100644
index 000000000..b4a6d946c
--- /dev/null
+++ b/src/plugins/scenegraph/stereo/main.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include <QtDeclarative/qsgcontextplugin.h>
+#include "qsgstereocontext.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGStereoContextPlugin : public QSGContextPlugin
+{
+public:
+ QStringList keys() const;
+ QSGContext *create(const QString &key) const;
+};
+
+QStringList QSGStereoContextPlugin::keys() const
+{
+ QStringList keys;
+ keys += QLatin1String("stereo");
+ keys += QLatin1String("stereo-test"); // Red-cyan test mode
+ return keys;
+}
+
+QSGContext *QSGStereoContextPlugin::create(const QString &key) const
+{
+ return new QSGStereoContext(key);
+}
+
+Q_EXPORT_STATIC_PLUGIN(QSGStereoContextPlugin)
+Q_EXPORT_PLUGIN2(qstereoscenegraph, QSGStereoContextPlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/stereo/qsgstereocontext.cpp b/src/plugins/scenegraph/stereo/qsgstereocontext.cpp
new file mode 100644
index 000000000..b5f2168fc
--- /dev/null
+++ b/src/plugins/scenegraph/stereo/qsgstereocontext.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** 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 "qsgstereocontext.h"
+#include "qsgpretransformnode_p.h"
+#include "qglnamespace.h"
+#include <QtDeclarative/private/nodeupdater_p.h>
+#include <QtDeclarative/renderer.h>
+#include <QtOpenGL/qglframebufferobject.h>
+
+QT_BEGIN_NAMESPACE
+
+// Determine how to switch drawing buffers. On desktop OpenGL we
+// use glDrawBuffer(). On OpenGL/ES we attempt to resolve either
+// glDrawBufferOES() or glDrawBuffersOES(), under the assumption
+// that the OpenGL/ES implementation has a buffer-switching extension
+// that mirrors how desktop OpenGL works. For other kinds of buffer
+// switching, modify QSGStereoContext::renderNextFrame().
+#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT) && !defined(QT_OPENGL_ES)
+ #define DESKTOP_GL_DRAW_BUFFERS 1
+#elif defined(QT_OPENGL_ES)
+ #define OPENGL_ES_DRAW_BUFFERS 1
+#endif
+#ifndef GL_BACK_LEFT
+#define GL_BACK_LEFT 0x0402
+#endif
+#ifndef GL_BACK_RIGHT
+#define GL_BACK_RIGHT 0x0403
+#endif
+
+#ifdef Q_WS_WIN
+# define QSG_GLF_APIENTRY APIENTRY
+#endif
+#ifndef Q_WS_MAC
+# ifndef QSG_GLF_APIENTRYP
+# ifdef QSG_GLF_APIENTRY
+# define QSG_GLF_APIENTRYP QSG_GLF_APIENTRY *
+# else
+# define QSG_GLF_APIENTRY
+# define QSG_GLF_APIENTRYP *
+# endif
+# endif
+#else
+# define QSG_GLF_APIENTRY
+# define QSG_GLF_APIENTRYP *
+#endif
+
+typedef void (QSG_GLF_APIENTRYP q_PFNGLDRAWBUFFERPROC)(GLenum mode);
+typedef void (QSG_GLF_APIENTRYP q_PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs);
+
+class QSGStereoContextPrivate
+{
+public:
+ enum StereoMode
+ {
+ Autodetect,
+ HardwareStereo,
+ RedCyanStereo
+ };
+
+ QSGStereoContextPrivate()
+ : eye(QGL::NoEye)
+ , stereoMode(QSGStereoContextPrivate::Autodetect)
+#if defined(OPENGL_ES_DRAW_BUFFERS)
+ , functionsResolved(false)
+ , drawBuffer(0)
+ , drawBuffers(0)
+#endif
+ {
+ }
+
+ QGL::Eye eye;
+ StereoMode stereoMode;
+
+#if defined(OPENGL_ES_DRAW_BUFFERS)
+ bool functionsResolved;
+ q_PFNGLDRAWBUFFERPROC drawBuffer;
+ q_PFNGLDRAWBUFFERSPROC drawBuffers;
+#endif
+
+ void setEye(QGL::Eye value) { eye = value; }
+ void setDrawBuffer(GLenum buffer);
+};
+
+void QSGStereoContextPrivate::setDrawBuffer(GLenum buffer)
+{
+#if defined(DESKTOP_GL_DRAW_BUFFERS)
+ glDrawBuffer(buffer);
+#elif defined(OPENGL_ES_DRAW_BUFFERS)
+ if (!functionsResolved) {
+ QGLContext *context = const_cast<QGLContext *>(QGLContext::currentContext());
+ drawBuffer = (q_PFNGLDRAWBUFFERPROC)
+ context->getProcAddress(QLatin1String("glDrawBuffer"));
+ if (!drawBuffer) {
+ drawBuffer = (q_PFNGLDRAWBUFFERPROC)
+ context->getProcAddress(QLatin1String("glDrawBufferOES"));
+ }
+ if (!drawBuffer) {
+ drawBuffer = (q_PFNGLDRAWBUFFERPROC)
+ context->getProcAddress(QLatin1String("glDrawBufferARB"));
+ }
+ drawBuffers = (q_PFNGLDRAWBUFFERSPROC)
+ context->getProcAddress(QLatin1String("glDrawBuffers"));
+ if (!drawBuffers) {
+ drawBuffers = (q_PFNGLDRAWBUFFERSPROC)
+ context->getProcAddress(QLatin1String("glDrawBuffersOES"));
+ }
+ if (!drawBuffers) {
+ drawBuffers = (q_PFNGLDRAWBUFFERSPROC)
+ context->getProcAddress(QLatin1String("glDrawBuffersARB"));
+ }
+ if (!drawBuffer && !drawBuffers) {
+ qWarning("QSGContext: QGLContext is stereo-capable but "
+ "glDrawBuffersOES() is not available");
+ }
+ functionsResolved = true;
+ }
+ if (drawBuffer)
+ drawBuffer(buffer);
+ else if (drawBuffers)
+ drawBuffers(1, &buffer);
+#else
+ Q_UNUSED(buffer);
+#endif
+}
+
+class CurrentContextBindable : public Bindable
+{
+public:
+ CurrentContextBindable()
+ : m_ctx(const_cast<QGLContext *>(QGLContext::currentContext()))
+ {
+ }
+
+ void bind() const;
+
+private:
+ QGLContext *m_ctx;
+};
+
+class DrawBufferBindable : public CurrentContextBindable
+{
+public:
+ DrawBufferBindable(QSGStereoContextPrivate *context, GLenum buffer)
+ : m_context(context), m_buffer(buffer) {}
+
+ void bind() const;
+
+private:
+ QSGStereoContextPrivate *m_context;
+ GLenum m_buffer;
+};
+
+class RedStereoBindable : public CurrentContextBindable
+{
+public:
+ void clear() const;
+ void reactivate() const;
+};
+
+class CyanStereoBindable : public CurrentContextBindable
+{
+public:
+ void clear() const;
+ void reactivate() const;
+};
+
+void CurrentContextBindable::bind() const
+{
+ m_ctx->makeCurrent();
+ QGLFramebufferObject::bindDefault();
+}
+
+void DrawBufferBindable::bind() const
+{
+ CurrentContextBindable::bind();
+ m_context->setDrawBuffer(m_buffer);
+}
+
+void RedStereoBindable::clear() const
+{
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
+}
+
+void RedStereoBindable::reactivate() const
+{
+ glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
+}
+
+void CyanStereoBindable::clear() const
+{
+ // Only need to clear the depth buffer on the second pass.
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE);
+}
+
+void CyanStereoBindable::reactivate() const
+{
+ glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE);
+}
+
+class QSGStereoNodeUpdater : public NodeUpdater
+{
+protected:
+ void enterPreTransformNode(QSGPreTransformNode *);
+ void leavePreTransformNode(QSGPreTransformNode *);
+
+ void visitNode(Node *n);
+};
+
+void QSGStereoNodeUpdater::enterPreTransformNode(QSGPreTransformNode *t)
+{
+ if (t->dirtyFlags() & Node::DirtyMatrix)
+ ++m_force_update;
+
+ if (!t->preMatrix().isIdentity() || !t->matrix().isIdentity()) {
+ m_combined_matrix_stack.push(&t->combinedMatrix());
+
+ m_matrix_stack.push();
+ m_matrix_stack = t->preMatrix() * m_matrix_stack.top() * t->matrix();
+ }
+
+ t->setCombinedMatrix(m_matrix_stack.top());
+}
+
+void QSGStereoNodeUpdater::leavePreTransformNode(QSGPreTransformNode *t)
+{
+ if (t->dirtyFlags() & Node::DirtyMatrix)
+ --m_force_update;
+
+ if (!t->preMatrix().isIdentity() || !t->matrix().isIdentity()) {
+ m_matrix_stack.pop();
+ m_combined_matrix_stack.pop();
+ }
+}
+
+void QSGStereoNodeUpdater::visitNode(Node *n)
+{
+ if (n->type() == QSGPreTransformNode::PreTransformNodeType) {
+ QSGPreTransformNode *t = static_cast<QSGPreTransformNode *>(n);
+ enterPreTransformNode(t);
+ visitChildren(t);
+ leavePreTransformNode(t);
+ } else {
+ NodeUpdater::visitNode(n);
+ }
+}
+
+QSGStereoContext::QSGStereoContext(const QString &key, QObject *parent)
+ : QSGContext(parent)
+ , d_ptr(new QSGStereoContextPrivate)
+{
+ Q_D(QSGStereoContext);
+ if (key == QLatin1String("stereo-test"))
+ d->stereoMode = QSGStereoContextPrivate::RedCyanStereo;
+}
+
+QSGStereoContext::~QSGStereoContext()
+{
+}
+
+int QSGStereoContext::eye() const
+{
+ Q_D(const QSGStereoContext);
+ return int(d->eye);
+}
+
+Renderer *QSGStereoContext::createRenderer()
+{
+ Renderer *renderer = QSGContext::createRenderer();
+ renderer->setNodeUpdater(new QSGStereoNodeUpdater);
+ return renderer;
+}
+
+void QSGStereoContext::renderNextFrame()
+{
+ Q_D(QSGStereoContext);
+
+ emit aboutToRenderNextFrame();
+
+ // Detect the type of stereo we should use the first time we render.
+ if (d->stereoMode == QSGStereoContextPrivate::Autodetect) {
+ if (glContext()->format().stereo())
+ d->stereoMode = QSGStereoContextPrivate::HardwareStereo;
+ else
+ d->stereoMode = QSGStereoContextPrivate::RedCyanStereo;
+ }
+
+ // Render the scene according to the stereo mode.
+ Renderer *renderer = this->renderer();
+ switch (d->stereoMode) {
+ case QSGStereoContextPrivate::HardwareStereo: {
+ DrawBufferBindable left(d, GL_BACK_LEFT);
+ DrawBufferBindable right(d, GL_BACK_RIGHT);
+ d->setEye(QGL::LeftEye);
+ renderer->renderScene(left);
+ d->setEye(QGL::RightEye);
+ renderer->renderScene(right);
+ d->setEye(QGL::NoEye);
+ break; }
+
+ case QSGStereoContextPrivate::RedCyanStereo: {
+ RedStereoBindable left;
+ CyanStereoBindable right;
+ d->setEye(QGL::LeftEye);
+ renderer->renderScene(left);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ d->setEye(QGL::RightEye);
+ renderer->renderScene(right);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ d->setEye(QGL::NoEye);
+ break; }
+
+ default: break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/stereo/qsgstereocontext.h b/src/plugins/scenegraph/stereo/qsgstereocontext.h
new file mode 100644
index 000000000..d8cc1f30e
--- /dev/null
+++ b/src/plugins/scenegraph/stereo/qsgstereocontext.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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 QSGSTEREOCONTEXT_H
+#define QSGSTEREOCONTEXT_H
+
+#include <QtDeclarative/qsgcontext.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGStereoContextPrivate;
+
+class QSGStereoContext : public QSGContext
+{
+ Q_OBJECT
+ // These properties exist for the QSGStereoInfo class to
+ // fetch information about the stereo context without having
+ // to directly link against QSGStereoContext.
+ Q_PROPERTY(bool hasStereo READ returnTrue)
+ Q_PROPERTY(bool hasPreTransform READ returnTrue)
+ Q_PROPERTY(int eye READ eye)
+public:
+ explicit QSGStereoContext(const QString &key, QObject *parent = 0);
+ ~QSGStereoContext();
+
+ Renderer *createRenderer();
+ void renderNextFrame();
+
+private:
+ bool returnTrue() const { return true; }
+ int eye() const;
+
+ QScopedPointer<QSGStereoContextPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QSGStereoContext)
+ Q_DISABLE_COPY(QSGStereoContext)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/scenegraph/stereo/stereo.pro b/src/plugins/scenegraph/stereo/stereo.pro
new file mode 100644
index 000000000..9f30306ff
--- /dev/null
+++ b/src/plugins/scenegraph/stereo/stereo.pro
@@ -0,0 +1,15 @@
+TARGET = qstereoscenegraph
+include(../../qpluginbase.pri)
+
+CONFIG += quick3d
+
+SOURCES += \
+ main.cpp \
+ qsgstereocontext.cpp
+
+HEADERS += \
+ qsgstereocontext.h
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/scenegraph
+target.path += $$[QT_INSTALL_PLUGINS]/scenegraph
+INSTALLS += target