blob: 020befd63c6a5894e3e53719f6b569114a8c4645 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <Qt3DRender/qrendercapture.h>
#include <Qt3DRender/private/qrendercapture_p.h>
#include <Qt3DCore/qscenechange.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
#include <QPointer>
#include <QMutexLocker>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
* \class Qt3DRender::QRenderCapture
* \inheaderfile Qt3DRender/QRenderCapture
* \inmodule Qt3DRender
*
* \brief Frame graph node for render capture.
*
* The QRenderCapture is used to capture rendering into an image at any render stage.
* Capturing must be initiated by the user and one image is returned per capture request.
* User can issue multiple render capture requests simultaniously, but only one request
* is served per QRenderCapture instance per frame.
*
* \since 5.8
*/
/*!
* \qmltype RenderCapture
* \instantiates Qt3DRender::QRenderCapture
* \inherits FrameGraphNode
* \inqmlmodule Qt3D.Render
* \since 5.8
* \brief Capture rendering.
*/
/*!
* \class Qt3DRender::QRenderCaptureReply
* \inheaderfile Qt3DRender/QRenderCaptureReply
* \inmodule Qt3DRender
*
* \brief Receives the result of render capture request.
*
* An object, which receives the image from QRenderCapture::requestCapture.
*
* \since 5.8
*/
/*!
* \qmltype RenderCaptureReply
* \instantiates Qt3DRender::QRenderCaptureReply
* \inherits QObject
* \inqmlmodule Qt3D.Render
* \since 5.8
* \brief Receives render capture result.
*/
/*!
* \qmlproperty variant Qt3D.Render::RenderCaptureReply::image
*
* Holds the image, which was produced as a result of render capture.
*/
/*!
* \qmlproperty int Qt3D.Render::RenderCaptureReply::captureId
*
* Holds the captureId, which was passed to the renderCapture.
*/
/*!
* \qmlproperty bool Qt3D.Render::RenderCaptureReply::complete
*
* Holds the complete state of the render capture.
*/
/*!
* \qmlmethod bool Qt3D.Render::RenderCaptureReply::saveImage(fileName)
*
* Saves the render capture result as an image to \a fileName.
* Returns true if the image was successfully saved; otherwise returns false.
*
* \since 5.9
*/
/*!
* \qmlmethod void Qt3D.Render::RenderCaptureReply::saveToFile(fileName)
* \deprecated
*
* Saves the render capture result as an image to \a fileName.
*
* Deprecated in 5.9. Use saveImage().
*/
/*!
* \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(int captureId)
* \deprecated
*
* Used to request render capture. User can specify a \a captureId to identify
* the request. The requestId does not have to be unique. Only one render capture result
* is produced per requestCapture call even if the frame graph has multiple leaf nodes.
* The function returns a QRenderCaptureReply object, which receives the captured image
* when it is done. The user is responsible for deallocating the returned object.
*/
/*!
* \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture()
*
* Used to request render capture. Only one render capture result is produced per
* requestCapture call even if the frame graph has multiple leaf nodes.
* The function returns a QRenderCaptureReply object, which receives the captured image
* when it is done. The user is responsible for deallocating the returned object.
*/
/*!
* \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(Rect rect)
*
* Used to request render capture from a specified \a rect. Only one render capture
* result is produced per requestCapture call even if the frame graph has multiple leaf nodes.
* The function returns a QRenderCaptureReply object, which receives the captured image
* when it is done. The user is responsible for deallocating the returned object.
*/
/*!
* \internal
*/
QRenderCaptureReplyPrivate::QRenderCaptureReplyPrivate()
: QObjectPrivate()
, m_captureId(0)
, m_complete(false)
{
}
/*!
* The constructor creates an instance with the specified \a parent.
*/
QRenderCaptureReply::QRenderCaptureReply(QObject *parent)
: QObject(* new QRenderCaptureReplyPrivate, parent)
{
}
/*!
* \property QRenderCaptureReply::image
*
* Holds the image, which was produced as a result of render capture.
*/
QImage QRenderCaptureReply::image() const
{
Q_D(const QRenderCaptureReply);
return d->m_image;
}
/*!
* \property QRenderCaptureReply::captureId
*
* Holds the captureId, which was passed to the renderCapture.
*/
int QRenderCaptureReply::captureId() const
{
Q_D(const QRenderCaptureReply);
return d->m_captureId;
}
/*!
* \property QRenderCaptureReply::complete
*
* Holds the complete state of the render capture.
*/
bool QRenderCaptureReply::isComplete() const
{
Q_D(const QRenderCaptureReply);
return d->m_complete;
}
/*!
* Saves the render capture result as an image to \a fileName.
*
* Returns true if the image was successfully saved; otherwise returns false.
* \since 5.9
*/
bool QRenderCaptureReply::saveImage(const QString &fileName) const
{
Q_D(const QRenderCaptureReply);
if (d->m_complete)
{
return d->m_image.save(fileName);
}
return false;
}
/*!
* \deprecated
* Saves the render capture result as an image to \a fileName.
*
* Deprecated in 5.9. Use saveImage().
*/
void QRenderCaptureReply::saveToFile(const QString &fileName) const
{
Q_D(const QRenderCaptureReply);
if (d->m_complete)
d->m_image.save(fileName);
}
/*!
* \internal
*/
QRenderCapturePrivate::QRenderCapturePrivate()
: QFrameGraphNodePrivate()
{
}
/*!
* \internal
*/
QRenderCapturePrivate::~QRenderCapturePrivate()
{
}
/*!
* \internal
*/
QRenderCaptureReply *QRenderCapturePrivate::createReply(int captureId)
{
QMutexLocker lock(&m_mutex);
QRenderCaptureReply *reply = new QRenderCaptureReply();
reply->d_func()->m_captureId = captureId;
m_waitingReplies.push_back(reply);
return reply;
}
/*!
* \internal
*/
QRenderCaptureReply *QRenderCapturePrivate::takeReply(int captureId)
{
QRenderCaptureReply *reply = nullptr;
QMutexLocker lock(&m_mutex);
for (int i = 0; i < m_waitingReplies.size(); ++i) {
if (m_waitingReplies[i]->d_func()->m_captureId == captureId) {
reply = m_waitingReplies.takeAt(i);
break;
}
}
return reply;
}
/*!
* \internal
*/
void QRenderCapturePrivate::setImage(QRenderCaptureReply *reply, const QImage &image)
{
reply->d_func()->m_complete = true;
reply->d_func()->m_image = image;
}
/*!
* \internal
*/
void QRenderCapturePrivate::replyDestroyed(QRenderCaptureReply *reply)
{
QMutexLocker lock(&m_mutex);
m_waitingReplies.removeAll(reply);
}
/*!
* The constructor creates an instance with the specified \a parent.
*/
QRenderCapture::QRenderCapture(Qt3DCore::QNode *parent)
: QFrameGraphNode(*new QRenderCapturePrivate, parent)
{
}
/*!
* \deprecated Used to request render capture. User can specify a \a captureId
* to identify the request. The requestId does not have to be unique. Only one
* render capture result is produced per requestCapture call even if the frame
* graph has multiple leaf nodes. The function returns a QRenderCaptureReply
* object, which receives the captured image when it is done. The user is
* responsible for deallocating the returned object by calling deleteLater().
*/
QRenderCaptureReply *QRenderCapture::requestCapture(int captureId)
{
Q_D(QRenderCapture);
QRenderCaptureReply *reply = d->createReply(captureId);
reply->setParent(this);
QObject::connect(reply, &QObject::destroyed, this, [&, reply, d] (QObject *) {
d->replyDestroyed(reply);
});
const QRenderCaptureRequest request = { captureId, QRect() };
d->m_pendingRequests.push_back(request);
d->update();
return reply;
}
/*!
* Used to request render capture from a specified \a rect. Only one render
* capture result is produced per requestCapture call even if the frame graph
* has multiple leaf nodes. The function returns a QRenderCaptureReply object,
* which receives the captured image when it is done. The user is responsible
* for deallocating the returned object by calling deleteLater().
*/
QRenderCaptureReply *QRenderCapture::requestCapture(const QRect &rect)
{
Q_D(QRenderCapture);
static int captureId = 1;
QRenderCaptureReply *reply = d->createReply(captureId);
reply->setParent(this);
QObject::connect(reply, &QObject::destroyed, this, [&, reply, d] (QObject *) {
d->replyDestroyed(reply);
});
const QRenderCaptureRequest request = { captureId, rect };
d->m_pendingRequests.push_back(request);
d->update();
captureId++;
return reply;
}
/*!
* Used to request render capture. Only one render capture result is produced
* per requestCapture call even if the frame graph has multiple leaf nodes. The
* function returns a QRenderCaptureReply object, which receives the captured
* image when it is done. The user is responsible for deallocating the returned
* object by calling deleterLater().
*/
Qt3DRender::QRenderCaptureReply *QRenderCapture::requestCapture()
{
return requestCapture(QRect());
}
/*!
* \internal
*/
void QRenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
{
Q_D(QRenderCapture);
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
if (propertyChange->type() == Qt3DCore::PropertyUpdated) {
if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureData")) {
RenderCaptureDataPtr data = propertyChange->value().value<RenderCaptureDataPtr>();
QPointer<QRenderCaptureReply> reply = d->takeReply(data.data()->captureId);
if (!reply.isNull()) {
d->setImage(reply, data.data()->image);
emit reply->completed();
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
if (reply)
emit reply->completeChanged(true);
QT_WARNING_POP
}
}
}
}
/*!
* \internal
*/
Qt3DCore::QNodeCreatedChangeBasePtr QRenderCapture::createNodeCreationChange() const
{
auto creationChange = QFrameGraphNodeCreatedChangePtr<QRenderCaptureInitData>::create(this);
QRenderCaptureInitData &data = creationChange->data;
data.captureId = 0;
return creationChange;
}
} // Qt3DRender
QT_END_NAMESPACE