summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Qt3DStudio/Render/StudioSubPresentationRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Qt3DStudio/Render/StudioSubPresentationRenderer.cpp')
-rw-r--r--src/Authoring/Qt3DStudio/Render/StudioSubPresentationRenderer.cpp377
1 files changed, 377 insertions, 0 deletions
diff --git a/src/Authoring/Qt3DStudio/Render/StudioSubPresentationRenderer.cpp b/src/Authoring/Qt3DStudio/Render/StudioSubPresentationRenderer.cpp
new file mode 100644
index 00000000..b04233cd
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Render/StudioSubPresentationRenderer.cpp
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "StudioSubPresentationRenderer.h"
+#include "render/Qt3DSRenderContext.h"
+#include "q3dspresentation.h"
+#include "q3dsviewersettings.h"
+
+#include <QtCore/qfileinfo.h>
+#include <qxmlstream.h>
+
+using namespace qt3ds::render;
+
+class RendererThread : public QThread
+{
+public:
+ RendererThread(QThread *mainThread)
+ : m_running(false)
+ , m_updated(false)
+ , m_initialized(false)
+ , m_mainThread(mainThread)
+ , m_semaphore(0)
+ {
+ }
+
+ QSize readPresentationSize(const QString &url)
+ {
+ QFile file(url);
+ file.open(QFile::Text | QFile::ReadOnly);
+ if (!file.isOpen()) {
+ qWarning () << file.errorString();
+ return QSize();
+ }
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ if (reader.readNextStartElement() && reader.qualifiedName() == QLatin1String("UIP")) {
+ if (reader.readNextStartElement()
+ && reader.qualifiedName() == QLatin1String("Project")) {
+ if (reader.readNextStartElement()
+ && reader.qualifiedName() == QLatin1String("ProjectSettings")) {
+ const auto attrib = reader.attributes();
+ return QSize(attrib.value(QLatin1String("presentationWidth")).toInt(),
+ attrib.value(QLatin1String("presentationHeight")).toInt());
+ }
+ }
+ }
+ return QSize();
+ }
+
+ void initialize(const QString &id, const QString &presentation, const QString &path)
+ {
+ m_path = path;
+ m_presentation = presentation;
+
+ m_surfaceViewer.reset(new Q3DSSurfaceViewer);
+ m_surfaceViewer->setPresentationId(id);
+ m_context.reset(new QT_PREPEND_NAMESPACE(QOpenGLContext));
+ m_surface.reset(new QOffscreenSurface);
+
+ QSurfaceFormat format = QSurfaceFormat::defaultFormat();
+ if (QT_PREPEND_NAMESPACE(QOpenGLContext)::currentContext())
+ format = QT_PREPEND_NAMESPACE(QOpenGLContext)::currentContext()->format();
+ m_context->setShareContext(QT_PREPEND_NAMESPACE(QOpenGLContext)::currentContext());
+ m_context->setFormat(format);
+ m_surface->setFormat(format);
+ m_context->create();
+ m_surface->create();
+ m_context->moveToThread(this);
+ m_surface->moveToThread(this);
+ m_surfaceViewer->moveToThread(this);
+
+ QObject::connect(m_surfaceViewer.data(), &Q3DSSurfaceViewer::frameUpdate,
+ this, &RendererThread::frameRendered);
+ m_initialized = true;
+ }
+
+ void run() override
+ {
+ QFileInfo info(m_path + "/" + m_presentation);
+ m_size = readPresentationSize(m_path + "/" + m_presentation);
+
+ m_context->makeCurrent(m_surface.data());
+
+ m_fbo.reset(new QOpenGLFramebufferObject(m_size,
+ QOpenGLFramebufferObject::CombinedDepthStencil));
+
+ m_surfaceViewer->setSize(m_size);
+ m_surfaceViewer->setAutoSize(false);
+ m_surfaceViewer->setUpdateInterval(-1);
+ m_surfaceViewer->presentation()->setSource(QUrl::fromLocalFile(info.absoluteFilePath()));
+ m_surfaceViewer->settings()->setMatteColor(Qt::transparent);
+ m_surfaceViewer->create(m_surface.data(), m_context.data(), m_fbo->handle());
+ m_running = true;
+ m_semaphore.release();
+
+ m_context->doneCurrent();
+
+ while (true) {
+ QMutexLocker lock(&m_mutex);
+ if (!m_running)
+ break;
+ m_context->makeCurrent(m_surface.data());
+ if (!m_surfaceViewer->isRunning()) {
+ qWarning () << "Subpresentation stopped running. Stopping updating.";
+ break;
+ }
+
+ m_surfaceViewer->update();
+ m_context->functions()->glFlush();
+ m_updated = true;
+ m_context->doneCurrent();
+ lock.unlock();
+
+ // Update approx 30 fps
+ QThread::usleep(33000);
+ }
+ m_fbo.reset();
+ m_context->doneCurrent();
+ m_context.reset();
+ m_surfaceViewer->destroy();
+ m_surfaceViewer.reset();
+ m_surface->moveToThread(m_mainThread);
+ m_semaphore.release();
+ }
+
+ void frameRendered()
+ {
+ m_updated = true;
+ }
+
+ QScopedPointer<Q3DSSurfaceViewer> m_surfaceViewer;
+ QScopedPointer<QT_PREPEND_NAMESPACE(QOpenGLContext)> m_context;
+ QScopedPointer<QOffscreenSurface> m_surface;
+ QScopedPointer<QOpenGLFramebufferObject> m_fbo;
+ QString m_path;
+ QString m_presentation;
+ QMutex m_mutex;
+ bool m_running, m_updated, m_initialized;
+ QThread *m_mainThread;
+ QSemaphore m_semaphore;
+ QSize m_size;
+};
+
+StudioSubpresentationRenderer::StudioSubpresentationRenderer(
+ IQt3DSRenderContext &inRenderContext, const QString &id,
+ const QString &presentation, const QString &path)
+ : m_renderContext(inRenderContext), m_id(id), m_presentation(presentation), m_path(path)
+ , m_program(nullptr)
+ , m_vao(nullptr)
+ , m_vertices(nullptr)
+ , m_callback(nullptr)
+ , m_rendererType(inRenderContext.GetStringTable().RegisterStr("StudioPresentationRenderer"))
+ , mRefCount(0)
+{
+ m_thread.reset(new RendererThread(QThread::currentThread()));
+}
+
+StudioSubpresentationRenderer::~StudioSubpresentationRenderer()
+{
+ QMutexLocker lock(&m_thread->m_mutex);
+ if (m_thread->m_running) {
+ m_thread->m_running = false;
+ lock.unlock();
+ m_thread->m_semaphore.acquire();
+ }
+}
+
+CRegisteredString StudioSubpresentationRenderer::GetOffscreenRendererType()
+{
+ return m_rendererType;
+}
+
+SOffscreenRendererEnvironment
+StudioSubpresentationRenderer::GetDesiredEnvironment(QT3DSVec2 inPresentationScaleFactor)
+{
+ // If we aren't using a clear color, then we are expected to blend with the background
+ if (!m_thread->m_initialized) {
+ initialize();
+ }
+ bool hasTransparency = true;
+ NVRenderTextureFormats::Enum format =
+ hasTransparency ? NVRenderTextureFormats::RGBA8 : NVRenderTextureFormats::RGB8;
+ return SOffscreenRendererEnvironment(
+ QT3DSU32(m_thread->m_size.width() * inPresentationScaleFactor.x),
+ QT3DSU32(m_thread->m_size.height() * inPresentationScaleFactor.y),
+ format, OffscreenRendererDepthValues::Depth24, false,
+ AAModeValues::NoAA);
+}
+
+SOffscreenRenderFlags StudioSubpresentationRenderer::NeedsRender(
+ const SOffscreenRendererEnvironment &inEnvironment,
+ QT3DSVec2 inPresentationScaleFactor,
+ const SRenderInstanceId instanceId)
+{
+ Q_UNUSED(inEnvironment)
+ Q_UNUSED(inPresentationScaleFactor)
+ Q_UNUSED(instanceId)
+ return SOffscreenRenderFlags(true, true);
+}
+
+void StudioSubpresentationRenderer::initialize()
+{
+ m_thread->initialize(m_id, m_presentation, m_path);
+ m_thread->start();
+ m_thread->m_semaphore.acquire();
+ if (m_callback)
+ m_callback->onOffscreenRendererInitialized(m_id);
+}
+
+void StudioSubpresentationRenderer::Render(const SOffscreenRendererEnvironment &inEnvironment,
+ NVRenderContext &inRenderContext, QT3DSVec2 inPresentationScaleFactor,
+ SScene::RenderClearCommand inColorBufferNeedsClear,
+ const SRenderInstanceId instanceId)
+{
+ Q_UNUSED(inEnvironment)
+ Q_UNUSED(inPresentationScaleFactor)
+ Q_UNUSED(instanceId)
+ inRenderContext.PushPropertySet();
+ if (!m_thread->m_initialized) {
+ initialize();
+ }
+ QMutexLocker lock(&m_thread->m_mutex);
+ if (m_thread->m_initialized && m_thread->m_updated) {
+ QT_PREPEND_NAMESPACE(QOpenGLContext) *context
+ = QT_PREPEND_NAMESPACE(QOpenGLContext)::currentContext();
+ QOpenGLFunctions *func = context->functions();
+ GLuint texture = m_thread->m_fbo->texture();
+ func->glDisable(GL_DEPTH_TEST);
+ if (inColorBufferNeedsClear == SScene::RenderClearCommand::AlwaysClear)
+ func->glDisable(GL_BLEND);
+ else
+ func->glEnable(GL_BLEND);
+ func->glBlendEquation(GL_FUNC_ADD);
+ func->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ if (!m_program)
+ initializeFboCopy();
+
+ m_program->bind();
+
+ if (!m_vao) {
+ m_vao = new QOpenGLVertexArrayObject;
+ m_vao->create();
+ m_vao->bind();
+ m_vertices->bind();
+
+ m_program->enableAttributeArray(0);
+ m_program->enableAttributeArray(1);
+ func->glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
+ func->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
+ reinterpret_cast<const void *>(4 * sizeof(GLfloat)));
+ m_vertices->release();
+ } else {
+ m_vao->bind();
+ }
+
+ func->glActiveTexture(GL_TEXTURE0);
+ func->glBindTexture(GL_TEXTURE_2D, texture);
+ func->glDrawArrays(GL_TRIANGLES, 0, 6);
+ func->glEnable(GL_DEPTH_TEST);
+ func->glBindTexture(GL_TEXTURE_2D, 0);
+
+ m_program->release();
+ m_vao->release();
+
+ if (m_callback)
+ m_callback->onOffscreenRendererFrame(m_id);
+ }
+ inRenderContext.PopPropertySet(true);
+}
+
+void StudioSubpresentationRenderer::RenderWithClear(
+ const SOffscreenRendererEnvironment &inEnvironment,
+ NVRenderContext &inRenderContext, QT3DSVec2 inPresentationScaleFactor,
+ SScene::RenderClearCommand inColorBufferNeedsClear,
+ QT3DSVec4 inclearColor,
+ const SRenderInstanceId instanceId)
+{
+ inRenderContext.SetClearColor(inclearColor);
+ Render(inEnvironment, inRenderContext, inPresentationScaleFactor,
+ inColorBufferNeedsClear, instanceId);
+}
+
+void StudioSubpresentationRenderer::initializeFboCopy()
+{
+ m_program = new QOpenGLShaderProgram;
+ if (m_thread->m_context->format().renderableType() == QSurfaceFormat::OpenGLES) {
+ static const char *vsSource =
+ "attribute highp vec4 pos;\n"
+ "attribute highp vec2 tc;\n"
+ "varying lowp vec2 texcoord;\n"
+ "void main() {\n"
+ " texcoord = tc;\n"
+ " gl_Position = pos;\n"
+ "}\n";
+ static const char *fsSource =
+ "varying highp vec2 texcoord;\n"
+ "uniform sampler2D sampler;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(sampler, texcoord);\n"
+ "}\n";
+ m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vsSource);
+ m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fsSource);
+ } else {
+ static const char *vsSource =
+ "#version 150 core\n"
+ "in vec4 pos;\n"
+ "in vec2 tc;\n"
+ "out vec2 texcoord;\n"
+ "void main() {\n"
+ " texcoord = tc;\n"
+ " gl_Position = pos;\n"
+ "}\n";
+ static const char *fsSource =
+ "#version 150 core\n"
+ "in vec2 texcoord;\n"
+ "out vec4 fragColor;\n"
+ "uniform sampler2D sampler;\n"
+ "void main() {\n"
+ " fragColor = texture(sampler, texcoord);\n"
+ "}\n";
+ m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vsSource);
+ m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fsSource);
+ }
+
+ m_program->bindAttributeLocation("pos", 0);
+ m_program->bindAttributeLocation("tc", 1);
+
+ if (!m_program->link()) {
+ QByteArray logData(m_program->log().toLocal8Bit());
+ const char *log = logData.data();
+ qFatal("Failed to create shader program: %s", log);
+ }
+
+ m_vertices = new QOpenGLBuffer;
+ m_vertices->create();
+ m_vertices->bind();
+
+ static const float vertices[] =
+ {
+ -1, -1, 0, 1, 0, 0,
+ 1, -1, 0, 1, 1, 0,
+ 1, 1, 0, 1, 1, 1,
+ -1, -1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 1, 1,
+ -1, 1, 0, 1, 0, 1,
+ };
+
+ m_vertices->allocate(vertices, sizeof(vertices));
+ m_vertices->release();
+}